ibatis2.3源码之数据源&连接池浅析

数据源(datasource包&jdbc包)

     在datasource包中ibatis提供三类对外数据源factory,分别为:SimpleDataSourceFactory、JndiDataSourceFactory、DbcpDataSourceFactory。

 

SimpleDataSourceFactory

SimpleDataSourceFactory对外提供简单数据源,接口定义如下:

 

Java代码   收藏代码
  1. public class SimpleDataSourceFactory implements DataSourceFactory {  
  2.   private DataSource dataSource;  
  3.   public void initialize(Map map) {// map是从sqlMapConfig.xml配置文件拆分出来的配置信息,用于初始化数据源。  
  4.     dataSource = new SimpleDataSource(map);  
  5.   }  
  6. }  

 工厂定义很简单,主要对外提供一个javax.sql.DataSource数据源。

 

 对于数据源来说,配置信息涉及到:

Java代码   收藏代码
  1. // Required Properties  
  2. private static final String PROP_JDBC_DRIVER = "JDBC.Driver";  
  3. private static final String PROP_JDBC_URL = "JDBC.ConnectionURL";  
  4. private static final String PROP_JDBC_USERNAME = "JDBC.Username";  
  5. private static final String PROP_JDBC_PASSWORD = "JDBC.Password";  
  6. private static final String PROP_JDBC_DEFAULT_AUTOCOMMIT = "JDBC.DefaultAutoCommit";  
  7.   
  8. // Optional Properties  
  9. private static final String PROP_POOL_MAX_ACTIVE_CONN = "Pool.MaximumActiveConnections";  
  10. private static final String PROP_POOL_MAX_IDLE_CONN = "Pool.MaximumIdleConnections";  
  11. ...  

典型的数据源配置如下:

Java代码   收藏代码
  1. <transactionManager type="JDBC">  
  2.     <dataSource type="DBCP">  
  3.     <property name="JDBC.Driver" value="${driver}"/>  
  4.     <property name="JDBC.ConnectionURL" value="${url}"/>  
  5.     <property name="JDBC.Username" value="${username}"/>  
  6.     <property name="JDBC.Password" value="${password}"/>  
  7.     <property name="Pool.MaximumActiveConnections" value="8"/>  
  8.     <property name="Pool.MaximumIdleConnections" value="8"/>  
  9.     ....      
  10.     </dataSource>  
  11. </transactionManager>  

 

知道了需要配置的参数后,第一件是就是调用SimpleDataSource的initialize(Map props)做初始化工作,主要需要校验、设置默认值或赋值等。

   大堆的初始化工作中就不说了,注意到initialize方法里有个driverProps变量,用于存储用户在配置中以Driver.开头的配置,如<property name="Driver.xxx" values="xxx" />,在建立连接池的时候,加载这些配置(DriverManager.getConnection(jdbcUrl, driverProps))。

 

JndiDataSourceFactory

   同样ibatis也支持JNDI来初始化datasource,主要用于让服务器容器管理连接池。同样初始化工作、获取数据源实现如下:

Java代码   收藏代码
  1. public void initialize(Map properties) {  
  2.    try {  
  3.      InitialContext initCtx = null;  
  4.      Hashtable context = getContextProperties(properties);  
  5.   
  6.      if (context == null) {  
  7.        initCtx = new InitialContext();  
  8.      } else {  
  9.        initCtx = new InitialContext(context);  
  10.      }  
  11.   
  12.      if (properties.containsKey("DataSource")) {  
  13.        dataSource = (DataSource) initCtx.lookup((String) properties.get("DataSource"));  
  14.      } else if (properties.containsKey("DBJndiContext")) { // LEGACY --Backward compatibility          
  15.        dataSource = (DataSource) initCtx.lookup((String) properties.get("DBJndiContext"));  
  16.      } else if (properties.containsKey("DBFullJndiContext")) { // LEGACY --Backward compatibility  
  17.        dataSource = (DataSource) initCtx.lookup((String) properties.get("DBFullJndiContext"));  
  18.      } else if (properties.containsKey("DBInitialContext")  
  19.          && properties.containsKey("DBLookup")) { // LEGACY --Backward compatibility  
  20.        Context ctx = (Context) initCtx.lookup((String) properties.get("DBInitialContext"));  
  21.        dataSource = (DataSource) ctx.lookup((String) properties.get("DBLookup"));  
  22.      }  
  23.   
  24.    } catch (NamingException e) {  
  25.      throw new SqlMapException("There was an error configuring JndiDataSourceTransactionPool. Cause: " + e, e);  
  26.    }  
  27.  }  

 

