package com.taobao.tddl.repo.mysql.spi; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.sql.DataSource; import com.taobao.tddl.common.exception.TddlException; import com.taobao.tddl.common.utils.ExceptionErrorCodeUtils; import com.taobao.tddl.executor.common.AtomicNumberCreator; import com.taobao.tddl.executor.spi.ITHLog; import com.taobao.tddl.executor.spi.ITransaction; import com.taobao.tddl.group.jdbc.TGroupConnection; import com.taobao.tddl.common.utils.logger.Logger; import com.taobao.tddl.common.utils.logger.LoggerFactory; /** * @author mengshi.sunmengshi 2013-12-6 上午11:31:29 * @since 5.0.0 */ public class My_Transaction implements ITransaction { protected final static Logger logger = LoggerFactory.getLogger(My_Transaction.class); private AtomicNumberCreator idGen = AtomicNumberCreator.getNewInstance(); private Integer id = idGen.getIntegerNextNumber(); /** * 处于事务中的连接管理 */ protected Map<String, List<Connection>> connMap = new HashMap<String, List<Connection>>(1); /** * 当前进行事务的节点 */ protected String transactionalNodeName = null; protected boolean autoCommit = true; protected Stragety stragety = Stragety.STRONG; public enum Stragety { /** 跨机允许读不允许写 */ ALLOW_READ, /** 跨机读写都不允许 */ STRONG, /** 随意跨机 */ NONE } public My_Transaction(boolean autoCommit){ this.autoCommit = autoCommit; } public void beginTransaction() { if (connMap != null && !connMap.isEmpty()) { try { if (connMap != null && !connMap.isEmpty()) { for (List<Connection> conns : connMap.values()) { for (Connection conn : conns) { conn.setAutoCommit(false); } } } } catch (SQLException e) { throw new RuntimeException(e); } } } /** * 策略两种:1. 强一致策略,事务中不允许跨机查询。2.弱一致策略,事务中允许跨机查询; * * @param groupName * @param ds * @param strongConsistent 这个请求是否是强一致的,这个与ALLOW_READ一起作用。 * 当ALLOW_READ的情况下,strongConsistent = * true时,会创建事务链接,而如果sConsistent=false则会创建非事务链接 * @return */ public Connection getConnection(String groupName, DataSource ds) throws SQLException { if (groupName == null) { throw new IllegalArgumentException("group name is null"); } if (autoCommit) {// 自动提交,不建立事务链接 return newConnection(ds); } // if (stragety == Stragety.NONE) { // Connection my_JdbcHandler = getConnection(groupName, ds, true); // return my_JdbcHandler; // } else if (stragety == Stragety.ALLOW_READ) { // if (!strongConsistent && // !groupName.equalsIgnoreCase(transactionalNodeName)) {// 非强一致,又非事务用链接 // Connection my_JdbcHandler = getConnection(groupName, ds, true); // return my_JdbcHandler; // } // } /* * 状态是强一致或ALLOW_READ 策略一致 */ if (transactionalNodeName != null) {// 已经有事务链接了 if (transactionalNodeName.equalsIgnoreCase(groupName)) { List<Connection> conn = getConnections(transactionalNodeName, ds); if (conn.size() != 1 && conn.get(0).getAutoCommit()) { // 拿出来的应该是已经存在的链接,这个链接也必然是事务链接 throw new RuntimeException("connection is not transactional? should not be here"); } return conn.get(0); } else { throw new RuntimeException("只支持单机事务,当前进行事务的是" + transactionalNodeName + " . 你现在希望进行操作的db是:" + groupName); } } else {// 没有事务建立,新建事务 transactionalNodeName = groupName; Connection handler = getConnection(groupName, ds); return handler; } } private List<Connection> getConnections(String groupName, DataSource ds) throws SQLException { List<Connection> conns = connMap.get(groupName); if (conns == null || conns.isEmpty()) { conns = new ArrayList(); Connection conn = newConnection(ds); conns.add(conn); connMap.put(groupName, conns); } if (!autoCommit) { for (Connection conn : conns) { conn.setAutoCommit(false); } } return conns; } private Connection newConnection(DataSource ds) throws SQLException { Connection myConn = ds.getConnection(); return myConn; } public void commit() throws TddlException { try { if (connMap != null && !connMap.isEmpty()) { for (List<Connection> conns : connMap.values()) { for (Connection conn : conns) { conn.commit(); } } } } catch (SQLException e) { throw new TddlException(ExceptionErrorCodeUtils.UNKNOWN_EXCEPTION, e); } transactionalNodeName = null; } public void rollback() throws TddlException { try { if (connMap != null && !connMap.isEmpty()) { for (List<Connection> conns : connMap.values()) { for (Connection conn : conns) { conn.rollback(); } } } } catch (SQLException e) { throw new TddlException(ExceptionErrorCodeUtils.UNKNOWN_EXCEPTION, e); } transactionalNodeName = null; } public long getId() { return id; } public ITHLog getHistoryLog() { return null; } public void close() throws TddlException { if (autoCommit) { // 如果是auto commit模式,因为不存在重用,链接关闭自管理 return; } SQLException exception = null; if (connMap != null && !connMap.isEmpty()) { for (List<Connection> conns : connMap.values()) { for (Connection conn : conns) { try { conn.close(); } catch (SQLException e) { logger.error("", e); exception = e; } } } connMap.clear(); } if (exception != null) { throw new TddlException(ExceptionErrorCodeUtils.UNKNOWN_EXCEPTION, exception); } } public static void closeStreaming(My_Transaction trans, String groupName, DataSource ds) throws SQLException { List<Connection> conns = trans.getConnections(groupName, ds); for (Connection con : conns) { closeStreaming(con); } } public static void closeStreaming(Connection con) throws SQLException { TGroupConnection myconn = getTGroupConnection(con); myconn.cancel(); } private static TGroupConnection getTGroupConnection(Connection con) { if (con instanceof TGroupConnection) { return (TGroupConnection) con; } throw new RuntimeException("impossible,connection is not TGroupConnection:" + con.getClass()); } public boolean isAutoCommit() { return autoCommit; } public void setAutoCommit(boolean autoCommit) { this.autoCommit = autoCommit; } public Map<String, List<Connection>> getConnMap() { return connMap; } public void setConnMap(Map<String, List<Connection>> connMap) { this.connMap = connMap; } public String getTransactionalNodeName() { return transactionalNodeName; } public void setTransactionalNodeName(String transactionalNodeName) { this.transactionalNodeName = transactionalNodeName; } }