[TOC]
0x00 database transaction
What is a transaction?
Answer: Transaction refers to a group of operations containing multiple tiny logical units. As long as one of the logic fails, then this group of operations will all end in failure and all data will return to the original state (rollback) , There is no half-success, half-unsuccessful situation.
Why have business?
A: To ensure the success of the logic. Transactions may not be commonly used in ordinary CRUD, but if we have a requirement that a set of operations must be successfully executed, the task is completed. As long as there is an error, all tasks will return to the original state. This is the application scenario of using transactions, such as: bank transfer example;
Operational transaction processes and commands in the database:
copy-- Check autocommit Whether auto-commit is turned off > SHOW VARIABLES LIKE 'autocommit'; "autocommit" "ON" -- The current terminal temporarily turns off autocommit > SET autocommit = off; -- start transaction > START TRANSACTION; -- Commit or roll back the transaction commit; --- Commit the transaction and the data will be written to the database on disk rollback ; --- The data is rolled back, back to the original state.
Test SQL statement:
copyCREATE TABLE account( `id` INT PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(64) NOT NULL, `money` FLOAT DEFAULT 0 ); INSERT INTO account VALUES (null,'WeiyiGeek',1000),(null,'muzi',1000);
1. Transaction processing in JDBC
Description: The transaction is only for the connection connection object. If another connection object is opened, then it is the default commit (note: the transaction will be automatically committed ).
- Turn off autocommit by setting (transactions are only for connections) conn.setAutoCommit(false)
- Commit transaction conn.commit();
- Rollback transaction conn.rollback();
JDBC uses JAVA code to demonstrate transactions:
copypackage top.weiyigeek.Web; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import org.junit.Test; import top.weiyigeek.Util.db; public class Test_transaction { @Test public void transaction() { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { conn = db.getConn(); //1. Connection: Transactions are automatically committed by default. Turn off autocommit. conn.setAutoCommit(false); String sql = "update account set money = money - ? where id = ?"; ps = conn.prepareStatement(sql); //2. Deduct money: deduct 100 yuan with ID 1 ps.setInt(1, 100); ps.setInt(2, 1); ps.executeUpdate(); //3. Set the exception to view the impact of transaction submission int a = 10 /0 ; //4. Add money, add 100 yuan to ID 2 ps.setInt(1, -100); ps.setInt(2, 2); ps.executeUpdate(); //5. Success: Commit the transaction. conn.commit(); } catch (SQLException e) { try { //6. If an exception occurs in step 3, enter catch{} to roll back the transaction conn.rollback(); System.out.println("\nSQL Transaction commit exception, transaction has been rolled back automatically!"); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); }finally { db.release(conn, ps, rs); } } }

WeiyiGeek. Transaction Processing
2. Characteristics of transactions
Description: Transactions have four ACID properties including:
- Atomicity (Atomicity English /ˌætəˈmɪsəti/): The logic in a transaction must be fully executed and inseparable. (Atom is the smallest unit in physics) Refers to the logic contained in the transaction, which is indivisible.
- Consistency (English /kənˈsɪstənsi/): Refers to the integrity of the data before and after the execution of the transaction is consistent Refers to before and after the transaction is executed. data integrity
- Isolation (Isolation English /ˌaɪsəˈleɪʃn/ ): means that a transaction should not be affected by other transactions during its execution Refers to the transaction should not be affected by other transactions during execution
- Durability (Durability English /ˌdjʊərəˈbɪləti/ ): the transaction execution ends (commit or rollback), and the data should be persisted to the data Refers to the successful execution of the transaction, then the data should be persisted to disk.
3. Transaction security risks
Description: When the isolation level setting is not considered, the following problems will occur.
- 1) Problems when reading
- dirty read
- non-repeatable read
- hallucinations
- 2) Problems while writing (missing updates)
- pessimistic lock
- optimistic locking
(1) Problems when reading
- Dirty read: refers to a transaction that has read data that has not yet been committed by another transaction
- Non-repeatable read: Refers to a transaction that reads data submitted by another transaction, resulting in inconsistent results of multiple queries.
- Phantom read: Refers to a transaction that has read the inserted data (INSERT) committed by another transaction, resulting in inconsistent results of multiple queries.
(2) Problems when writing Lost update: refers to a transaction to modify the database and another transaction to modify the database, the last transaction, whether it is committed or rolled back, will cause the data update of the previous transaction to be lost;

WeiyiGeek. Lost Update
There are usually two ways to solve lost updates: pessimistic locking and optimistic locking
- Pessimistic lock: It means that the transaction believes that lost updates will happen at the beginning. This is a very pessimistic thing. The specific operation steps are as follows:
- 1. All transactions should query the data once before executing the operation. The query statement is as follows: select * from student for update ; the latter for update is actually a database lock mechanism, an exclusive lock.
- 2. Which transaction executes this statement first, whichever transaction holds the lock, can query the data, and then execute this statement again in the subsequent transaction, there will be no data displayed, so you can only wait.
- 3. Wait until the previous transaction submits the data, and the subsequent transaction data will come out, then you can continue to operate.
- The mechanism of the pessimistic lock: It is a bit similar to when you go to the bathroom, whoever comes first can go in and squat, and the person who comes behind has to wait, and only the person inside can come in when they come out. This is actually the concept of synchronization in java.

- Optimistic locking: refers to never feeling that lost updates will happen.
So what exactly does it do?
The programmer is required to add a field to the database and then when the subsequent update is performed, the field will be judged and compared, and the update will be allowed if it is consistent.
- 1. An additional version field is added to the database table to record the version. By default, starting from 0, as long as the data in the table is modified, the version will be +1.
- 2. Start A transaction and then start B transaction.
- 3.A Perform database table operations first. Because no one has modified it before, transaction A is allowed to modify the database, but after the modification, the value of version is changed to 1.
- 4. If the B transaction wants to perform modification at this time, modification is not allowed. Because transaction B has not queried the database content before, it thinks that the database version is still 0; but the version of the database has been modified by A, and it is already 1; so it is not allowed to modify at this time, and it is required to re-query.
- 5. After B re-queries, it will get the data whose version is 1. This data is the data modified by the previous transaction of A. When B is modifying, it is also modified on the basis of A. So there will be no loss of updates.
- Optimistic locking mechanism: It is actually implemented by comparing versions or fields, which is the same as the version control software [SVN, GIT] mechanism used.

WeiyiGeek. Optimistic Lock
4. Isolation level
Description: The isolation according to the transaction is often the following four isolation levels:
- 1.Read Uncommitted [read uncommitted]: cause dirty reading
- 2.Read Committed [Read committed]: Solve dirty reads and cause non-repeatable reads
- 3.Repeatable Read [Repeatable Read]: MySQL data volume defaults to this isolation level; resolves dirty reads, non-repeatable reads, and unresolved phantom reads
- 4.Serializable [Serializable]: Solution: Dirty read, non-repeatable read, phantom read but lack of performance;
Q: How to query the isolation level of the current session and change the isolation level of the current session?
copy-- Inquire SQL > select @@tx_isolation; -- +-----------------+ -- | @@tx_isolation | -- +-----------------+ -- | REPEATABLE-READ | -- +-----------------+ -- 1 row in set (0.00 sec) -- Fix setting the transaction isolation level of the current window to SQL > set session transaction isolation level read uncommitted; -- Query OK, 0 rows affected (0.00 sec)
1) Read Uncommitted Description: A transaction can read data that has not been committed by another transaction; it will cause a "dirty read" to read the data in the database memory, not the real data on the disk.
SQL Example 1:
copy-- 1.Modify the current isolation level to`read uncommitted` db_window-1 > set session transaction isolation level read uncommitted; -- Query OK, 0 rows affected (0.00 sec) -- 2.Check whether the modification is successful db_window-1 > select @@tx_isolation; +------------------+ | @@tx_isolation | +------------------+ | READ-UNCOMMITTED | +------------------+ 1 row in set (0.00 sec) -- 3.The isolation level of terminal 2 is repeatable read by default db_window-2 > select @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+ 1 row in set (0.00 sec) db_window-2 > update account set money = money + 100 where id = 1; Query OK, 1 row affected (0.11 sec) Rows matched: 1 Changed: 1 Warnings: 0 -- 4.open transaction db_window-2 > start transaction; Query OK, 0 rows affected (0.00 sec) db_window-1 > start transaction; Query OK, 0 rows affected (0.00 sec) db_window-2 > update account set money = money - 100 where id = 2; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 -- 5.Terminal 1 has read data that has not been submitted by terminal 2 db_window-1 > select * from account; | id | name | money | | 1 | WeiyiGeek | 1100 | | 2 | muzi | 900 | -- 6.Commit transaction (actual terminal 1 has read data from memory) db_window-2 > commit;