DbcpDataSourceFactory

 使用了第三方apache的dbcp来管理连接池。工厂接口很简单,如下:

Java代码   收藏代码
  1. public class DbcpDataSourceFactory implements DataSourceFactory {  
  2.   
  3.   private DataSource dataSource;  
  4.   
  5.   public void initialize(Map map) {  
  6.     DbcpConfiguration dbcp = new DbcpConfiguration(map);  
  7.     dataSource = dbcp.getDataSource();  
  8.   }  
  9. }  

 

加载dbcp的时候,有个判断配置Map是否含有“JDBC.Driver“属性,如下:

Java代码   收藏代码
  1. BasicDataSource basicDataSource = null;  
  2.    if (map.containsKey("JDBC.Driver")) {  
  3.      basicDataSource = new BasicDataSource();  
  4.      String driver = (String) map.get("JDBC.Driver");  
  5.      String url = (String) map.get("JDBC.ConnectionURL");  
  6.      String username = (String) map.get("JDBC.Username");  
  7.    ...   

如果有:则正常加载所有属性(源码省略),这里注意IBATIS只为DBCP加载一定量的配置,其他DBCP配置请以Driver.开头。

如果没有JDBC.Driver,则利用反射的知识进行赋值,在赋值的时候ibatis做了点类型转换的工作,因为源数据都是String字符类型,需要反射invoke到方法里,需要做类型变换,如下:

 

Java代码   收藏代码
  1. private BasicDataSource newDbcpConfiguration(Map map) {  
  2.     BasicDataSource basicDataSource = new BasicDataSource();  
  3.     Iterator props = map.keySet().iterator();  
  4.     while (props.hasNext()) {  
  5.       String propertyName = (String) props.next();  
  6.       if (PROBE.hasWritableProperty(basicDataSource, propertyName))//判断basticDataSource对象有没有propertyName属性 {  
  7.         String value = (String) map.get(propertyName);  
  8.         Object convertedValue = convertValue(basicDataSource, propertyName, value);// 将value类型转换成basicDataSource对象propertyName变量的类型  
  9.         PROBE.setObject(basicDataSource, propertyName, convertedValue);  
  10.       }  
  11.     }  
  12.     return basicDataSource;  
  13.   }  
  14.   
  15.   private Object convertValue(Object object, String propertyName, String value) {  
  16.     Object convertedValue = value;  
  17.     Class targetType = PROBE.getPropertyTypeForSetter(object, propertyName);// 获取object对象propertyName变量的类型  
  18.     if (targetType == Integer.class || targetType == int.class) {  
  19.       convertedValue = Integer.valueOf(value);  
  20.     } else if (targetType == Long.class || targetType == long.class) {  
  21.       convertedValue = Long.valueOf(value);  
  22.     } else if (targetType == Boolean.class || targetType == boolean.class) {  
  23.       convertedValue = Boolean.valueOf(value);  
  24.     }  
  25.     return convertedValue;  
  26.   }  

 

以上关于ibatis三类数据源加载就完成了,对于加载数据源,看到ibatis基本没有什么限制,甚至可以不配置任何数据源信息,这为外部应用加载其他数据源提供了很大灵活性。

 

 

连接池(SimpleDataSource)

 

    对于JNDIDataSource和DBCP都有自己的连接池管理,而SimpleDataSource由ibatis自己管理着连接,所有需要有自己的实现。在上面创建SimpleDataSource的时,ibatis并不马上建立自己的连接池的,而是在第一次使用Connection时触发连接池的创建。

 

    看看 public Connection getConnection()方法:

Java代码   收藏代码
  1. public Connection getConnection() throws SQLException {  
  2.     return popConnection(jdbcUsername, jdbcPassword).getProxyConnection();  
  3.   }  

 ibatis的连接池由2个数组分别存放空闲连接和非空闲连接:

Java代码   收藏代码
  1. private final Object POOL_LOCK = new Object();  
  2. private List idleConnections = new ArrayList();  
  3. private List activeConnections = new ArrayList();  

 

 ibatis的连接池实现大致解读为:

 

