Three layers and transaction control of JDBC

Existing problems: user interaction code and business code are mixed together. Changing the interaction mode in the futu...
1. Three storey structure
2 transaction control
3 transaction control in multithreaded environment
4 test with JUnit test framework

Existing problems: user interaction code and business code are mixed together. Changing the interaction mode in the future will inevitably affect the business and have a high degree of coupling,
It is not conducive to reuse and maintenance.
As shown in the figure:

1. Three storey structure

Database access, business processing and user interaction are divided into three modules, which follow a single responsibility, perform their respective duties and reduce coupling.
Call the procedure, as shown in the figure:

1. Business layer design (service)

Concept: call Dao's code to realize specific business functions according to business requirements.
Service design specification:

1.Service Usually by interface+Realize the composition of classes to facilitate decoupling. 2.One Service Business corresponding to a table, for example t_person Business correspondence PersonService,t_user corresponding UserService. 3.Service Naming rules for implementation classes of interfaces: Interfaces+impl,for example PersonService,Implementation class is PersonServiceImpl. 4.All interfaces are placed in service In the package, all implementation classes are placed in service.impl In the sub package. 5.The naming of methods in the interface is business-related, such as registration register,land login If the business is simple and unspeakable, refer to Dao Method naming, replacing initials: 1)add to: add First word. 2)Delete: remove First word. 3)Modification: change First word. 4)Query: find First word.

Demo: the code of the AccountService interface (the method is extracted from the actual business) is as follows:

package com.txw.service; import com.txw.entity.Account; /** * Account business layer * @Author Adair * @QQ:[email protected] * @Date 2021/10/19 9:07 am */ @SuppressWarnings("all") // Annotation warning message public interface AccountService { /** * register * @param acc */ public void register(Account acc) throws Exception; /** * Deposit business * @param username * @param password * @param money */ public void deposit(String username,String password,double money) throws Exception; /** * Withdrawal business * @param username * @param password * @param money */ public void withdraw(String username,String password, double money) throws Exception; /** * Transfer business * @param username * @param password * @param money * @param toUsername */ public void transfer(String username,String password,String toUsername,Double money)throws Exception; }

As shown in the figure:

The code of AccountServiceImpl implementation class is as follows:

package com.txw.service.impl; import com.txw.dao.AccountDao; import com.txw.dao.impl.AccountDaoImpl; import com.txw.entity.Account; import com.txw.service.AccountService; /** * Account business layer implementation class * @Author Adair * @QQ:[email protected] * @Date 2021/10/19 9:26 am */ @SuppressWarnings("all") // Annotation warning message public class AccountServiceImpl implements AccountService { /** * register * @param acc * @throws Exception */ @Override public void register(Account acc) throws Exception { AccountDao ad = new AccountDaoImpl(); // 1. Verify whether the user already exists // 1-1 call dao to query whether there is the same user name Account information Account account = ad.selectAccountByUsername(acc.getUsername()); // 1-2 if Account= Null indicates that there is Account information with the same user name, and registration is refused if(account!=null){ System.out.println("Duplicate user name!"); return; } // 2. Insert Account information ad.insertAccount(acc); } /** * Deposit business * @param username * @param password * @param money * @throws Exception */ @Override public void deposit(String username, String password, double money) throws Exception { } /** * Withdrawal business * @param username * @param password * @param money * @throws Exception */ @Override public void withdraw(String username, String password, double money) throws Exception { } /** * Transfer business * @param username * @param password * @param money * @param toUsername * @throws Exception */ @Override public void transfer(String username, String password, String toUsername,Double money) throws Exception { try { AccountDao ad = new AccountDaoImpl(); // 1. Call dao account_name and password query a row of data Account accA = ad.selectAccountByUsernameAndPassword(username, password); // 2. Verify whether the user name and password are correct. If not, transfer is not allowed if(accA==null){ System.out.println("Wrong user name and password!"); return; } // 3. Call dao account_name query a row of data Account accB = ad.selectAccountByUsername(toUsername); // 4. If the account does not exist, transfer is not allowed if(accB==null){ System.out.println("Opposite account does not exist!"); return; } // 5. Verify whether the balance of account A is sufficient. If not, transfer is not allowed if(accA.getBalance()<money){ System.out.println("Sorry, your credit is running low!"); return; } // 6. Deduct the balance of account A accA.setBalance( accA.getBalance()- money ); // 7. Call dao to modify a row of data ad.updateAccount(accA); // 8. Increase the balance of account B accB.setBalance( accB.getBalance()+ money ); // 9. Call dao to modify a row of data ad.updateAccount( accB ); }catch(Exception e){ e.printStackTrace(); } } }