WeiyiGeek. Read Uncommitted
2) Read Committed Description: It is just the opposite of the previous read uncommitted, it can only read the data that has been committed by other transactions, and those uncommitted data cannot be read. Cause the problem: The results read before and after are different, which cannot be repeated!!!, The so-called non repeatable read means that you cannot perform multiple reads, otherwise the results will be different (at this time, we introduce the isolation level of repeatable read) Simply put: this isolation level can block the phenomenon of dirty reads, but it causes another problem that is non-repeatable reads.
copy-- 1.Set the isolation level for terminal 1 db_window-1 > set session transaction isolation level read committed; Query OK, 0 rows affected (0.00 sec) db_window-1 > select @@tx_isolation; +----------------+ | @@tx_isolation | +----------------+ | READ-COMMITTED | +----------------+ 1 row in set (0.00 sec) -- 2.Terminal 1 starts the transaction db_window-1 > start transaction; Query OK, 0 rows affected (0.00 sec) -- 3.Terminal 1 queries raw data db_window-1 > select * from account; +----+-----------+-------+ | id | name | money | +----+-----------+-------+ | 1 | WeiyiGeek | 1000 | | 2 | muzi | 1000 | +----+-----------+-------+ 2 rows in set (0.00 sec) -- 4.Terminal 2 starts transaction db_window-2 > select @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+ 1 row in set (0.00 sec) db_window-2 > start transaction; Query OK, 0 rows affected (0.00 sec) -- 5.Terminal 2 performs the update operation db_window-2 > update account set money = money - 100 where id = 1; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 db_window-2 > update account set money = money + 100 where id = 2; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 -- 6.Terminal 1 performs a query operation (the data has not changed) db_window-1 > select * from account; +----+-----------+-------+ | id | name | money | +----+-----------+-------+ | 1 | WeiyiGeek | 1000 | | 2 | muzi | 1000 | +----+-----------+-------+ 2 rows in set (0.00 sec) -- 7.Terminal 2 executes commit db_window-2 > commit; Query OK, 0 rows affected (0.05 sec) -- 8.After submission, terminal 1 queries the data and finds that it has changed db_window-1 > select * from account; +----+-----------+-------+ | id | name | money | +----+-----------+-------+ | 1 | WeiyiGeek | 900 | | 2 | muzi | 1100 | +----+-----------+-------+ 2 rows in set (0.00 sec)