Java代码   收藏代码
  1. SimplePooledConnection conn = null;  
  2.   
  3.  while (conn == null) {  
  4.       synchronized (POOL_LOCK) {  
  5.         if (idleConnections.size() > 0) {  
  6.           // 有空闲连接,从池中取,这里因为用的ArrayList,效率有待提高,remove会触发数组的复制。  
  7.           conn = (SimplePooledConnection) idleConnections.remove(0);  
  8.         } else {  
  9.           // 无空闲连接且活动连接小于最大活动数,则创建新的连接池  
  10.           if (activeConnections.size() < poolMaximumActiveConnections) {  
  11.             // Can create new connection  
  12.             if (useDriverProps) {  
  13.               conn = new SimplePooledConnection(DriverManager.getConnection(jdbcUrl, driverProps), this);  
  14.             } else {  
  15.               conn = new SimplePooledConnection(DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword), this);  
  16.             }  
  17.           } else {  
  18.             // Cannot create new connection,当前活动连接数大于最大值,不能创建新连接。  
  19.             SimplePooledConnection oldestActiveConnection = (SimplePooledConnection) activeConnections.get(0);  
  20.             long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();  
  21.         // 尝试移除oldest活动连接,判断是否超时  
  22.             if (longestCheckoutTime > poolMaximumCheckoutTime) {  
  23.               // Can claim overdue connection  
  24.               ...  
  25.               if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {  
  26.                 oldestActiveConnection.getRealConnection().rollback();// 回滚  
  27.               }  
  28.               conn = new SimplePooledConnection(oldestActiveConnection.getRealConnection(), this);  
  29.               oldestActiveConnection.invalidate();// 当前连接已经超时却为活动状态,判为无效。  
  30.               } else {  
  31.               // Must wait 没有可用的连接池,最坏情况,会造成当先线程等待  
  32.               try {  
  33.                 if (!countedWait) {  
  34.                   hadToWaitCount++;  
  35.                   countedWait = true;  
  36.                 }  
  37.                long wt = System.currentTimeMillis();  
  38.                 POOL_LOCK.wait(poolTimeToWait);  
  39.                 accumulatedWaitTime += System.currentTimeMillis() - wt;  
  40.               } catch (InterruptedException e) {  
  41.                 break;  
  42.               }  
  43.             }  
  44.           }  
  45.         }  
  46.         
  47.         if (conn != null) {  
  48.       // 非新建立连接,从空闲队列中取的连接池,需要重置状态  
  49.           if (conn.isValid()) {  
  50.             if (!conn.getRealConnection().getAutoCommit()) {  
  51.               conn.getRealConnection().rollback();  
  52.             }  
  53.             conn.setConnectionTypeCode(assembleConnectionTypeCode(jdbcUrl, username, password));  
  54.             conn.setCheckoutTimestamp(System.currentTimeMillis());  
  55.             conn.setLastUsedTimestamp(System.currentTimeMillis());  
  56.             activeConnections.add(conn);  
  57.             requestCount++;  
  58.             accumulatedRequestTime += System.currentTimeMillis() - t;  
  59.           } else {  
  60.             badConnectionCount++;  
  61.             localBadConnectionCount++;  
  62.             conn = null;  
  63.             if (localBadConnectionCount > (poolMaximumIdleConnections + 3)) {// 当前活动连接超时成为“坏”连接,抛出程序异常。  
  64.              throw new SQLException("SimpleDataSource: Could not get a good connection to the database.");  
  65.             }  
  66.           }  
  67.         }  
  68.       }  
  69.   
  70.     }  

 

再看看pushConnection连接返回连接池操作,能看出ibatis池的一点异同。

Java代码   收藏代码
  1. private void pushConnection(SimplePooledConnection conn)  
  2.       throws SQLException {  
  3.     synchronized (POOL_LOCK) {  
  4.       activeConnections.remove(conn);// 从活动队列移除conn  
  5.       if (conn.isValid()) {  
  6.         if (idleConnections.size() < poolMaximumIdleConnections && conn.getConnectionTypeCode() == getExpectedConnectionTypeCode()) {  
  7.           accumulatedCheckoutTime += conn.getCheckoutTime();  
  8.           if (!conn.getRealConnection().getAutoCommit()) {  
  9.             conn.getRealConnection().rollback();  
  10.           }  
  11.           SimplePooledConnection newConn = new SimplePooledConnection(conn.getRealConnection(), this);// <span style="color: #ff0000;">精华,把移除的conn中的Connection重新赋值给新的SimplePooledConnection,而原来的SimplePooledConnection对象会销毁。  
  12. </span>          idleConnections.add(newConn);  
  13.           newConn.setCreatedTimestamp(conn.getCreatedTimestamp());  
  14.           newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp());  
  15.           conn.invalidate();  
  16.           POOL_LOCK.notifyAll();  
  17.         } else {  
  18.           accumulatedCheckoutTime += conn.getCheckoutTime();  
  19.           if (!conn.getRealConnection().getAutoCommit()) {  
  20.             conn.getRealConnection().rollback();  
  21.           }  
  22.           conn.getRealConnection().close();  
  23.           conn.invalidate();  
  24.         }  
  25.       } else {  
  26.        badConnectionCount++;  
  27.       }  
  28.     }  
  29.   }  

 