As shown in the figure:

The code for writing Account is as follows:

package com.txw.entity; import java.io.Serializable; /** * Account entity class * @Author Adair * @QQ:[email protected] * @Date 2021/10/19 9:12 am */ @SuppressWarnings("all") // Annotation warning letter public class Account implements Serializable { Integer accountId; String username; String password; Double balance; public Account() { } public Account(Integer accountId, String username, String password, Double balance) { this.accountId = accountId; this.username = username; this.password = password; this.balance = balance; } public Integer getAccountId() { return accountId; } public void setAccountId(Integer accountId) { this.accountId = accountId; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Double getBalance() { return balance; } public void setBalance(Double balance) { this.balance = balance; } @Override public String toString() { return "Account{" + "accountId=" + accountId + ", username='" + username + '\'' + ", password='" + password + '\'' + ", balance=" + balance + '}'; } }

As shown in the figure:
The SQL statement for creating account database and table structure is as follows:

create table t_account( accout_id int primary key auto_increment, username varchar(20), password varchar(20), balance double )

As shown in the figure:
The code for creating jdbc.properties under com.txw.config package is as follows:

driverClassName=com.mysql.cj.jdbc.Driver username=root password=123456 url=jdbc:mysql://192.168.64.128:3306/test?useUnicode=true&characterEncoding=UTF-8&uesSSL=false&serverTimezone=Asia/Shanghai

As shown in the figure:

2 view (understanding)

Concept: the view layer is responsible for interacting with users, receiving data submitted by users or displaying the results of user operations.
The view layer should be placed in the view package. Since the current view is temporarily replaced by the console window, there are no other requirements.
Demo: the code of AccountSystemView is as follows:

package com.txw.view; import com.txw.entity.Account; import com.txw.service.AccountService; import com.txw.service.impl.AccountServiceImpl; import java.util.Scanner; /** * Account system view * @Author Adair * @QQ:[email protected] * @Date 2021/10/19 10:15 am */ @SuppressWarnings("all") // Annotation warning message public class AccountSystemView { // Because each view method uses Scanner, it is declared as an attribute and can be used by static methods modified by static private static Scanner sc = new Scanner(System.in); public static void main(String[] args) throws Exception { System.out.println("Welcome to our account management system"); System.out.println("Please enter the business number:"); int n = sc.nextInt(); System.out.println("1: deposit"); System.out.println("2: withdraw money"); System.out.println("3: transfer accounts"); switch (n){ case 1: // Call registration method register(); break; case 2: // Call deposit method deposit(); break; case 3: // Call withdrawal method withdraw(); break; case 4: // Call transfer method transfer(); break; } } // View method of corresponding business /** * Call registration method */ public static void register(){ try { // 1. Enter user name and password System.out.println("Please enter user name:"); String username = sc.next(); System.out.println("Please input a password:"); String password = sc.next(); // Call service AccountService as = new AccountServiceImpl(); Account account = new Account(null,username,password,null); as.register(account); } catch (Exception e) { e.printStackTrace(); } } /** * Call deposit method * @throws Exception */ public static void deposit() { try { // 1. Enter user name and password System.out.println("Please enter user name:"); String username = sc.next(); System.out.println("Please input a password:"); String password = sc.next(); System.out.println("Enter deposit amount:"); double money = sc.nextDouble(); // Create Service call business AccountService acs = new AccountServiceImpl(); // Call deposit business method acs.deposit(username,password,money); } catch (Exception e) { e.printStackTrace(); } } /** * Call withdrawal method */ public static void withdraw(){ // 1. Enter user name and password // 2. Call dao account_name and password query a row of data // 3. Verify whether the user name and password are correct. If not, withdrawal is not allowed // 4. Verify whether the balance is sufficient. If not, withdrawal is not allowed // 5. Deduct account balance // 6. Call dao to modify a row of data } /** * Call transfer method * @throws Exception */ public static void transfer() { try { Scanner sc = new Scanner(System.in); System.out.println("Please enter user name and password:"); String usernameA = sc.next(); String password = sc.next(); //4. User input B account name System.out.println("Please enter the opposite account name:"); String usernameB = sc.next(); //7. User input transfer amount System.out.println("Please enter the transfer amount:"); Double balance = sc.nextDouble(); //Use AccountService to complete business AccountService as = new AccountServiceImpl(); as.transfer(usernameA,password,usernameB,balance); }catch(Exception e){ e.printStackTrace(); } } }