WeiyiGeek. Read Submitted
3) Repeatable Read [Repeat Read] Description: MySQL's default isolation level is this. This isolation level allows a transaction to repeatedly read data in its own session, and there will be no different results. Even if other transactions have committed, the previous data is still displayed. Repeatable read (REPEATABLE READ) function: ensure that the result of reading the same data multiple times in the same transaction is the same to avoid the occurrence of dirty reads and non-repeatable reads.
copy-- 1.Terminal 1 sets the isolation to repeat the read and view the current isolation db_window-1 > set session transaction isolation level repeatable read; Query OK, 0 rows affected (0.00 sec) db_window-1 > select @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+ 1 row in set (0.00 sec) -- 2.Terminal 1 displays raw data db_window-1 > select * from account; +----+-----------+-------+ | id | name | money | +----+-----------+-------+ | 1 | WeiyiGeek | 1000 | | 2 | muzi | 1000 | +----+-----------+-------+ 2 rows in set (0.00 sec) -- 3.Terminal 1 starts transaction db_window-1 > start transaction; Query OK, 0 rows affected (0.00 sec) -- 4.Terminal 2 checks the current isolation and opens a transaction db_window-2 > select @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+ 1 row in set (0.00 sec) db_window-2 > start transaction; Query OK, 0 rows affected (0.00 sec) -- 5.Terminal 2 performs the update operation db_window-2 > update account set money = money - 100 where id = 1; Query OK, 1 row affected (0.06 sec) Rows matched: 1 Changed: 1 Warnings: 0 db_window-2 > update account set money = money + 100 where id = 2; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 -- 6.Terminal 1 executes the query statement and the result remains unchanged db_window-1 > select * from account; +----+-----------+-------+ | id | name | money | +----+-----------+-------+ | 1 | WeiyiGeek | 1000 | | 2 | muzi | 1000 | +----+-----------+-------+ 2 rows in set (0.00 sec) -- 7.Terminal 2 executes submit data db_window-2 > commit; Query OK, 0 rows affected (0.08 sec) -- 8.Terminal 1 executes the query data and still does not change(The query results are consistent with the previous query results and will not change.) db_window-1 > select * from account; +----+-----------+-------+ | id | name | money | +----+-----------+-------+ | 1 | WeiyiGeek | 1000 | | 2 | muzi | 1000 | +----+-----------+-------+ 2 rows in set (0.00 sec)

