(未使用AOP)使用ThreadLocal对象把Connection和当前线程绑定, 从而使一个线程中只有一个能控制事务的对象
每个连接都有自己的独立事务,会造成数据的不一致
这组操作应该要么一起操作成功,要么一起操作失败, 应该使用同一个连接,只有一个能控制事务的对象
需要使用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 }