I. Why use threadlocal:
In the previous blog post, we controlled the transaction by passing the connection way, which can achieve the goal, but it makes people look uncomfortable,
If it involves invoking multiple service, do I still have to pass connection from the controller layer?
Threadlocal's usage see the previous blog, which guarantees that instance variables of a class have a separate copy in each thread.
So that the instance variables in other threads are not affected
Two. How to use threadlocal:
1. Write a TransactionManager class:
/** * Management Transaction */public class TransactionManager {private static threadlocal<connection> local = new Threadlocal<conn Ection> ();//open transaction public static void BeginTransaction () throws SQLException {Connection conn = jdbcutils.getconnection (); Conn.setautocommit (false); Deposit the connection to Threadlocallocal.set (conn);} ROLLBACK TRANSACTION public static void Rollback () throws SQLException {Connection conn = Local.get (); if (conn! = null) {Conn.rollback () ; Conn.close ();//emptying Threadlocallocal.remove ();}} Commit TRANSACTION public static void Commitandclose () throws SQLException {Connection conn = Local.get (); if (conn! = null) {Conn.comm It (); Conn.close ();//Empty Threadlocallocal.remove ();}} Get database connection public static Connection getconnection () {return local.get ();}}
use threadlocal to make sure that the same thread gets the same connection.
2. Modify the Business processing class
/** * Business Logic Layer */public class Accountservice {public void transfer (account Outaccount, account Inaccount, int. money) throws S qlexception {//Open transaction transactionmanager.begintransaction ();//Query two accounts accountdao Accountdao = new Accountdao (); O Utaccount = Accountdao.findaccountbyid (Outaccount.getid ()); inaccount = Accountdao.findaccountbyid (InAccount.getId ( );//Transfer-Modify the original account amount Outaccount.setmoney (Outaccount.getmoney ()-money); Inaccount.setmoney (Inaccount.getmoney () + cash) try {//Update account Amount accountdao.update (Outaccount); accountdao.update (inaccount);//Transfer successful, Commit Transaction Transactionmanager.commitandclose ();} catch (Exception e) {//Transfer failed, ROLLBACK transaction transactionmanager.rollback (); E.printstacktrace ();}}}
By using TransactionManager to manage transactions, the code becomes more concise.
3. Modifying the DAO class
/** * DAO Layer: CRUD */public class Accountdao {//Query account public accounts findaccountbyid (int id) throws SQLException {String sql = "SELECT * from account where id =?"; O Bject[] params = {ID}; Queryrunner Queryrunner = new Queryrunner (Jdbcutils.getdatasource ()); return queryrunner.query (SQL, new Beanhandler <Account> (Account.class), params);} Update accounts public void update throws SQLException {String sql = ' Update account set name =? ', Money =? WHERE id =? "; O Bject[] params = {account.getname (), Account.getmoney (), Account.getid ()};//Get the connection from the threadlocal, The same thread gets the same connection connection conn = Transactionmanager.getconnection (); Queryrunner Queryrunner = new Queryrunner () queryrunner.update (conn, SQL, params);}}
You do not need to pass connection to get the connection directly from the TransactionManager.
Three. Summary:
Both service and DAO get connection through TransactionManager, and in the same thread, they use the same connection object throughout the transaction, so the transaction is processed successfully. DAO does not accept business-unrelated objects, eliminates API pollution, and uses TransactionManager to manage transactions, simplifying the service layer's code.
Java Transactions (iii)-Using threadlocal