以上的精华就在:SimplePooledConnection newConn = new SimplePooledConnection(conn.getRealConnection(), this);//精华,把移除的conn中的Connection重新赋值给新的SimplePooledConnection,而原来的SimplePooledConnection对象会销毁。
         

对于对象池操作,如果要把老对象返回到池中,必定需要做清理工作,而ibatis的连接池在做返回池中并没有保留老对象,而是直接摒弃老对象,new一个新对象且载入老对象的Connection入到idleConnections队列中。

 

注意这里的remove()操作只是去除了引用,而非内存对象,GC暂时不会回收:)

推荐对于非容器管理连接池的话,用DBCP。

 

 

 事务(transaction)

 

    ibatis涉及到3类事务,分别为JDBC事务,JTA事务,可扩展事务。 

    说道事务一般会涉及到事务的接口、状态、配置、分布式事务等。ibatis提供的事务接口看上去很简单:

Java代码   收藏代码
  1. public interface Transaction {  
  2.   
  3.   public void commit() throws SQLException, TransactionException;  
  4.   public void rollback() throws SQLException, TransactionException;  
  5.   public void close() throws SQLException, TransactionException;  
  6.   
  7.   public Connection getConnection() throws SQLException, TransactionException;  
  8.   
  9. }  

 

    事务状态有:STATE_STARTED、STATE_COMMITTED、STATE_ENDED、STATE_USER_PROVIDED

    事务配置有:

Java代码   收藏代码
  1. public interface TransactionConfig {  
  2.   
  3.   public DataSource getDataSource();  
  4.   public void setDataSource(DataSource ds);  
  5.   
  6.   public void initialize(Properties props) throws SQLException, TransactionException;  
  7.   
  8.   public Transaction newTransaction(int transactionIsolation) throws SQLException, TransactionException;  
  9.   public int getMaximumConcurrentTransactions();  
  10.   public void setMaximumConcurrentTransactions(int maximumConcurrentTransactions);  
  11. }  

 

    JDBC事务

  

Java代码   收藏代码
  1. public class JdbcTransaction implements Transaction {  
  2.   
  3.   private static final Log connectionLog = LogFactory.getLog(Connection.class);  
  4.   
  5.   private DataSource dataSource;  
  6.   private Connection connection;  
  7.   private IsolationLevel isolationLevel = new IsolationLevel();  
  8.   
  9.   public JdbcTransaction(DataSource ds, int isolationLevel) throws TransactionException {  
  10.     // Check Parameters  
  11.     dataSource = ds;  
  12.     if (dataSource == null) {  
  13.       throw new TransactionException("JdbcTransaction initialization failed.  DataSource was null.");  
  14.     }  
  15.     this.isolationLevel.setIsolationLevel(isolationLevel);  
  16.   }  
  17.   
  18.   private void init() throws SQLException, TransactionException {  
  19.     // Open JDBC Transaction  
  20.     connection = dataSource.getConnection();  
  21.     if (connection == null) {  
  22.       throw new TransactionException("JdbcTransaction could not start transaction.  Cause: The DataSource returned a null connection.");  
  23.     }  
  24.     // Isolation Level  
  25.     isolationLevel.applyIsolationLevel(connection);  
  26.     // AutoCommit  
  27.     if (connection.getAutoCommit()) {  
  28.       connection.setAutoCommit(false);  
  29.     }  
  30.     // Debug  
  31.     if (connectionLog.isDebugEnabled()) {  
  32.       connection = ConnectionLogProxy.newInstance(connection);  
  33.     }  
  34.   }  
  35.   
  36.   public void commit() throws SQLException, TransactionException {  
  37.     if (connection != null) {  
  38.       connection.commit();  
  39.     }  
  40.   }  
  41.   
  42.   public void rollback() throws SQLException, TransactionException {  
  43.     if (connection != null) {  
  44.       connection.rollback();  
  45.     }  
  46.   }  
  47.   
  48.   public void close() throws SQLException, TransactionException {  
  49.     if (connection != null) {  
  50.       try {  
  51.         isolationLevel.restoreIsolationLevel(connection);  
  52.       } finally {  
  53.         connection.close();  
  54.         connection = null;  
  55.       }  
  56.     }  
  57.   }  
  58.   
  59.   public Connection getConnection() throws SQLException, TransactionException {  
  60.     if (connection == null) {  
  61.       init();  
  62.     }  
  63.     return connection;  
  64.   }  
  65.   
  66. }  

 