As shown in the figure:

Package structure diagram, as shown in the figure:

2 transaction control

Concept: a complete business represents a transaction. We will call Dao for CRUD many times in a business. These SQL statements either succeed or fail together.
Demo: the transfer method failed with the following code:

/** * Transfer business * @param username * @param password * @param money * @param toUsername * @throws Exception */ @Override public void transfer(String username, String password, String toUsername,Double money) throws Exception { try { AccountDao accountDao = new AccountDaoImpl(); // 1. Call dao account_name and password query a row of data Account accA = accountDao.selectAccountByUsernameAndPassword(username, password); // 2. Verify whether the user name and password are correct. If not, transfer is not allowed if(accA == null){ throw new RuntimeException("user name/Wrong password!"); } // Call dao to query whether the user exists Account accB = accountDao.selectAccountByUsername(toUsername); if(accB == null){ throw new RuntimeException("The opposite account does not exist!"); } if(money > accA.getBalance()){ throw new RuntimeException("Sorry, your credit is running low!"); } // Deduction balance accA.setBalance( accA.getBalance() - money ); accountDao.updateAccount(accA); if(1==1) throw new RuntimeException("Business failure"); // Add balance accB.setBalance(accB.getBalance() + money ); accountDao.updateAccount( accB ); }catch(Exception e){ e.printStackTrace(); } } }

As shown in the figure:
1. Methods of controlling transactions
All database operations should be based on Connection, and the control of transactions is no exception. The method of controlling transactions in Connection. As shown in the figure:

3. Location of control transactions
It is set to manual commit before the business starts. After the business ends, the transaction is committed and rolled back when an exception occurs.
The demo code is as follows:

public void transfer(String username, String password, String toUsername,Double money) throws Exception { Connection conn = null; try { // Get links, one link, one transaction conn = JDBCUtilsPlusProMax.getConnection(); System.out.println("AccountService--transfer--"+conn); //Set the transaction submission method to manual submission conn.setAutoCommit(false); System.out.println("-----begin transaction----"); AccountDao ad = new AccountDaoImpl(); //1. Call dao account_name and password query a row of data Account accA = ad.selectAccountByUsernameAndPassword(username, password); // 2. Verify whether the user name and password are correct. If not, transfer is not allowed if(accA==null){ System.out.println("Wrong user name and password!"); return; } // 3. Call dao account_name query a row of data Account accB = ad.selectAccountByUsername(toUsername); // 4. If the account does not exist, transfer is not allowed if(accB==null){ System.out.println("Opposite account does not exist!"); return; } // 5. Verify whether the balance of account A is sufficient. If not, transfer is not allowed if(accA.getBalance()<money){ System.out.println("Sorry, your credit is running low!"); return; } // 6. Deduct the balance of account A accA.setBalance(accA.getBalance() - money); // 7. Call dao to modify a row of data ad.updateAccount(accA); // if(1==1)throw new RuntimeException("business failure"); // 8. Increase the balance of account B accB.setBalance(accB.getBalance() + money); // 9. Call dao to modify a row of data ad.updateAccount(accB); // After all business codes are executed, submit the transaction conn.commit(); System.out.println("-----commit----"); }catch(Exception e){ e.printStackTrace(); conn.rollback(); // RollBACK System.out.println("-----rollback----"); }finally{ JDBCUtilsPlusProMax.close(null,null,conn); } }

As shown in the figure:

Note: in actual development, no matter how simple the business layer method is, transaction control must be added.
3. Link sharing
Since the transaction control is based on the link, it must be ensured that the link controlling the transaction is the same as the link sending SQL.
Example: the link obtained by Service and Dao is not a shared link, so the control transaction fails. As shown in the figure:
Solution steps

  1. Modify JDBC utils to join the judgment. If the link has been created, no new link will be created.
    The demo code is as follows:
package com.txw.util; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.Properties; /** * JDBC Tool class * @Author Adair * @QQ:[email protected] * @Date 2021/10/20 11:35 am */ @SuppressWarnings("all") // Annotation warning message public class JDBCUtils { private static Properties p = new Properties(); // 1. Extract the Connection object as a static attribute without repeated creation private static Connection conn = null; static { InputStream is = JDBCUtilsPlus.class.getResourceAsStream("/com/txw/config/jdbc.properties"); try { p.load(is); } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection(){ try { // 2. Add if judgment // If conn is not null for the second call, it is not created if (conn == null){ // Use the getProperty method to obtain the corresponding value according to the key // 1. Load drive Class.forName(p.getProperty("driverClassName")); // 2. Create links String dbUsername = p.getProperty("username"); String dbPassword = p.getProperty("password"); String url = p.getProperty("url"); conn = DriverManager.getConnection(url, dbUsername, dbPassword); } }catch (Exception e){ e.printStackTrace(); } return conn; } /** * Close the resourceresultset Preparedstatement connection * If you need to close any resource, you can pass in any object. If no resource needs to be closed, you can pass in null * Example: JDBC utils. Close (RS, PSTM, Conn); Close ResultSet, PreparedStatement, Connection * JDBCUtils.close(null,pstm,conn);Close PreparedStatement and Connection * @param rs * @param pstm * @param conn */ public static void close(ResultSet rs, PreparedStatement pstm, Connection conn){ trycatch(Exception e) trycatch(Exception e) trycatch(Exception e) } }

As shown in the figure:
The code of AccountDaoImpl is as follows:

package com.txw.dao.impl; import com.txw.dao.AccountDao; import com.txw.entity.Account; import com.txw.util.JDBCUtils; import com.txw.util.JDBCUtilsPlus; import com.txw.util.JDBCUtilsPlusProMax; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; /** * Business persistence layer implementation class * @Author Adair * @QQ:[email protected] * @Date 2021/10/19 0019 9:32 am */ @SuppressWarnings("all") // Annotation warning message public class AccountDaoImpl implements AccountDao { private Account acc = null; private Connection conn = null; private PreparedStatement pstm = null; private ResultSet rs = null; /** * Add account * @param account */ @Override public void insertAccount(Account acc) throws Exception{ conn = JDBCUtilsPlus.getConnection(); String sql = "insert into t_account values(null,?,?,?)"; pstm = conn.prepareStatement(sql); pstm.setString(1,acc.getUsername()); pstm.setString(2,acc.getPassword()); pstm.setDouble(3,0.0); // The new account balance is 0 pstm.executeUpdate(); JDBCUtilsPlus.close(null,pstm, conn); } /** * Query account according to user name * @param username * @return */ @Override public Account selectAccountByUsername(String username) throws Exception{ // Load driver, get link conn = JDBCUtilsPlus.getConnection(); // Prepare sql and create tools to execute sql String sql = "select account_id,username,password,balance from t_account where username=?;"; PreparedStatement pstm = conn.prepareStatement(sql); pstm.setString(1,username); // Execute sql ResultSet rs = pstm.executeQuery(); Account account = null; // Processing result set if(rs.next()){ int accountId = rs.getInt("account_id"); String uname = rs.getString("username"); String paw = rs.getString("password"); double balance = rs.getDouble("balance"); account = new Account(accountId,uname,paw,balance); } JDBCUtilsPlus.close(rs,pstm,conn); return account; } /** * Query account according to user name and password * @param username * @param password * @return */ @Override public Account selectAccountByUsernameAndPassword(String username, String password) throws Exception{ // Load driver, get link conn = JDBCUtilsPlus.getConnection(); // Prepare sql and create tools to execute sql String sql = "select account_id,username,password,balance from t_account where username=? and password=?;"; pstm = conn.prepareStatement(sql); pstm.setString(1,username); pstm.setString(2,password); // Execute sql ResultSet rs = pstm.executeQuery(); Account account = null; // Processing result set if(rs.next()){ int accountId = rs.getInt("account_id"); String uname = rs.getString("username"); String paw = rs.getString("password"); double balance = rs.getDouble("balance"); account = new Account(accountId,uname,paw,balance); } JDBCUtilsPlus.close(rs,pstm,conn); return account; } /** * Modify account * @param account */ @Override public void updateAccount(Account account) throws Exception{ conn = JDBCUtilsPlusProMax.getConnection(); System.out.println("AccountDao--update--"+conn); String sql = "update t_account set username=?,password=?,balance=? where account_id = ?;"; pstm = conn.prepareStatement( sql ); pstm.setString(1,acc.getUsername()); pstm.setString(2,acc.getPassword()); pstm.setDouble(3,acc.getBalance()); pstm.setInt(4,acc.getAccountId()); pstm.executeUpdate(); JDBCUtilsPlusProMax.close(null,pstm,null); } /** * Query all data * @return * @throws Exception */ @Override public List<Account> selectAccounts() throws Exception { // Load driver, get link conn = JDBCUtilsPlus.getConnection(); // Prepare sql and create tools to execute sql String sql = "select * from t_account"; pstm = conn.prepareStatement(sql); // Execute sql rs = pstm.executeQuery(); List<Account> list = new ArrayList<>(); Account account = null; // Processing result set if(rs.next()){ int accountId = rs.getInt("account_id"); String uname = rs.getString("username"); String paw = rs.getString("password"); double balance = rs.getDouble("balance"); account = new Account(accountId,uname,paw,balance); list.add(account); } JDBCUtilsPlus.close(rs,pstm,conn); return list; } /** * Delete a row of data according to id * @param id * @throws Exception */ @Override public void deleteAccountById(Integer id) throws Exception { // Load driver, get link conn = JDBCUtilsPlus.getConnection(); // Prepare to send SQL String sql = "delete from t_account where account_id = ?"; pstm = conn.prepareStatement(sql); pstm.setInt(1,id); // Execute SQL pstm.executeUpdate(); // close resource JDBCUtilsPlus.close(null,pstm,conn); } }

Implementation steps:

1.take Connection Extract as attributes to avoid each call caused by local variables getConnection Will be recreated. 2.join if Judgment, if not Connection Create, otherwise do not create.
  1. Because the service needs to submit a transaction using a link object, dao is no longer responsible for closing the link.
    The demo code is as follows:
/** * Query account according to user name * @param username * @return */ @Override public Account selectAccountByUsername(String username) throws Exception{ // Load driver, get link conn = JDBCUtilsPlus.getConnection(); // Prepare sql and create tools to execute sql String sql = "select account_id,username,password,balance from t_account where username=?;"; pstm = conn.prepareStatement(sql); pstm.setString(1,username); // Execute sql rs = pstm.executeQuery(); Account account = null; // Processing result set if(rs.next()){ int accountId = rs.getInt("account_id"); String uname = rs.getString("username"); String paw = rs.getString("password"); double balance = rs.getDouble("balance"); account = new Account(accountId,uname,paw,balance); } //No longer close linked resources JDBCUtils.close(rs,pstm,null); return account; }

As shown in the figure:
Test multiple access links
The demo code is as follows:

package com.txw.test; import com.txw.util.JDBCUtilsPlus; import java.sql.Connection; /** * JDBC Test class * @Author Adair * @QQ:[email protected] * @Date 2021/10/20 10:52 am */ @SuppressWarnings("all") // Annotation warning message public class TestJDBCUtils { public static void main(String[] args) { // Test tool class Connection conn1 = JDBCUtils.getConnection(); System.out.println(conn1); // Load driver, get link Connection conn2 = JDBCUtils.getConnection(); System.out.println(conn2); // Execute SQL // Processing results // close resource } }

As shown in the figure:

3 transaction control in multithreaded environment

Multiple users are multiple threads. When the system is exposed to the use of multiple users, new problems appear.
The Connection object is over shared. All threads use one. If thread 1 closes the link, thread 2 will not be able to use it.
The demo code is as follows:

package com.txw.test; import com.txw.service.AccountService; import com.txw.service.impl.AccountServiceImpl; /** * Test account business layer * @Author Adair * @QQ:[email protected] * @Date 2021/10/20 11:20 am */ @SuppressWarnings("all") // Annotation warning message public class TestAccountService { public static void main(String[] args) { AccountService accountService = new AccountServiceImpl(); Thread t1 = new Thread(){ @Override public void run() { try { accountService.transfer("Adair","123456","Adair999",100.00); } catch (Exception e) { e.printStackTrace(); } } }; Thread t2 = new Thread(){ @Override public void run() { try { Thread.sleep(1000); accountService.transfer("Adair","123456","Adair666",200.00); } catch (Exception e) { e.printStackTrace(); } } }; // Start thread t1.start(); t2.start(); } }

As shown in the figure:

Core problem: the Connection object is stored in JDBC utils and can be shared by multiple threads.
Solution: store the Connection in the thread and assign a Connection object to each thread.

  1. ThreadLocal
    Concept: ThreadLocal can open up an independent memory space for each thread, store (bind) an object for the thread, and will not be obtained by other threads.
    Common methods, as shown in the figure:

    The demo code is as follows:
package com.txw.util; /** * Thread test * @Author Adair * @QQ:[email protected] * @Date 2021/10/20 0020 10:59 am */ @SuppressWarnings("all") // Annotation warning message public class ThreadLocalTest { public static void main(String[] args) { // Create ThreadLocal ThreadLocal<String> threadLocal = new ThreadLocal<>(); Thread t1 = new Thread() { @Override public void run() { // Bind data to current thread threadLocal.set("t1----value"); // Gets the data bound to threadLocal by the current thread System.out.println(threadLocal.get()); // t1----value } }; Thread t2 = new Thread() { @Override public void run() { // Analog network delay try { Thread.sleep(300); } catch (Exception e) { e.printStackTrace(); } // Gets the data bound to threadLocal by the current thread System.out.println(threadLocal.get()); // null } }; // Start thread t1.start(); t2.start(); } }

As shown in the figure:

Implementation principle: ThreadLocal stores a Map internally, takes the current thread as the key, and takes the bound data as value to form a key value pair and store it in the Map.
For example:

When obtaining value, you can only obtain the value corresponding to the current thread, so as to store data independent of threads.
2. Modify JDBC utils
Save the Connection object to ThreadLocal and assign an independent Connection object to each thread.
JDBCUtils final power enhancement.
The demo code is as follows:

package com.txw.util; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.Properties; /** * JDBC Tool class * @Author Adair * @QQ:[email protected] * @Date 2021/10/20 10:50 am */ @SuppressWarnings("all") // Annotation warning message public class JDBCUtilsPlusProMax { // Use Properties to store the key value in the configuration file private static Properties ps = new Properties(); // Create ThreadLocal to store linked objects, and bind one linked object to one thread private static ThreadLocal<Connection> tl = new ThreadLocal<>(); // Static code blocks are executed only once static{ try { // Specify profile path // In the path: the first / indicates src InputStream is = JDBCUtilsPlusProMax.class.getResourceAsStream("/com/txw/config/jdbc.properties"); // Automatically read the configuration file from the stream and convert it to a key value pair ps.load( is ); // Get value according to key Class.forName(ps.getProperty("driverClassName")); }catch(Exception e){ e.printStackTrace(); } } /** * Create linked object and return * @return */ public static Connection getConnection(){ try { // Get the link object stored by the current thread from ThreadLocal Connection conn = tl.get(); // If conn is null, create a link and assign a value to conn; otherwise, return the conn link object directly if(conn==null) { // 2. Create links // Get the corresponding value according to the key String url = ps.getProperty("url"); String username = ps.getProperty("username"); String password = ps.getProperty("password"); // Create a new link, add the link object to ThreadLocal and bind it with the thread conn = DriverManager.getConnection(url, username, password); // binding tl.set(conn); } }catch(Exception e){ e.printStackTrace(); } // Returns the thread object created in ThreadLocal return tl.get(); } /** * Close the resourceresultset Preparedstatement connection * If you need to close any resource, you can pass in any object. If no resource needs to be closed, you can pass in null * Example: JDBC utils. Close (RS, PSTM, Conn); Close ResultSet, PreparedStatement, Connection * JDBCUtils.close(null,pstm,conn);Close PreparedStatement and Connection * @param rs * @param pstm * @param conn */ public static void close(ResultSet rs, PreparedStatement pstm, Connection conn){ trycatch(Exception e) trycatch(Exception e) try{ if(conn!=null){ conn.close(); // Delete useless links in ThreadLocal, and create new links next time tl.remove(); } }catch(Exception e) } }

As shown in the figure:

Test the business test in the multithreaded environment again.

4 test with JUnit test framework

Test scheme for replacing main function
A method to be tested must have a test class. The number of test classes is very large and difficult to manage.
Solution: JUnit test framework
Usage idea: using @ Test annotation to describe common methods can make the method have the same running ability as the main function.
To use the JUnit 4 framework:
2. Use framework
Use requirements:

  1. The test class must be a public class
  2. The test method must be an exposed, non static, parameterless, and return value free method
The simplest common method
  1. Note: try not to define a class named Test under the same package to avoid confusion
    The @ Test description must be added to the Test method to run.

20 October 2021, 00:44 | Views: 5644

Add new comment

For adding a comment, please log in
or create account

0 comments