每個連接都有自己的獨立事務,會造成數據的不一致
這組操作應該要么一起操作成功,要么一起操作失敗, 應該使用同一個連接,只有一個能控制事務的對象
需要使用ThreadLocal對象把Connection和當前線程綁定, 從而使一個線程中只有一個能控制事務的對象
關於ThreadLocal: Java並發編程:深入剖析ThreadLocal
事務控制應該都是在業務層
創建一個連接的工具類,它用於從數據源中獲取一個連接,並且實現和線程的綁定
/** * 連接的工具類,它用於從數據源中獲取一個連接,並且實現和線程的綁定 */ public class ConnectionUtils { private ThreadLocal<Connection> tl = new ThreadLocal<Connection>(); private DataSource dataSource; public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } /** * 獲取當前線程上的連接 * @return */ public Connection getThreadConnection() { try{ //1.先從ThreadLocal上獲取 Connection conn = tl.get(); //2.判斷當前線程上是否有連接 if (conn == null) { //3.從數據源中獲取一個連接,並且存入ThreadLocal中 conn = dataSource.getConnection(); tl.set(conn); } //4.返回當前線程上的連接 return conn; }catch (Exception e){ throw new RuntimeException(e); } } /** * 把連接和線程解綁 */ public void removeConnection(){ tl.remove();//remove()用來移除當前線程中變量的副本
}
}
和事務管理相關的工具類,它包含了,開啟事務,提交事務,回滾事務和釋放連接
1 /** 2 * 和事務管理相關的工具類,它包含了,開啟事務,提交事務,回滾事務和釋放連接 3 */ 4 public class TransactionManager { 5 6 private ConnectionUtils connectionUtils; 7 8 public void setConnectionUtils(ConnectionUtils connectionUtils) { 9 this.connectionUtils = connectionUtils; 10 } 11 12 /** 13 * 開啟事務 14 */ 15 public void beginTransaction(){ 16 try { 17 connectionUtils.getThreadConnection().setAutoCommit(false); 18 }catch (Exception e){ 19 e.printStackTrace(); 20 } 21 } 22 23 /** 24 * 提交事務 25 */ 26 public void commit(){ 27 try { 28 connectionUtils.getThreadConnection().commit(); 29 }catch (Exception e){ 30 e.printStackTrace(); 31 } 32 } 33 34 /** 35 * 回滾事務 36 */ 37 public void rollback(){ 38 try { 39 connectionUtils.getThreadConnection().rollback(); 40 }catch (Exception e){ 41 e.printStackTrace(); 42 } 43 } 44 45 46 /** 47 * 釋放連接 48 */ 49 public void release(){ 50 try { 51 connectionUtils.getThreadConnection().close();//還回連接池中 52 connectionUtils.removeConnection(); 53 }catch (Exception e){ 54 e.printStackTrace(); 55 } 56 } 57 }
1 public class AccountDaoImpl implements IAccountDao { 2 3 private QueryRunner runner; 4 private ConnectionUtils connectionUtils; 5 6 public void setRunner(QueryRunner runner) { 7 this.runner = runner; 8 } 9 10 public void setConnectionUtils(ConnectionUtils connectionUtils) { 11 this.connectionUtils = connectionUtils; 12 } 13 14 public List<Account> findAllAccount() { 15 try{ 16 return runner.query(connectionUtils.getThreadConnection(),"select * from account",new BeanListHandler<Account>(Account.class)); 17 }catch (Exception e) { 18 throw new RuntimeException(e); 19 } 20 } 21 }