JTA事务(JTA事务一般由第三方实现,ibatis不关心实现)

 

Java代码   收藏代码
  1. public class JtaTransaction implements Transaction {  
  2.   
  3.   private static final Log connectionLog = LogFactory.getLog(Connection.class);  
  4.   
  5.   private UserTransaction userTransaction;  
  6.   private DataSource dataSource;  
  7.   private Connection connection;  
  8.   private IsolationLevel isolationLevel = new IsolationLevel();  
  9.   
  10.   private boolean commmitted = false;  
  11.   private boolean newTransaction = false;  
  12.   
  13.   public JtaTransaction(UserTransaction utx, DataSource ds, int isolationLevel) throws TransactionException {  
  14.     // Check parameters  
  15.     userTransaction = utx;  
  16.     dataSource = ds;  
  17.     if (userTransaction == null) {  
  18.       throw new TransactionException("JtaTransaction initialization failed.  UserTransaction was null.");  
  19.     }  
  20.     if (dataSource == null) {  
  21.       throw new TransactionException("JtaTransaction initialization failed.  DataSource was null.");  
  22.     }  
  23.     this.isolationLevel.setIsolationLevel(isolationLevel);  
  24.   }  
  25.   
  26.   private void init() throws TransactionException, SQLException {  
  27.     // Start JTA Transaction  
  28.     try {  
  29.       newTransaction = userTransaction.getStatus() == Status.STATUS_NO_TRANSACTION;  
  30.       if (newTransaction) {  
  31.         userTransaction.begin();  
  32.       }  
  33.     } catch (Exception e) {  
  34.       throw new TransactionException("JtaTransaction could not start transaction.  Cause: ", e);  
  35.     }  
  36.   
  37.     // Open JDBC Connection  
  38.     connection = dataSource.getConnection();  
  39.     if (connection == null) {  
  40.       throw new TransactionException("JtaTransaction could not start transaction.  Cause: The DataSource returned a null connection.");  
  41.     }  
  42.     // Isolation Level  
  43.     isolationLevel.applyIsolationLevel(connection);  
  44.     // AutoCommit  
  45.     if (connection.getAutoCommit()) {  
  46.       connection.setAutoCommit(false);  
  47.     }  
  48.     // Debug  
  49.     if (connectionLog.isDebugEnabled()) {  
  50.       connection = ConnectionLogProxy.newInstance(connection);  
  51.     }  
  52.   }  
  53.   
  54.   public void commit() throws SQLException, TransactionException {  
  55.     if (connection != null) {  
  56.       if (commmitted) {  
  57.         throw new TransactionException("JtaTransaction could not commit because this transaction has already been committed.");  
  58.       }  
  59.       try {  
  60.         if (newTransaction) {  
  61.           userTransaction.commit();  
  62.         }  
  63.       } catch (Exception e) {  
  64.         throw new TransactionException("JtaTransaction could not commit.  Cause: ", e);  
  65.       }  
  66.       commmitted = true;  
  67.     }  
  68.   }  
  69.   
  70.   public void rollback() throws SQLException, TransactionException {  
  71.     if (connection != null) {  
  72.       if (!commmitted) {  
  73.         try {  
  74.           if (userTransaction != null) {  
  75.             if (newTransaction) {  
  76.               userTransaction.rollback();  
  77.             } else {  
  78.               userTransaction.setRollbackOnly();  
  79.             }  
  80.           }  
  81.         } catch (Exception e) {  
  82.           throw new TransactionException("JtaTransaction could not rollback.  Cause: ", e);  
  83.         }  
  84.       }  
  85.     }  
  86.   }  
  87.   
  88.   public void close() throws SQLException, TransactionException {  
  89.     if (connection != null) {  
  90.       try {  
  91.         isolationLevel.restoreIsolationLevel(connection);  
  92.       } finally {  
  93.         connection.close();  
  94.         connection = null;  
  95.       }  
  96.     }  
  97.   }  
  98.   
  99.   public Connection getConnection() throws SQLException, TransactionException {  
  100.     if (connection == null) {  
  101.       init();  
  102.     }  
  103.     return connection;  
  104.   }  
  105.   
  106.   
  107. }  

  