WeiyiGeek. Repeatable Read
4) Serializable [Serializable] Description: This transaction level is the most advanced transaction level, which is stronger than the previous ones, that is, the previous problems [dirty read, non repeatable read, phantom read] can be solved, but this isolation level is generally more less
Other transactions must wait for the transaction that is currently operating the table to commit first before going down, otherwise they can only wait for the blocker; that is, if the isolation level of a connection is set to serialize whoever opens the transaction first, whoever opens the transaction first With the right to execute first (preconceived) and the previous transaction, it can be executed after committing or rolling back.
SQL example:
copy-- 1.Terminal 1 settings Serializable Serializable isolation level db_window-1 > set session transaction isolation level serializable; Query OK, 0 rows affected (0.00 sec) db_window-1 > select @@tx_isolation; +----------------+ | @@tx_isolation | +----------------+ | SERIALIZABLE | +----------------+ 1 row in set (0.00 sec) -- 2.Terminal 2 current isolation db_window-2 > select @@tx_isolation; +-----------------+ | @@tx_isolation | +-----------------+ | REPEATABLE-READ | +-----------------+ 1 row in set (0.00 sec) -- 3.Terminal 1 queries raw data db_window-1 > select * from account; | id | name | money | | 1 | WeiyiGeek | 1000 | | 2 | muzi | 1000 | -- 4.Terminal 2 starts the transaction first db_window-2 > start transaction; Query OK, 0 rows affected (0.00 sec) -- 5.Terminal 1 starts the transaction next db_window-1 > start transaction; Query OK, 0 rows affected (0.00 sec) -- 6.Terminal 2 executes CRUD SQL(There is no problem) db_window-2 > insert into account values (null,'mariadb',1000); Query OK, 1 row affected (0.00 sec) -- 7.Terminal 1 waits for the transaction of terminal 2 to complete and executes, otherwise it will block including(CURD) db_window-1 > update account set money = money - 100 where id = 3; -- wait for terminal 2 Commit commit transaction Query OK, 1 row affected (46.09 sec) Rows matched: 1 Changed: 1 Warnings: 0 -- 8.After the transaction execution of terminal 2 is completed, the above update statement can be executed db_window-2 > commit; Query OK, 0 rows affected (0.07 sec) -- 9.Terminal 1 can execute any arbitrary CURD statement db_window-1 > select * from account; +----+-----------+-------+ | id | name | money | +----+-----------+-------+ | 1 | WeiyiGeek | 1000 | | 2 | muzi | 1000 | | 3 | mariadb | 900 | +----+-----------+-------+ 3 rows in set (0.00 sec)

WeiyiGeek.SERIALIZABLE
Summarize: By efficiency, from high to low
read uncommitted > read committed > repeatable read > serializable
According to the degree of interception, from high to bottom
Serializable > Repeatable Read > Read Committed > Read Uncommitted
Database default isolation level:
- The default isolation level of mySql is Repeatable Read
- Oracle's default isolation level is read committed
0x01 database connection pool
What is connection pooling?
Connection pool refers to: creating a pool (container) actually opens up a space (collection) in memory, and places multiple connection objects in the pool to manage connection objects;

