package li.dao; import java.sql.Connection; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import javax.sql.DataSource; import li.util.Log; /** * 事务模版工具类 * * @author li (limingwei@mail.com) * @version 0.1.6 (2012-05-08) */ public abstract class Trans { private static final Log log = Log.init(); /** * 当前线程的事务,为空表示未在事务中 */ private static final ThreadLocal<Trans> TRANS_LOCAL = new ThreadLocal<Trans>(); /** * 当前事务管理的链接,每DataSource一个,多DataSource支持 */ private Map<DataSource, Connection> connectionMap = new HashMap<DataSource, Connection>(); /** * 事务隔离级别 */ private Integer level; /** * 是否只读事务 */ private Boolean readOnly; /** * 用于存放一些值,可用于Trans内外通信 */ private Map<Object, Object> map; /** * 返回map引用 */ public Map<Object, Object> map() { return this.map; } /** * 返回事务执行成功与否的标记 */ public Boolean success() { return (Boolean) this.map.get(hashCode() + "~!@#success"); } /** * 获取当前线程的事务,没在事务中则返回空 */ public static Trans current() { return TRANS_LOCAL.get(); } /** * 在事务中获取数据库链接 */ public Connection getConnection(DataSource dataSource) throws Exception { Connection connection = this.connectionMap.get(dataSource); // 从connectionMap中得到为这个DataSource缓存的connection if (null == connection || connection.isClosed()) { // 没有缓存这个DataSource的connection或已被关闭 connection = dataSource.getConnection(); // 获取一个新的connection connection.setAutoCommit(false); // 设置为不自动提交 connection.setTransactionIsolation(null != this.level ? this.level : connection.getTransactionIsolation());// 设置事务级别 connection.setReadOnly(null != this.readOnly ? this.readOnly : connection.isReadOnly());// 设置只读 this.connectionMap.put(dataSource, connection); // 缓存connection } return connection; // 返回这个connection } /** * 定义一个事务,并执行run()中包裹的数据操作方法 */ public Trans() { this(new HashMap<Object, Object>(), null, false); } /** * 定义并执行一个事务,传入一些参数,指定事务级别,指定是否只读 */ public Trans(Map<Object, Object> map, Integer level, Boolean readOnly) { try { try { this.map = map; this.level = level; this.readOnly = readOnly; this.begin(); // 开始事务 this.run(); // 执行事务内方法 this.commit(); // 提交事务 this.map.put(hashCode() + "~!@#success", true); } catch (Exception e) {// QueryRunner里面已经打印栈,事务管理中,也不需要抛出异常,这里就只管流程 this.rollback(); // 回滚事务 this.map.put(hashCode() + "~!@#success", false); } finally { this.end(); // 结束事务 } } catch (Exception e) { throw new RuntimeException(e + " ", e); } } /** * 抽象方法,包裹需要事务控制的Dao方法 */ public abstract void run(); /** * 开始事务,初始化CONNECTION_MAP,或者标记这个事务已被其他事务包裹融化 */ private void begin() { if (null == Trans.current()) { // 未在另一个事务中 TRANS_LOCAL.set(this); log.trace("Trans@? level=? readOnly=? beginning", hashCode(), null == level ? "default" : level, this.readOnly); } else { this.map.put(hashCode() + "~!@#in_trans", true);// 在另一个事务中 } } /** * 结束事务,关闭当前事务中的所有Connection,如果这个事务未在其他事务中的话 */ private void end() throws Exception { if (null == this.map.get(hashCode() + "~!@#in_trans")) {// 未在另一个事务中 for (Entry<DataSource, Connection> connection : this.connectionMap.entrySet()) { connection.getValue().close(); log.trace("Closing Connection in Trans ?", connection.getValue()); } TRANS_LOCAL.set(null); log.trace("Trans@? level=? readOnly=? ending", hashCode(), null == level ? "default" : level, this.readOnly); } } /** * 捆绑提交当前事务中所有Connection的事务,如果这个事务未在其他事务中的话 */ private void commit() throws Exception { if (null == this.map.get(hashCode() + "~!@#in_trans") && !this.readOnly) {// 未在另一个事务中且非只读 for (Entry<DataSource, Connection> connection : this.connectionMap.entrySet()) { connection.getValue().commit(); log.trace("Trans@? level=? readOnly=? commiting ?", hashCode(), null == level ? "default" : level, this.readOnly, connection.getValue()); } } } /** * 捆绑回滚当前事务中所有Connection中的事务,如果这个事务 */ private void rollback() throws Exception { if (null == this.map.get(hashCode() + "~!@#in_trans") && !this.readOnly) {// 未在另一个事务中且非只读 for (Entry<DataSource, Connection> connection : this.connectionMap.entrySet()) { connection.getValue().rollback(); log.trace("Trans@? level=? readOnly=? rollingback ?", hashCode(), null == level ? "default" : level, this.readOnly, connection.getValue()); } } } }