affair
Transaction actually refers to a set of operations that contain many single logic. As long as one logic fails to execute successfully, it fails. All data is returned to its original state (rollback)
- Why do we have business?
To ensure the success of logic. Example: Bank transfer.
Demonstrate transactions using the command line.
-
Open a transaction
start transaction;
-
Submit or roll back transactions
Commit; commit the transaction, and the data will be written to the database on disk Rollback; data rollback, back to its original state.
- Turn off automatic submission.
- Demonstration transaction
Demonstrating transactions in a code-based manner
The transactions in the code are mainly for connections.
- Close the autocommit settings by conn.setAutoCommit (false).
- Commit transaction conn.commit();
- Rollback transaction conn.rollback();
[@Test](https://my.oschina.net/azibug) public void testTransaction(){ Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = JDBCUtil.getConn(); //Connection, transaction is automatically committed by default. Turn off automatic submission. conn.setAutoCommit(false); String sql = "update account set money = money - ? where id = ?"; ps = conn.prepareStatement(sql); //Deduction, deduction ID of 100 yuan ps.setInt(1, 100); ps.setInt(2, 1); ps.executeUpdate(); int a = 10 /0 ; //Add money, give ID 2 plus 100 yuan ps.setInt(1, -100); ps.setInt(2, 2); ps.executeUpdate(); //Success: Submit the transaction. conn.commit(); } catch (SQLException e) { try { //Incident: Roll back the transaction conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); }finally { JDBCUtil.release(conn, ps, rs); } }
The Characteristics of Transactions
* Atomicity
It refers to the logic contained in the transaction, which is inseparable.
* Consistency
Refers to the time before and after the transaction is executed. Data Integrity
* Isolation
Refers to transactions that should not be affected by other transactions during execution
* Persistence
When a transaction is successfully executed, the data should be persisted to disk.
Transaction isolation level
Read uncommitted
Causing Problems: Dirty Reading
Read submitted
Solution: Dirty Reading, Initiation: Non-repeatable Reading
Repeatable reading
Solution: dirty reading, unrepeatable reading, unresolved: hallucination
Serializable
Solution: Dirty reading, non-repeatable reading, illusory reading.
mySql's default isolation level is repeatable
Oracle's default isolation level is to read submitted
Read Unsubmitted Demo
- Set the isolation level of window A to read uncommitted
- Both windows open transactions separately
Read the presentation submitted
- Set the isolation level of window A to read submitted
- Both windows of A and B open transactions and perform update operations in B windows.
- The query results executed in window A are inconsistent. One is before the transaction is committed in window B, and the other is after the transaction is committed in window B.
This isolation level can shield dirty reading, but it raises another problem, which is not repeatable.
Serializable
If the isolation level of a connection is set to serialization, then whoever opens the transaction first has the right to execute it first and whoever opens the transaction later will have to wait for the transaction before committing or rolling back to execute it. But this isolation level is generally less used. It is easy to cause performance problems. The efficiency is relatively low.
- According to efficiency, from high to low
Read Uncommitted > Read Submitted > Repeatable Read > Serializable
- Depending on the degree of interception, from high to low
Serializable > Repeatable Read > Read Submitted > Read Unsubmitted
Security Hidden Dangers of Transactions
Without considering isolation level settings, the following problems arise.
* Reading
Dirty reading should not be reread or hallucinated.
Dirty Reading
> One transaction reads uncommitted data from another transaction
Non-repeatable reading
> One transaction reads the data submitted by another transaction, resulting in inconsistencies between the two queries.
phantom read
> One transaction reads data from another transaction insert, resulting in inconsistent query results.
* Writing
Lost updates
Resolving Lost Updates
Pessimistic Lock
You can add for update when querying
Optimistic Lock
Require programmers to control themselves.
Database connection pool
- The database connection object creation work, compares the consumptive performance.
2. In the beginning, there is a space (collection) in the memory, and several connection objects are placed in the pool first. If you need a connection at the back, go directly from the pool. Don't create your own connection. After use, remember to return the connection. Ensure that connected objects are recycled.
Custom database connection pool
code implementation
Problems arising:
1. You need to remember the addBack method extra. 2. Single case. 3. Interface-oriented programming is not possible. UserDao dao = new UserDaoImpl(); dao.insert(); DataSource dataSource = new MyDataSource(); Because there is no addBack method defined in the interface. 4. How to solve it? Take addBack as the starting point.
Solve the problem of custom database connection pool.
Because of the addition of an addBack method, it needs to be remembered where this connection pool is used, and Interface-oriented programming is not yet possible.
We intend to modify the close method in the interface. The close method of the original Connection object actually closes the connection. I intend to modify the close method and call close later, not really close, but return the connection object.
How to extend a method?
The original method logic is not what we want. Want to change your logic
-
Direct source modification is not possible.
-
Inheritance, we must know who the specific implementation of this interface is.
Use Decorator Mode
Decorator pattern: Decorative pattern refers to the dynamic expansion of an object's function without changing the original file and using inheritance. It wraps real objects by creating a wrapping object, that is, decoration.
Generally speaking, the idea of Java object-oriented is to use interfaces and implementation classes, create objects that point to the interfaces that implement classes to call implementation methods, but if the methods of implementing classes themselves are not enough to meet the requirements, something needs to be added, without changing the interface and implementation classes or inheriting them, create another wrapper class implementation. The method of this interface is modified, and the interface object is passed in the place where the construction method is constructed. When creating the object pointing to the interface of the wrapper class, the parameter of the implementation class instance can be transferred to the parent class automatically. That is, the object is created or the object pointing to the interface of the implementation class. The object is unchanged, but the method is called. It's time to call methods in wrapper classes
Packaging class code
import java.sql.Array; import java.sql.Blob; import java.sql.CallableStatement; import java.sql.Clob; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.NClob; import java.sql.PreparedStatement; import java.sql.SQLClientInfoException; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.SQLXML; import java.sql.Savepoint; import java.sql.Statement; import java.sql.Struct; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.Executor; public class ConnectionWrap implements Connection{ Connection connection=null; List<Connection> list=null; //Pass in the connection object parameter and list in the encapsulated object public ConnectionWrap(Connection conn,List<Connection> list) { super(); this.connection=conn; this.list=list; } //When the copy close method meets the requirement, it does not close the connection but returns it to the connection pool. @Override public void close() throws SQLException { System.out.println("The number of objects that are ready to be returned is"+list.size()); list.add(connection); System.out.println("The number of objects returned is"+list.size());//It shows + 1 above. } @Override public PreparedStatement prepareStatement(String sql) throws SQLException { return connection.prepareStatement(sql); } @Override public Statement createStatement() throws SQLException { return connection.createStatement(); }
Custom connection pool code
import java.io.PrintWriter; import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; import javax.sql.DataSource; import s20190719.jdbc.util.JDBCUtil; import s2019072.connection.wrap.ConnectionWrap; public class MyDatasource implements DataSource{ //Create a list to place the connection object List<Connection> list = new ArrayList<Connection>(); //Constructor automatically creates 10 connection objects in list when creating instances public MyDatasource() { for (int i = 0; i < 10; i++) { Connection conn=JDBCUtil.getConn(); list.add(conn); } } @Override public Connection getConnection() throws SQLException { //Increase capacity first when there are no connection objects in connection pool if (list.size()==0) { for (int i = 0; i < 5; i++) { Connection conn=JDBCUtil.getConn(); list.add(conn); } } //Remove a connection object from the list and encapsulate it to the caller Connection conn = list.remove(0); Connection connection=new ConnectionWrap(conn, list); return connection; }
Open source connection pools (two commonly used)
DBCP connection pool
1. Importing jar files
2. Do not use configuration files:
public void testDBCP01(){ Connection conn = null; PreparedStatement ps = null; try { //1. Building Data Source Objects BasicDataSource dataSource = new BasicDataSource(); //What kind of database is connected, which database is accessed, user name, password. //jdbc:mysql://localhost/bank master protocol: subprotocol: //local/database dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost/bank"); dataSource.setUsername("root"); dataSource.setPassword("root"); //2. Get the connection object conn = dataSource.getConnection(); String sql = "insert into account values(null , ? , ?)"; ps = conn.prepareStatement(sql); ps.setString(1, "admin"); ps.setInt(2, 1000); ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); }finally { JDBCUtil.release(conn, ps); } }
3. Use configuration file: Copy the configuration properties file to the src directory
Open to modify connection settings and other parameters as required
#connections setting up driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/jdbc username=root password= #<! - Initialize the connection - > initialSize=10 #Maximum number of connections maxActive=50 #<! - Maximum idle connection maxIdle=20 #<! - Minimum idle connection - > minIdle=5 #<! - Overtime waiting time in milliseconds is 6000 milliseconds/1000 equal to 60 seconds - > maxWait=60000 #The format of the join attribute attributes attached to the JDBC driver when establishing a connection must be as follows: [attribute name = property;] #Note that the attributes "user" and "password" will be passed explicitly, so they need not be included here. connectionProperties=useUnicode=true;characterEncoding=gbk #Specifies the auto-commit state of the connection created by the connection pool. defaultAutoCommit=true #driver default specifies the transaction level (Transaction Isolation) of the connection created by the connection pool. #Available values are one of the following: (Details can be found in javadoc.) NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE defaultTransactionIsolation=READ_UNCOMMITTED
Connection conn = null; PreparedStatement ps = null; try { BasicDataSourceFactory factory = new BasicDataSourceFactory(); Properties properties = new Properties(); InputStream is = new FileInputStream("src//dbcpconfig.properties"); properties.load(is); DataSource dataSource = factory.createDataSource(properties); //2. Get the connection object conn = dataSource.getConnection(); String sql = "insert into account values(null , ? , ?)"; ps = conn.prepareStatement(sql); ps.setString(1, "liangchaowei"); ps.setInt(2, 100); ps.executeUpdate(); } catch (Exception e) { e.printStackTrace(); }finally { JDBCUtil.release(conn, ps); }
* C3P0
1. Copy jar files to lib directory
2. Do not use configuration file
Connection conn = null; PreparedStatement ps = null; try { //1. Create data source ComboPooledDataSource dataSource = new ComboPooledDataSource(); //2. Setting up information for connecting data dataSource.setDriverClass("com.mysql.jdbc.Driver"); //Forget - > go to the previous code - > JDBC documentation dataSource.setJdbcUrl("jdbc:mysql://localhost/bank"); dataSource.setUser("root"); dataSource.setPassword("root"); //2. Get the connection object conn = dataSource.getConnection(); String sql = "insert into account values(null , ? , ?)"; ps = conn.prepareStatement(sql); ps.setString(1, "admi234n"); ps.setInt(2, 103200); ps.executeUpdate(); } catch (Exception e) { e.printStackTrace(); }finally { JDBCUtil.release(conn, ps); }
3. Use configuration file
Support property and xml formats, recommend xml
Configuration file name: c3p0-config.xml (fixed)
Configuration file path: src (class path)
Configuration file content: Specify rules, usually for different database configurations with different requirements
New ComboPooled Data Source ("Name"); // Use Configuration File "Named Configuration"
<c3p0-config> <!-- Named Configuration --> <named-config name="test"> <!-- Four Basic Parameters for Connecting Database --> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/mytest01</property> <property name="user">root</property> <property name="password">321</property> <!-- How many increments per time if the data connection in the pool is insufficient --> <property name="acquireIncrement">5</property> <!-- Number of Initial Connections --> <property name="initialPoolSize">10</property> <!-- Minimum number of connections --> <property name="minPoolSize">10</property> <!-- maximum connection --> <property name="maxPoolSize">100</property> <!-- JDBC Standard parameters to control loading within the data source PrepareStatements Number --> <property name="maxStatements">200</property> <!-- Maximum cache owned by a single connection in the connection pool statements number --> <property name="maxStatementsPerConnection">5</property> </named-config> </c3p0-config>
Default configuration when not specified: new ComboPooled DataSource (); // Use configuration file "Default configuration"
<c3p0-config> <!-- Default configuration, which is used if no use is specified --> <default-config> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/mytest01</property> <property name="user">root</property> <property name="password">321</property> <property name="acquireIncrement">50</property> <property name="initialPoolSize">100</property> <property name="minPoolSize">50</property> <property name="maxPoolSize">1000</property> <!-- intergalactoApp adopts a different approach to configuring statement caching --> <property name="maxStatements">0</property> <property name="maxStatementsPerConnection">5</property> <!-- he's important, but there's only one of him --> <user-overrides user="master-of-the-universe"> <property name="acquireIncrement">1</property> <property name="initialPoolSize">1</property> <property name="minPoolSize">1</property> <property name="maxPoolSize">5</property> <property name="maxStatementsPerConnection">50</property> </user-overrides> </default-config> </c3p0-config>
//By default, the class loader looks for default-config branches in xml. So you don't need to write more code. ComboPooledDataSource dataSource = new ComboPooledDataSource(); //2. Get the connection object conn = dataSource.getConnection(); String sql = "insert into account values(null , ? , ?)"; ps = conn.prepareStatement(sql); ps.setString(1, "admi234n"); ps.setInt(2, 103200);
Further simplify the JDBCUtil code: (to get the connection in the method of the dao implementation class in one sentence conn=JDBCUtil.getConn())
import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import com.mchange.v2.c3p0.ComboPooledDataSource; public class JDBCUtil2 { static ComboPooledDataSource datasource = null; static { datasource=new ComboPooledDataSource(); } //Redefining getconn method public static Connection getConn() throws SQLException { return datasource.getConnection(); } public static void release(Connection conn, Statement st, ResultSet rs) { closeConn(conn); closeRs(rs); closeSt(st); } public static void release(Connection conn, Statement st) { closeConn(conn); closeSt(st); } private static void closeConn(Connection conn) { try { if (conn != null) { conn.close(); } } catch (SQLException e) { e.printStackTrace(); } finally { conn = null; } } private static void closeSt(Statement st) { try { if (st != null) { st.close(); } } catch (SQLException e) { e.printStackTrace(); } finally { st = null; } } private static void closeRs(ResultSet rs) { try { if (rs != null) { rs.close(); } } catch (SQLException e) { e.printStackTrace(); } finally { rs = null; } } }
DBUtils(QueryRunner)
Add, delete and modify update
//dbutils only helps us simplify the CRUD code, but the creation and acquisition of connections. Not in his consideration QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource()); //increase //queryRunner.update("insert into account values (null , ? , ? )", "aa" ,1000); //delete //queryRunner.update("delete from account where id = ?", 5); //To update //queryRunner.update("update account set money = ? where id = ?", 10000000 , 6);
query
1. Anonymous Implementation Class of Direct new Interface
QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource()); Account account = queryRunner.query("select * from account where id = ?", new ResultSetHandler<Account>(){ [@Override](https://my.oschina.net/u/1162528) public Account handle(ResultSet rs) throws SQLException { Account account = new Account(); while(rs.next()){ String name = rs.getString("name"); int money = rs.getInt("money"); account.setName(name); account.setMoney(money); } return account; } }, 6); System.out.println(account.toString());
2. Use the implementation class that the framework has written directly.
* Query a single object BeanHandler<Account>(Account.class) QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource()); //Query a single object Account account = queryRunner.query("select * from account where id = ?", new BeanHandler<Account>(Account.class), 8); * Query multiple objects BeanListHandler<Account>(Account.class) QueryRunner queryRunner = new QueryRunner(new ComboPooledDataSource()); List<Account> list = queryRunner.query("select * from account ", new BeanListHandler<Account>(Account.class));
Common implementation classes of ResultSetHandler
The following two are the most frequently used
BeanHandler, which encapsulates the individual data queried into an object BeanListHandler, which encapsulates multiple queried data into a List < Object >
ArrayHandler, The queried individual data is encapsulated in an array ArrayListHandler, The queried data is encapsulated into a set, in which the elements are arrays. MapHandler, The individual data queried is encapsulated into one map MapListHandler,The queried data is encapsulated into a collection, in which the elements are map. ColumnListHandler KeyedHandler ScalarHandler
# Summary
## Affairs
Demonstration using the command line Using Code Demonstration
Dirty reading,
Not repeatable.
phantom read Lost updates
Pessimistic Lock Optimistic Lock Four isolation levels Read uncommitted Read submitted Repeatable reading Serializable
## Data connection pool
-
DBCP
No configuration
Use configuration
-
C3P0
No configuration
Use configuration (must be mastered)
-
Custom connection pool
Decorator Model
##DBUtils
It simplifies our CRUD, which defines a common CRUD method.
queryRunner.update(); queryRunner.query