WeiyiGeek.
What does the connection pool do?
1. Faster response speed: The connection in the connection pool has been created at the beginning, and if you need to take it directly later, there is no need to create it. 2. Reuse of resources and avoid repeated creation of objects: After the connection objects are used, they can be returned to the pool for unified management.
What are the problems with custom connection pools?
- 1. An additional addBack method is required to return the connection object
- 2. It is necessary to set a singleton to prevent repeated instantiation of objects;
- 3. Interface-oriented programming is not possible because we use the JDBC jar package provided by MySQL/Oracle, and the addBack method is not defined in the interface;
How to solve?
- 1. With addBack as the entry point, you need to remember this method where you use this connection pool, and you can't program for the interface;
- 3. Using the decoration in the design mode, the mode can directly use the rewritten close method. Calling the close method does not really close the database connection object but returns the connection object (just close the database result set);
Complementary Java Design Patterns (four very important) in order from easiest to hardest:
- Singleton pattern (java foundation)
- Engineering mode (java foundation)
- Decoration mode (java foundation)
- Dynamic proxy (java foundation)
Basic example:
copy// Call the connection pool using: /User/src/top/weiyigeek/Web/Test_Pool.java public class Test_Pool { @Test public void testPool() throws SQLException { Connection conn = null; PreparedStatement ps =null; //Note that it is necessary to avoid repeated application of objects here, so you need to use a singleton; CustomDatasource ds = CustomDatasource.getInstance(); try { //Get the link object of the resource pool conn = ds.getConnection(); String sql = "SELECT * FROM user LIMIT 0,10"; ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery(); while(rs.next()) { System.out.println("ID: " + rs.getInt("id") + " , Name = " + rs.getString("name")+", Log in time = " + rs.getDate("uptime")); } rs.close(); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } finally { try { //Close the PreparedStatementd object ps.close(); } catch (Exception e2) { // TODO: handle exception e2.printStackTrace(); } //return object //ds.addBack(conn); //This method is not used after decoration conn.close(); } } }
Decoration mode class: /User/src/top/weiyigeek/pool/ConnectionWrap.java
copy/** * @Desc:Decorate design pattern database connection close return * @author WeiyiGeek * @CreatTime 2:48:41 PM */ public class ConnectionWrap implements Connection { //1. The construction method accesses the connection connection and the connection pool collection Connection connection = null; List <Connection> list ; public ConnectionWrap(Connection connection , List <Connection> list) { super(); this.connection = connection; this.list = list; } //2. Parse the prepared SQL statement @Override public PreparedStatement prepareStatement(String sql) throws SQLException { return connection.prepareStatement(sql); } //3. Override the Close method @Override public void close() throws SQLException { // TODO Auto-generated method stub //connection.close(); //You can also call the original close System.out.println("Someone has come to return the connection object> Before returning, the number of available connections in the pool:"+list.size()); list.add(connection); System.out.println("Someone has come to return the connection object> After the return, the number of available connections in the pool:"+list.size()); } ...... }
Custom connection pool class: /User/src/top/weiyigeek/pool/CustomDatasource.java
copyimport top.weiyigeek.Util.db; public class CustomDatasource implements DataSource { // The method of database resource pool establishment //0. Create objects of this class and provide public access methods to the outside world private static CustomDatasource s = new CustomDatasource(); public static CustomDatasource getInstance() { return s; } // 1. Create a collection of storage connection pool objects List <Connection> list = new ArrayList<Connection>(); public CustomDatasource() { //2. Establish a connection object and store it in the resource pool for(int i = 0; i < 10;i++) { Connection conn; try { conn = db.getConn(); list.add(conn); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } //3. The method for obtaining connections published by the connection pool @Override public Connection getConnection() throws SQLException { // TODO Auto-generated method stub //4. To determine whether the resource pool is used up, add 3 connection objects to the resource pool (of course, the resource pool is limited) if (list.size() == 0 ) { try { for(int i = 0; i < 5; i++) list.add(db.getConn()); } catch (SQLException e) { e.printStackTrace(); } } //return and remove the first element Connection conn = list.remove(0); //The decoration mode wraps the object when it is thrown out. (The key point is worth learning) Connection connection = new ConnectionWrap(conn, list); return connection; } //5. Return the connection object public void addBack(Connection conn) { list.add(conn); } ..... }
Results of the:

WeiyiGeek. Connection Pool
Summarize:
- 1. We generally do not write connection pools ourselves in actual development. We have to stand on the shoulders of giants, but we need to understand its operation principle;
0x02 Open source connection pool
1.OBCP
Description: DBCP (DataBase Connection Pool) database connection pool is a kind of java database connection pool, developed by Apache through the database connection pool, the program can automatically manage the release and disconnection of database connections; Official website download address: http://commons.apache.org/proper/commons-dbcp/download_dbcp.cgi Current 2020306 latest version:
- commons-dbcp:https://mirrors.tuna.tsinghua.edu.cn/apache//commons/dbcp/binaries/commons-dbcp2-2.7.0-bin.zip
- commons-pool:https://mirrors.tuna.tsinghua.edu.cn/apache//commons/pool/binaries/commons-pool2-2.8.0-bin.zip
- commons-logging:https://mirrors.tuna.tsinghua.edu.cn/apache//commons/logging/binaries/commons-logging-1.2-bin.zip (must be introduced or an error will be reported java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory)
Environment dependency: import the jar packages commons-dbcp.jar,commons-pool.jar after downloading;

WeiyiGeek.
actual case: 1. Do not use the configuration file method /User/src/top/weiyigeek/DBCP/OBCPDemo1.java
copypackage top.weiyigeek.DBCP; /** * * @Desc: OBCP Apache Use of open source data connection management frameworks * @author WeiyiGeek * @CreatTime 12:45:22 PM */ public class OBCPDemo1 { @SuppressWarnings("resource") @Test public void testOBCP () { //1. Build the data source object BasicDataSource dataSource = new BasicDataSource(); //2. Get the connection object Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; //3. Database configuration (manual) dataSource.setDriverClassName("org.mariadb.jdbc.Driver"); //Main Protocol Subprotocol Database IP:Port Database dataSource.setUrl("jdbc:mariadb://127.0.0.1:3306/student"); dataSource.setUsername("root"); dataSource.setPassword(""); try { conn = dataSource.getConnection(); //4. Parse the SQL statement ps = conn.prepareStatement("SELECT * FROM user ORDER BY id DESC LIMIT 0,?"); ps.setInt(1, 10); rs = ps.executeQuery(); while(rs.next()) { System.out.println(rs.getInt("id") + " ---- " + rs.getString("name") + " ---- " + rs.getInt("grade")); } rs.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { //db.release(conn, ps, rs); //It is recommended to rewrite the close method to release resources } } }
2. Use the configuration file method. dbcp.properties:
copy#connection settings driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/jdbc username=root password= #<!-- Initialize connection --> initialSize=10 #Maximum number of connections maxActive=50 #<!-- Maximum idle connections --> maxIdle=20 #<!-- Minimum idle connection --> minIdle=5 #<!-- Timeout wait time in milliseconds 6000ms/1000 equals 60 seconds --> maxWait=60000 #The format of the connection property attribute attached when the JDBC driver establishes a connection must be as follows: [property name=property;] #Note: The "user" and "password" properties are passed explicitly, so there is no need to include them here. connectionProperties=useUnicode=true;characterEncoding=utf8 #Specifies the auto-commit state of connections created by the connection pool. defaultAutoCommit=true #The driver default specifies the transaction level (TransactionIsolation) of the connection created by the connection pool. #Available values are one of the following: (See the javadoc for details.) NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE defaultTransactionIsolation=READ_UNCOMMITTED
copy/** * * @Desc: OBCP Read the configuration file to configure the database connection * @author WeiyiGeek * @CreatTime 1:26:18 PM */ public class OBCPDemo2 { @Test public void testDemo2() throws Exception { //1. Use Properties to read the data in the configuration file Properties prop = new Properties(); InputStream is = this.getClass().getClassLoader().getResourceAsStream("dbcp.properties"); //Read jdbc.properties in the project into the input stream prop.load(is); //2. Build the connection object BasicDataSourceFactory factory = new BasicDataSourceFactory(); DataSource datasource = factory.createDataSource(prop); //Introduce properties file //3. Get the connection object Connection conn = datasource.getConnection(); PreparedStatement ps = conn.prepareStatement("SELECT * FROM user LIMIT 0,10"); ResultSet rs = ps.executeQuery(); //4. Print out the data read from the database while(rs.next()) { System.out.println(rs.getInt("id") + " ---- " + rs.getString("name") + " ---- " + rs.getInt("grade")); } //5. Close the connection System.out.println("connection closed"); rs.close(); ps.close(); conn.close(); } }
Results of the:

WeiyiGeek.
2.C3P0 (used more)
Description: C3P0 is an open source JDBC connection pool, which implements data source and JNDI binding, and supports JDBC3 specification and JDBC2 standard extension. Currently, open source projects using it include Hibernate, Spring, etc.
download link: https://sourceforge.net/projects/c3p0/
After the download is completed, import it into the project (Build Path) as above. When we learn a new technology, it is best to look at some of his help documents;
Code example (1): Manual configuration
copyimport top.weiyigeek.Util.db; import com.mchange.v2.c3p0.ComboPooledDataSource; public class C3P0Demo1 { @Test public void Demo1() throws PropertyVetoException,Exception { //1. Create DataSource ComboPooledDataSource cpds = new ComboPooledDataSource(); Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; //2. Set database connection information cpds.setDriverClass("org.mariadb.jdbc.Driver"); cpds.setJdbcUrl("jdbc:mariadb://127.0.0.1:3306/student"); cpds.setUser("root"); cpds.setPassword(""); //3. Get the connection object conn = cpds.getConnection(); ps = conn.prepareStatement("SELECT * FROM user LIMIT 0,?"); ps.setInt(1, 20); //4. Execute the SQL query rs = ps.executeQuery(); System.out.println("serial number - Name - grade"); while (rs.next()) { System.out.println(rs.getInt("id") + " - " + rs.getString("name") + " - " + rs.getShort("grade")); } //5. Close the connection db.release(conn, ps, rs); } }

WeiyiGeek.
Code example (2): The configuration file is configured by c3p0-config.xml by default, bytecode is used to read the file;
copy<c3p0-config> <default-config> <property name="driverClass">org.mariadb.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mariadb://127.0.0.1:3306/student</property> <property name="user">root</property> <property name="password"></property> <property name="automaticTestTable">con_test</property> <property name="checkoutTimeout">30000</property> <property name="idleConnectionTestPeriod">30</property> <property name="initialPoolSize">10</property> <property name="maxIdleTime">30</property> <property name="maxPoolSize">100</property> <property name="minPoolSize">10</property> <property name="maxStatements">200</property> <user-overrides user="test-user"> <property name="maxPoolSize">10</property> <property name="minPoolSize">1</property> <property name="maxStatements">0</property> </user-overrides> </default-config> <!--Multiple databases can be configured--> <named-config name="mysql"> <property name="driverClass">org.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/student</property> <property name="user">root</property> <property name="password"></property> </named-config> <!--Multiple databases can be configured--> <named-config name="oracle"> <property name="driverClass">oracle.jdbc.driver.OracleDriver</property> <property name="jdbcUrl">jdbc:oracle:thin:@192.168.10.25:1521:student</property> <property name="user">master</property> <property name="password"></property> </named-config> </c3p0-config>
Demo code:
copypackage top.weiyigeek.C3P0; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import org.junit.Test; import com.mchange.v2.c3p0.ComboPooledDataSource; import top.weiyigeek.Util.db; /** * * @Desc: C3P0 Read database connection and connection pool configuration through xml file configuration (actually similar to Demo1) * @author WeiyiGeek * @CreatTime 2:38:55 PM */ public class C3P0Demo2 { @Test public void demo2() throws SQLException { //1. Create a DataSource and read and set the database connection information (c3p0-config.xml) ComboPooledDataSource cpds = new ComboPooledDataSource(); //ComboPooledDataSource cpds = new ComboPooledDataSource("oracle"); //You can connect to the specified database in the configuration file Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; //2. Get the connection object conn = cpds.getConnection(); ps = conn.prepareStatement("SELECT count(*) FROM user"); //3. Execute the SQL query rs = ps.executeQuery(); System.out.println("serial number - Name - grade"); while (rs.next()) { System.out.println("total number of students: "+rs.getInt(1) ); } //4. Close the connection db.release(conn, ps, rs); } }
Results of the:
copyMarch 19, 2020 2:44:34 afternoon com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource getPoolManager information: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> con_test, breakAfterAcquireFailure -> false, checkoutTimeout -> 30000, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 1hgevwha81v0n140s2kcd6|33b37288, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> org.mariadb.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 1hgevwha81v0n140s2kcd6|33b37288, idleConnectionTestPeriod -> 30, initialPoolSize -> 10, jdbcUrl -> jdbc:mariadb://127.0.0.1:3306/student, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 30, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 100, maxStatements -> 200, maxStatementsPerConnection -> 0, minPoolSize -> 10, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> null, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ] serial number - Name - grade total number of students: 84 Database connection closed and resources released
Using C3P0 greatly simplifies the Tools class we wrote ourselves:
copyimport com.mchange.v2.c3p0.ComboPooledDataSource; /*** * @Desc: The database connection tool class adopts the c3p0 method (simplifies our code) * @author WeiyiGeek * @CreatTime 1:28:57 PM */ public class db1 { static ComboPooledDataSource cpds = null; static { cpds = new ComboPooledDataSource(); } /** * Get link object in C3P0 * @return Connection */ public static Connection getConn() throws SQLException { return cpds.getConnection(); } /** * Fun:Close the database connection and release resources (note: the order of closing) * @param conn * @param st * @param rs */ public static void release(Connection conn,Statement st, ResultSet rs) { closeRs(rs); closeSt(st); closeConn(conn); System.out.println("\n Database connection closed and resources released\n"); } //Private static method - release query result set private static void closeRs(ResultSet rs) { try { if(rs != null) rs.close(); } catch (SQLException e) { e.printStackTrace(); } finally { rs = null; } } //Private static method - release the statement object private static void closeSt(Statement st) { try { if(st != null) st.close(); } catch (SQLException e) { e.printStackTrace(); } finally { st = null; } } //Private static method - closes database connection private static void closeConn(Connection conn) { try { if(conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } finally { conn = null; } } }
3.DBUtils (emphasis)
What is DBUtils? Answer: Commons DbUtils is an open source tool class library provided by the Apache organization that simply encapsulates JDBC. Using it can simplify the development of JDBC applications without affecting the performance of the program;
To put it simply: DBUtils just simplifies the CRUD code for us, creating a database connection is not within his scope of consideration, you only need to pass in the DataSource connection object to him;
Official website download address: http://commons.apache.org/dbutils/download_dbutils.cgi
Additional instructions:
1. Obtain an instance of the class through the bytecode of the class (implemented through reflection)
copyAccount a = new Account(); Account al = Account.class.newInstance();
2.ResultSetHandler interface implementation class
BeanHander - encapsulates a single queried data into an object (commonly used);
BeanListHander - encapsulates multiple queried data into a List collection with objects (commonly used);
copyPerson res = qr.query("select * from person", new BeanHandler<Person>(Person.class)); List<Person> lp = runner.query("SELECT * FROM person ", new BeanListHandler<Person>(Person.class));
ArrayHandler - encapsulates a single queried data into an array
ArrayListHandler - encapsulates multiple queried data into a collection where the elements are arrays
MapHandler - encapsulates a single queried data into a Map
MapListHandler - encapsulates multiple queried data into a collection. The elements in it are Map
ColumnsListHandler (not commonly used)
KeyedHander (not commonly used) - Multiple records are encapsulated into a Map collection of Map collections. And the outer Map collection can be specified (specify one of the attribute names of the inner Map).
ScalarHander (not commonly used) - encapsulate a single value, such as select count (*), to find the number of pieces of content
copyLong count = (Long)runner.query("SELECT COUNT(*) FROM person",new ScalarHandler()); return count.intValue();

WeiyiGeek.
Query queries the class where the result is stored: (1) The class that stores the query data
copypackage top.weiyigeek.DBUtil; public class Account { private int id; private String name; private float money; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public float getMoney() { return money; } public void setMoney(float money) { this.money = money; } @Override public String toString() { return "Account [serial number=" + id + ", Name=" + name + ", salary=" + money + "]"; } }
(2) Classes implemented by DBUtil
copypackage top.weiyigeek.DBUtil; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import javax.sql.DataSource; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.ResultSetHandler; import org.apache.commons.dbutils.handlers.BeanListHandler; import com.mchange.v2.c3p0.ComboPooledDataSource; /* * Function: DButil CURD Case realization */ public class DBUtilDemo1 { //call implementation public static void main(String[] args) throws SQLException { ComboPooledDataSource cpds = new ComboPooledDataSource(); //Example 1. Insertion test if(insert(cpds)>0) { System.out.println("Inserted successfully"); }else { System.err.println("Insert failed"); } //Example 2. Test deletion if(delete(cpds)>0) { System.out.println("successfully deleted"); }else { System.err.println("failed to delete"); } //Example 3. Test update if(update(cpds)>0) { System.out.println("update completed"); }else { System.err.println("update failed"); } //Example 4. Test anonymous implementation class to return query results Account account = queryone(cpds); System.out.println(account.toString()); //Example 5. Return the result by implementing the interface of ResultSetHandler in DBuntil; List<Account> ls = querytwo(cpds); for(Account worker:ls) { System.out.println(worker.toString()); } } //(1) Function: Test SQL insert statement such as method name public static int insert(DataSource cpds) throws SQLException { QueryRunner qr = new QueryRunner(cpds); int flag = qr.update("INSERT INTO account VALUES (null,?,?)","Zhang Wei",1024); return flag; } //(2) Function: Test SQL delete statement such as method name public static int delete(DataSource cpds) throws SQLException { QueryRunner qr = new QueryRunner(cpds); int flag = qr.update("DELETE FROM account where name = ?","Zhang Wei"); return flag; } //(3) Function: Test SQL update statement such as method name public static int update(DataSource cpds) throws SQLException { QueryRunner qr = new QueryRunner(cpds); int flag = qr.update("UPDATE account SET money=money+100 where id = ? and name = ?",1,"WeiyiGeek"); return flag; } //(4) Function: Test SQL query statement such as method name public static Account queryone(DataSource cpds) throws SQLException { QueryRunner qr = new QueryRunner(cpds); //Anonymous class implementation Account account = qr.query("SELECT * FROM account WHERE id = ?", new ResultSetHandler<Account>() { @Override public Account handle(ResultSet rs) throws SQLException { // TODO Auto-generated method stub Account account = new Account(); while(rs.next()) { int id = rs.getInt("id"); String name = rs.getString("name"); float money = (float)rs.getInt("money"); account.setId(id); account.setName(name); account.setMoney(money); } return account; } }, 1); return account; } //(5) In ResultSetHandler, resultset is converted into other objects for implementation. public static List<Account> querytwo(DataSource cpds) throws SQLException { QueryRunner qr = new QueryRunner(cpds); //- BeanHander - returns an object; //- BeanListHander - returns a collection with objects; List<Account> list= qr.query("SELECT * FROM account", new BeanListHandler<Account>(Account.class)); return list; } }

WeiyiGeek.