自定义事务

 

Java代码   收藏代码
  1. public class ExternalTransaction implements Transaction {  
  2.   
  3.   private static final Log connectionLog = LogFactory.getLog(Connection.class);  
  4.   
  5.   private DataSource dataSource;  
  6.   private boolean defaultAutoCommit;  
  7.   private boolean setAutoCommitAllowed;  
  8.   private Connection connection;  
  9.   private IsolationLevel isolationLevel = new IsolationLevel();  
  10.   
  11.   public ExternalTransaction(DataSource ds, boolean defaultAutoCommit, boolean setAutoCommitAllowed, int isolationLevel) throws TransactionException {  
  12.     // Check Parameters  
  13.     dataSource = ds;  
  14.     if (dataSource == null) {  
  15.       throw new TransactionException("ExternalTransaction initialization failed.  DataSource was null.");  
  16.     }  
  17.   
  18.     this.defaultAutoCommit = defaultAutoCommit;  
  19.     this.setAutoCommitAllowed = setAutoCommitAllowed;  
  20.     this.isolationLevel.setIsolationLevel(isolationLevel);  
  21.   }  
  22.   
  23.   private void init() throws SQLException, TransactionException {  
  24.     // Open JDBC Transaction  
  25.     connection = dataSource.getConnection();  
  26.     if (connection == null) {  
  27.       throw new TransactionException("ExternalTransaction could not start transaction.  Cause: The DataSource returned a null connection.");  
  28.     }  
  29.     // Isolation Level  
  30.     isolationLevel.applyIsolationLevel(connection);  
  31.     // AutoCommit  
  32.     if (setAutoCommitAllowed) {  
  33.       if (connection.getAutoCommit() != defaultAutoCommit) {  
  34.         connection.setAutoCommit(defaultAutoCommit);  
  35.       }  
  36.     }  
  37.     // Debug  
  38.     if (connectionLog.isDebugEnabled()) {  
  39.       connection = ConnectionLogProxy.newInstance(connection);  
  40.     }  
  41.   }  
  42.   
  43.   public void commit() throws SQLException, TransactionException {  
  44.   }  
  45.   
  46.   public void rollback() throws SQLException, TransactionException {  
  47.   }  
  48.   
  49.   public void close() throws SQLException, TransactionException {  
  50.     if (connection != null) {  
  51.       try {  
  52.         isolationLevel.restoreIsolationLevel(connection);  
  53.       } finally {  
  54.         connection.close();  
  55.         connection = null;  
  56.       }  
  57.     }  
  58.   }  
  59.   
  60.   public Connection getConnection() throws SQLException, TransactionException {  
  61.     if (connection == null) {  
  62.       init();  
  63.     }  
  64.     return connection;  
  65.   }  
  66.   
  67. }  

  

可以看出TransactionConfig封装了Connection的细节部分,每个TransactionConfig实例绑定着一个Connection,这个Connection是从ds中获取到的。

 

有了配置文件,事务状态,隔离级别,事务异常,就开始使用了,TrasactionManger就是来调度所有这些上下文Config。其中有begin,commit,end主要的三个方法,其中begin是新建一个Config并植入session对象且定义当前session的事务状态,commit则提交当前session的事务,end显然就结束当前session事务。如下:

 

