由于请求中的一个事务涉及多个 DAO 操作,而这些 DAO 中的 Connection 不能从连接池中获得,如果是从连接池获得的话,两个 DAO 就用到了两个 Connection,这样的话是没有办法完成一个事务的。 DAO 中的 Connection 如果是从 ThreadLocal 中获得 Connection 的话那 么这些 DAO 就会被纳入到同一个 Connection 之下。当然了,这样的话, DAO 中就不能把 Connection 给关了,关掉的话,下一个使用者就不能用了。
ThreadLocal:线程本地变量该类提供了线程局部变量。这些变量不同于它们的普通对应物,因为访问一个变量(通过其 get 或 set 方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。ThreadLocal 实例通常是类中的私有静态字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联。
事务是一种机制、是一种操作序列,它包含了一组数据库操作命令,这组命令要么全部执行,要么全部不执行。因此事务是一个不可分割的工作逻辑单元。在数据库系统上执行并发操作时事务是作为最小的控制单元来使用的。这特别适用于多用户同时操作的数据通信系统。
在业务逻辑中我们要统一管理事务,但是在一个事务中会涉及到多个Dao,不同的DAO取得的是不同的Connection对象,这样就不能实现统一管理事务。
那么怎么才能实现两个或多个DAO用同一个事务来控制,来统一管理事务那?
首先就要解决一个根本问题,我们在一个事务中,不同的DAO取得的是同一个Connection,这个要怎么实现呢。我们想到了TheadLocal.
因为当一个业务逻辑要对多个DAO进行处理的时候,此操作属于同一个线程内。所以,我们希望能把此Connection放在线程内,或者和线程有关联。
在任何一个线程内都可以用ThreadLocal来保存一个变量的copy,这样,如果此对象存在,就可以直接取用。
如果ThreadLocal中放置connection, 保证事务中的DAO类获取的都是同一个connection,这样才保证事务。所以,在同一个线程内,不同的DAO就可以保证取得到的是同一个Connection
这样就实现了,事务的统一管理
ThreadLocal的API如下图:
下面是ThreadLocal对Connection的封装
public Class ConnectionManager { private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>; public static Connection getConnection(){ Connection conn = connectionHolder.get(); if (conn == null ){ conn = DbUtil.getConnection(); connectionHolder.set(conn); } return conn; }
public static void closeConnection(){ Connection conn = connectionHolder.get(); if (conn != null ){ try { conn.close(); connectionHolder.remove(); }catch (SQLException e){ e.printStackTrace(); } } }
public static void beginTransaction(Connection conn){ try { if (conn != null ){ if (conn.getAutoCommit()){ conn.setAutoCommit(false ); } } }catch (SQLException e){ e.printStackPrince(); } }
public static void commitTransaction(Connection conn){ try { if (conn != null ){ if (!conn.getAutoCommit()){ conn.commit(); } } }catch (SQLException e){ e.printStackTrace(); } }
public static void rollbackTransaction(){ try { if (conn != null ){ if (!conn.getAutoCommit()){ conn.rollback(); } } }catch (SQLException e){ e.printStackTrace(); } } }
以下是业务逻辑事务管理
public void addFlowCard(FlowCard flowCard) Connection conn = null ; try { conn = ConnectionManager.getConnection(); ConnectionManager.beginTransaction(conn); flowCardDao.addFlowCardMaster(flowCardVouNo, flowCard); flowCardDao.addFlowCardDetail(flowCardVouNo, flowCard.getFlowCardDetailList()); if (!conn.getAutoCommit()) { ConnectionManager.commitTransaction(conn); } }catch (Exception e) { e.printStackTrace(); if (!conn.getAutoCommit()) { ConnectionManager.rollbackTransaction(conn); } throw new ApplicationException( "操作失败!" ); }finally { ConnectionManager.closeConnection(); } }