Java代码   收藏代码
  1. public class TransactionManager {  
  2.   
  3.   private TransactionConfig transactionConfig;  
  4.   
  5.   private boolean forceCommit;  
  6.   
  7.   private Throttle txThrottle;  
  8.   
  9.   public TransactionManager(TransactionConfig transactionConfig) {  
  10.     this.transactionConfig = transactionConfig;  
  11.     this.txThrottle = new Throttle(transactionConfig.getMaximumConcurrentTransactions());  
  12.   }  
  13.   
  14.   
  15.   public void begin(SessionScope session) throws SQLException, TransactionException {  
  16.     begin(session, IsolationLevel.UNSET_ISOLATION_LEVEL);  
  17.   }  
  18.   
  19.   public void begin(SessionScope session, int transactionIsolation) throws SQLException, TransactionException {  
  20.     Transaction trans = session.getTransaction();  
  21.     TransactionState state = session.getTransactionState();  
  22.     if (state == TransactionState.STATE_STARTED) {  
  23.       throw new TransactionException("TransactionManager could not start a new transaction.  " +  
  24.           "A transaction is already started.");  
  25.     } else if (state == TransactionState.STATE_USER_PROVIDED) {  
  26.       throw new TransactionException("TransactionManager could not start a new transaction.  " +  
  27.           "A user provided connection is currently being used by this session.  " +  
  28.           "The calling .setUserConnection (null) will clear the user provided transaction.");  
  29.     }  
  30.   
  31.     txThrottle.increment();  
  32.   
  33.     try {  
  34.       trans = transactionConfig.newTransaction(transactionIsolation);  
  35.       session.setCommitRequired(false);  
  36.     } catch (SQLException e) {  
  37.       txThrottle.decrement();  
  38.       throw e;  
  39.     } catch (TransactionException e) {  
  40.       txThrottle.decrement();  
  41.       throw e;  
  42.     }  
  43.   
  44.     session.setTransaction(trans);  
  45.     session.setTransactionState(TransactionState.STATE_STARTED);  
  46.   }  
  47.   
  48.   public void commit(SessionScope session) throws SQLException, TransactionException {  
  49.     Transaction trans = session.getTransaction();  
  50.     TransactionState state = session.getTransactionState();  
  51.     if (state == TransactionState.STATE_USER_PROVIDED) {  
  52.       throw new TransactionException("TransactionManager could not commit.  " +  
  53.           "A user provided connection is currently being used by this session.  " +  
  54.           "You must call the commit() method of the Connection directly.  " +  
  55.           "The calling .setUserConnection (null) will clear the user provided transaction.");  
  56.     } else if (state != TransactionState.STATE_STARTED && state != TransactionState.STATE_COMMITTED ) {  
  57.       throw new TransactionException("TransactionManager could not commit.  No transaction is started.");  
  58.     }  
  59.     if (session.isCommitRequired() || forceCommit) {  
  60.       trans.commit();  
  61.       session.setCommitRequired(false);  
  62.     }  
  63.     session.setTransactionState(TransactionState.STATE_COMMITTED);  
  64.   }  
  65.   
  66.   public void end(SessionScope session) throws SQLException, TransactionException {  
  67.     Transaction trans = session.getTransaction();  
  68.     TransactionState state = session.getTransactionState();  
  69.   
  70.     if (state == TransactionState.STATE_USER_PROVIDED) {  
  71.       throw new TransactionException("TransactionManager could not end this transaction.  " +  
  72.           "A user provided connection is currently being used by this session.  " +  
  73.           "You must call the rollback() method of the Connection directly.  " +  
  74.           "The calling .setUserConnection (null) will clear the user provided transaction.");  
  75.     }  
  76.   
  77.     try {  
  78.       if (trans != null) {  
  79.         try {  
  80.           if (state != TransactionState.STATE_COMMITTED) {  
  81.             if (session.isCommitRequired() || forceCommit) {  
  82.               trans.rollback();  
  83.               session.setCommitRequired(false);  
  84.             }  
  85.           }  
  86.         } finally {  
  87.           session.closePreparedStatements();  
  88.           trans.close();  
  89.         }  
  90.       }  
  91.     } finally {  
  92.   
  93.       if (state != TransactionState.STATE_ENDED) {  
  94.         txThrottle.decrement();  
  95.       }  
  96.   
  97.       session.setTransaction(null);  
  98.       session.setTransactionState(TransactionState.STATE_ENDED);  
  99.     }  
  100.   }  
  101.   
  102.   public DataSource getDataSource() {  
  103.     return transactionConfig.getDataSource();  
  104.   }  
  105.   
  106.   public void setDataSource(DataSource ds) {  
  107.     transactionConfig.setDataSource(ds);  
  108.   }  
  109.   
  110.   public boolean isForceCommit() {  
  111.     return forceCommit;  
  112.   }  
  113.   
  114.   public void setForceCommit(boolean forceCommit) {  
  115.     this.forceCommit = forceCommit;  
  116.   }  
  117.   
  118. }  

 

所以关于事务的上下文控制在ibatis的scope包里面了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值