`
C_J
  • 浏览: 128127 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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

阅读更多

题记:

    人越来越懒了,最近看代码的速度越来越慢了,加速。

数据源(datasource包&jdbc包)

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

 

SimpleDataSourceFactory

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

 

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

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

 

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

  // Required Properties
  private static final String PROP_JDBC_DRIVER = "JDBC.Driver";
  private static final String PROP_JDBC_URL = "JDBC.ConnectionURL";
  private static final String PROP_JDBC_USERNAME = "JDBC.Username";
  private static final String PROP_JDBC_PASSWORD = "JDBC.Password";
  private static final String PROP_JDBC_DEFAULT_AUTOCOMMIT = "JDBC.DefaultAutoCommit";

  // Optional Properties
  private static final String PROP_POOL_MAX_ACTIVE_CONN = "Pool.MaximumActiveConnections";
  private static final String PROP_POOL_MAX_IDLE_CONN = "Pool.MaximumIdleConnections";
 ....

典型的数据源配置如下:

<transactionManager type="JDBC">
	<dataSource type="DBCP">
	<property name="JDBC.Driver" value="${driver}"/>
	<property name="JDBC.ConnectionURL" value="${url}"/>
	<property name="JDBC.Username" value="${username}"/>
	<property name="JDBC.Password" value="${password}"/>
	<property name="Pool.MaximumActiveConnections" value="8"/>
	<property name="Pool.MaximumIdleConnections" value="8"/>
	....	
	</dataSource>
</transactionManager>

 

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

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

 

JndiDataSourceFactory

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

 public void initialize(Map properties) {
    try {
      InitialContext initCtx = null;
      Hashtable context = getContextProperties(properties);

      if (context == null) {
        initCtx = new InitialContext();
      } else {
        initCtx = new InitialContext(context);
      }

      if (properties.containsKey("DataSource")) {
        dataSource = (DataSource) initCtx.lookup((String) properties.get("DataSource"));
      } else if (properties.containsKey("DBJndiContext")) { // LEGACY --Backward compatibility        
        dataSource = (DataSource) initCtx.lookup((String) properties.get("DBJndiContext"));
      } else if (properties.containsKey("DBFullJndiContext")) { // LEGACY --Backward compatibility
        dataSource = (DataSource) initCtx.lookup((String) properties.get("DBFullJndiContext"));
      } else if (properties.containsKey("DBInitialContext")
          && properties.containsKey("DBLookup")) { // LEGACY --Backward compatibility
        Context ctx = (Context) initCtx.lookup((String) properties.get("DBInitialContext"));
        dataSource = (DataSource) ctx.lookup((String) properties.get("DBLookup"));
      }

    } catch (NamingException e) {
      throw new SqlMapException("There was an error configuring JndiDataSourceTransactionPool. Cause: " + e, e);
    }
  }

 

DbcpDataSourceFactory

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

public class DbcpDataSourceFactory implements DataSourceFactory {

  private DataSource dataSource;

  public void initialize(Map map) {
    DbcpConfiguration dbcp = new DbcpConfiguration(map);
    dataSource = dbcp.getDataSource();
  }
}

 

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

 BasicDataSource basicDataSource = null;
    if (map.containsKey("JDBC.Driver")) {
      basicDataSource = new BasicDataSource();
      String driver = (String) map.get("JDBC.Driver");
      String url = (String) map.get("JDBC.ConnectionURL");
      String username = (String) map.get("JDBC.Username");
    ... 

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

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

 

private BasicDataSource newDbcpConfiguration(Map map) {
    BasicDataSource basicDataSource = new BasicDataSource();
    Iterator props = map.keySet().iterator();
    while (props.hasNext()) {
      String propertyName = (String) props.next();
      if (PROBE.hasWritableProperty(basicDataSource, propertyName))//判断basticDataSource对象有没有propertyName属性 {
        String value = (String) map.get(propertyName);
        Object convertedValue = convertValue(basicDataSource, propertyName, value);// 将value类型转换成basicDataSource对象propertyName变量的类型
        PROBE.setObject(basicDataSource, propertyName, convertedValue);
      }
    }
    return basicDataSource;
  }

  private Object convertValue(Object object, String propertyName, String value) {
    Object convertedValue = value;
    Class targetType = PROBE.getPropertyTypeForSetter(object, propertyName);// 获取object对象propertyName变量的类型
    if (targetType == Integer.class || targetType == int.class) {
      convertedValue = Integer.valueOf(value);
    } else if (targetType == Long.class || targetType == long.class) {
      convertedValue = Long.valueOf(value);
    } else if (targetType == Boolean.class || targetType == boolean.class) {
      convertedValue = Boolean.valueOf(value);
    }
    return convertedValue;
  }

 

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

 

 

连接池(SimpleDataSource)

 

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

 

    看看 public Connection getConnection()方法:

public Connection getConnection() throws SQLException {
    return popConnection(jdbcUsername, jdbcPassword).getProxyConnection();
  }

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

  private final Object POOL_LOCK = new Object();
  private List idleConnections = new ArrayList();
  private List activeConnections = new ArrayList();

 

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

 

SimplePooledConnection conn = null;

 while (conn == null) {
      synchronized (POOL_LOCK) {
        if (idleConnections.size() > 0) {
          // 有空闲连接,从池中取,这里因为用的ArrayList,效率有待提高,remove会触发数组的复制。
          conn = (SimplePooledConnection) idleConnections.remove(0);
        } else {
          // 无空闲连接且活动连接小于最大活动数,则创建新的连接池
          if (activeConnections.size() < poolMaximumActiveConnections) {
            // Can create new connection
            if (useDriverProps) {
              conn = new SimplePooledConnection(DriverManager.getConnection(jdbcUrl, driverProps), this);
            } else {
              conn = new SimplePooledConnection(DriverManager.getConnection(jdbcUrl, jdbcUsername, jdbcPassword), this);
            }
          } else {
            // Cannot create new connection,当前活动连接数大于最大值,不能创建新连接。
            SimplePooledConnection oldestActiveConnection = (SimplePooledConnection) activeConnections.get(0);
            long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();
        // 尝试移除oldest活动连接,判断是否超时
            if (longestCheckoutTime > poolMaximumCheckoutTime) {
              // Can claim overdue connection
              ...
              if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {
                oldestActiveConnection.getRealConnection().rollback();// 回滚
              }
              conn = new SimplePooledConnection(oldestActiveConnection.getRealConnection(), this);
              oldestActiveConnection.invalidate();// 当前连接已经超时却为活动状态,判为无效。
              } else {
              // Must wait 没有可用的连接池,最坏情况,会造成当先线程等待
              try {
                if (!countedWait) {
                  hadToWaitCount++;
                  countedWait = true;
                }
               long wt = System.currentTimeMillis();
                POOL_LOCK.wait(poolTimeToWait);
                accumulatedWaitTime += System.currentTimeMillis() - wt;
              } catch (InterruptedException e) {
                break;
              }
            }
          }
        }
      
        if (conn != null) {
      // 非新建立连接,从空闲队列中取的连接池,需要重置状态
          if (conn.isValid()) {
            if (!conn.getRealConnection().getAutoCommit()) {
              conn.getRealConnection().rollback();
            }
            conn.setConnectionTypeCode(assembleConnectionTypeCode(jdbcUrl, username, password));
            conn.setCheckoutTimestamp(System.currentTimeMillis());
            conn.setLastUsedTimestamp(System.currentTimeMillis());
            activeConnections.add(conn);
            requestCount++;
            accumulatedRequestTime += System.currentTimeMillis() - t;
          } else {
            badConnectionCount++;
            localBadConnectionCount++;
            conn = null;
            if (localBadConnectionCount > (poolMaximumIdleConnections + 3)) {// 当前活动连接超时成为“坏”连接,抛出程序异常。
             throw new SQLException("SimpleDataSource: Could not get a good connection to the database.");
            }
          }
        }
      }

    }

 

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

private void pushConnection(SimplePooledConnection conn)
      throws SQLException {
    synchronized (POOL_LOCK) {
      activeConnections.remove(conn);// 从活动队列移除conn
      if (conn.isValid()) {
        if (idleConnections.size() < poolMaximumIdleConnections && conn.getConnectionTypeCode() == getExpectedConnectionTypeCode()) {
          accumulatedCheckoutTime += conn.getCheckoutTime();
          if (!conn.getRealConnection().getAutoCommit()) {
            conn.getRealConnection().rollback();
          }
          SimplePooledConnection newConn = new SimplePooledConnection(conn.getRealConnection(), this);// 精华,把移除的conn中的Connection重新赋值给新的SimplePooledConnection,而原来的SimplePooledConnection对象会销毁。
          idleConnections.add(newConn);
          newConn.setCreatedTimestamp(conn.getCreatedTimestamp());
          newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp());
          conn.invalidate();
          POOL_LOCK.notifyAll();
        } else {
          accumulatedCheckoutTime += conn.getCheckoutTime();
          if (!conn.getRealConnection().getAutoCommit()) {
            conn.getRealConnection().rollback();
          }
          conn.getRealConnection().close();
          conn.invalidate();
        }
      } else {
       badConnectionCount++;
      }
    }
  }

 

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

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

 

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

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

 

 

 事务(transaction)

 

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

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

public interface Transaction {

  public void commit() throws SQLException, TransactionException;
  public void rollback() throws SQLException, TransactionException;
  public void close() throws SQLException, TransactionException;

  public Connection getConnection() throws SQLException, TransactionException;

}

 

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

    事务配置有:

public interface TransactionConfig {

  public DataSource getDataSource();
  public void setDataSource(DataSource ds);

  public void initialize(Properties props) throws SQLException, TransactionException;

  public Transaction newTransaction(int transactionIsolation) throws SQLException, TransactionException;
  public int getMaximumConcurrentTransactions();
  public void setMaximumConcurrentTransactions(int maximumConcurrentTransactions);
}

 

    JDBC事务

  

public class JdbcTransaction implements Transaction {

  private static final Log connectionLog = LogFactory.getLog(Connection.class);

  private DataSource dataSource;
  private Connection connection;
  private IsolationLevel isolationLevel = new IsolationLevel();

  public JdbcTransaction(DataSource ds, int isolationLevel) throws TransactionException {
    // Check Parameters
    dataSource = ds;
    if (dataSource == null) {
      throw new TransactionException("JdbcTransaction initialization failed.  DataSource was null.");
    }
    this.isolationLevel.setIsolationLevel(isolationLevel);
  }

  private void init() throws SQLException, TransactionException {
    // Open JDBC Transaction
    connection = dataSource.getConnection();
    if (connection == null) {
      throw new TransactionException("JdbcTransaction could not start transaction.  Cause: The DataSource returned a null connection.");
    }
    // Isolation Level
    isolationLevel.applyIsolationLevel(connection);
    // AutoCommit
    if (connection.getAutoCommit()) {
      connection.setAutoCommit(false);
    }
    // Debug
    if (connectionLog.isDebugEnabled()) {
      connection = ConnectionLogProxy.newInstance(connection);
    }
  }

  public void commit() throws SQLException, TransactionException {
    if (connection != null) {
      connection.commit();
    }
  }

  public void rollback() throws SQLException, TransactionException {
    if (connection != null) {
      connection.rollback();
    }
  }

  public void close() throws SQLException, TransactionException {
    if (connection != null) {
      try {
        isolationLevel.restoreIsolationLevel(connection);
      } finally {
        connection.close();
        connection = null;
      }
    }
  }

  public Connection getConnection() throws SQLException, TransactionException {
    if (connection == null) {
      init();
    }
    return connection;
  }

}

 

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

 

public class JtaTransaction implements Transaction {

  private static final Log connectionLog = LogFactory.getLog(Connection.class);

  private UserTransaction userTransaction;
  private DataSource dataSource;
  private Connection connection;
  private IsolationLevel isolationLevel = new IsolationLevel();

  private boolean commmitted = false;
  private boolean newTransaction = false;

  public JtaTransaction(UserTransaction utx, DataSource ds, int isolationLevel) throws TransactionException {
    // Check parameters
    userTransaction = utx;
    dataSource = ds;
    if (userTransaction == null) {
      throw new TransactionException("JtaTransaction initialization failed.  UserTransaction was null.");
    }
    if (dataSource == null) {
      throw new TransactionException("JtaTransaction initialization failed.  DataSource was null.");
    }
    this.isolationLevel.setIsolationLevel(isolationLevel);
  }

  private void init() throws TransactionException, SQLException {
    // Start JTA Transaction
    try {
      newTransaction = userTransaction.getStatus() == Status.STATUS_NO_TRANSACTION;
      if (newTransaction) {
        userTransaction.begin();
      }
    } catch (Exception e) {
      throw new TransactionException("JtaTransaction could not start transaction.  Cause: ", e);
    }

    // Open JDBC Connection
    connection = dataSource.getConnection();
    if (connection == null) {
      throw new TransactionException("JtaTransaction could not start transaction.  Cause: The DataSource returned a null connection.");
    }
    // Isolation Level
    isolationLevel.applyIsolationLevel(connection);
    // AutoCommit
    if (connection.getAutoCommit()) {
      connection.setAutoCommit(false);
    }
    // Debug
    if (connectionLog.isDebugEnabled()) {
      connection = ConnectionLogProxy.newInstance(connection);
    }
  }

  public void commit() throws SQLException, TransactionException {
    if (connection != null) {
      if (commmitted) {
        throw new TransactionException("JtaTransaction could not commit because this transaction has already been committed.");
      }
      try {
        if (newTransaction) {
          userTransaction.commit();
        }
      } catch (Exception e) {
        throw new TransactionException("JtaTransaction could not commit.  Cause: ", e);
      }
      commmitted = true;
    }
  }

  public void rollback() throws SQLException, TransactionException {
    if (connection != null) {
      if (!commmitted) {
        try {
          if (userTransaction != null) {
            if (newTransaction) {
              userTransaction.rollback();
            } else {
              userTransaction.setRollbackOnly();
            }
          }
        } catch (Exception e) {
          throw new TransactionException("JtaTransaction could not rollback.  Cause: ", e);
        }
      }
    }
  }

  public void close() throws SQLException, TransactionException {
    if (connection != null) {
      try {
        isolationLevel.restoreIsolationLevel(connection);
      } finally {
        connection.close();
        connection = null;
      }
    }
  }

  public Connection getConnection() throws SQLException, TransactionException {
    if (connection == null) {
      init();
    }
    return connection;
  }


}

  

自定义事务

 

public class ExternalTransaction implements Transaction {

  private static final Log connectionLog = LogFactory.getLog(Connection.class);

  private DataSource dataSource;
  private boolean defaultAutoCommit;
  private boolean setAutoCommitAllowed;
  private Connection connection;
  private IsolationLevel isolationLevel = new IsolationLevel();

  public ExternalTransaction(DataSource ds, boolean defaultAutoCommit, boolean setAutoCommitAllowed, int isolationLevel) throws TransactionException {
    // Check Parameters
    dataSource = ds;
    if (dataSource == null) {
      throw new TransactionException("ExternalTransaction initialization failed.  DataSource was null.");
    }

    this.defaultAutoCommit = defaultAutoCommit;
    this.setAutoCommitAllowed = setAutoCommitAllowed;
    this.isolationLevel.setIsolationLevel(isolationLevel);
  }

  private void init() throws SQLException, TransactionException {
    // Open JDBC Transaction
    connection = dataSource.getConnection();
    if (connection == null) {
      throw new TransactionException("ExternalTransaction could not start transaction.  Cause: The DataSource returned a null connection.");
    }
    // Isolation Level
    isolationLevel.applyIsolationLevel(connection);
    // AutoCommit
    if (setAutoCommitAllowed) {
      if (connection.getAutoCommit() != defaultAutoCommit) {
        connection.setAutoCommit(defaultAutoCommit);
      }
    }
    // Debug
    if (connectionLog.isDebugEnabled()) {
      connection = ConnectionLogProxy.newInstance(connection);
    }
  }

  public void commit() throws SQLException, TransactionException {
  }

  public void rollback() throws SQLException, TransactionException {
  }

  public void close() throws SQLException, TransactionException {
    if (connection != null) {
      try {
        isolationLevel.restoreIsolationLevel(connection);
      } finally {
        connection.close();
        connection = null;
      }
    }
  }

  public Connection getConnection() throws SQLException, TransactionException {
    if (connection == null) {
      init();
    }
    return connection;
  }

}

  

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

 

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

 

public class TransactionManager {

  private TransactionConfig transactionConfig;

  private boolean forceCommit;

  private Throttle txThrottle;

  public TransactionManager(TransactionConfig transactionConfig) {
    this.transactionConfig = transactionConfig;
    this.txThrottle = new Throttle(transactionConfig.getMaximumConcurrentTransactions());
  }


  public void begin(SessionScope session) throws SQLException, TransactionException {
    begin(session, IsolationLevel.UNSET_ISOLATION_LEVEL);
  }

  public void begin(SessionScope session, int transactionIsolation) throws SQLException, TransactionException {
    Transaction trans = session.getTransaction();
    TransactionState state = session.getTransactionState();
    if (state == TransactionState.STATE_STARTED) {
      throw new TransactionException("TransactionManager could not start a new transaction.  " +
          "A transaction is already started.");
    } else if (state == TransactionState.STATE_USER_PROVIDED) {
      throw new TransactionException("TransactionManager could not start a new transaction.  " +
          "A user provided connection is currently being used by this session.  " +
          "The calling .setUserConnection (null) will clear the user provided transaction.");
    }

    txThrottle.increment();

    try {
      trans = transactionConfig.newTransaction(transactionIsolation);
      session.setCommitRequired(false);
    } catch (SQLException e) {
      txThrottle.decrement();
      throw e;
    } catch (TransactionException e) {
      txThrottle.decrement();
      throw e;
    }

    session.setTransaction(trans);
    session.setTransactionState(TransactionState.STATE_STARTED);
  }

  public void commit(SessionScope session) throws SQLException, TransactionException {
    Transaction trans = session.getTransaction();
    TransactionState state = session.getTransactionState();
    if (state == TransactionState.STATE_USER_PROVIDED) {
      throw new TransactionException("TransactionManager could not commit.  " +
          "A user provided connection is currently being used by this session.  " +
          "You must call the commit() method of the Connection directly.  " +
          "The calling .setUserConnection (null) will clear the user provided transaction.");
    } else if (state != TransactionState.STATE_STARTED && state != TransactionState.STATE_COMMITTED ) {
      throw new TransactionException("TransactionManager could not commit.  No transaction is started.");
    }
    if (session.isCommitRequired() || forceCommit) {
      trans.commit();
      session.setCommitRequired(false);
    }
    session.setTransactionState(TransactionState.STATE_COMMITTED);
  }

  public void end(SessionScope session) throws SQLException, TransactionException {
    Transaction trans = session.getTransaction();
    TransactionState state = session.getTransactionState();

    if (state == TransactionState.STATE_USER_PROVIDED) {
      throw new TransactionException("TransactionManager could not end this transaction.  " +
          "A user provided connection is currently being used by this session.  " +
          "You must call the rollback() method of the Connection directly.  " +
          "The calling .setUserConnection (null) will clear the user provided transaction.");
    }

    try {
      if (trans != null) {
        try {
          if (state != TransactionState.STATE_COMMITTED) {
            if (session.isCommitRequired() || forceCommit) {
              trans.rollback();
              session.setCommitRequired(false);
            }
          }
        } finally {
          session.closePreparedStatements();
          trans.close();
        }
      }
    } finally {

      if (state != TransactionState.STATE_ENDED) {
        txThrottle.decrement();
      }

      session.setTransaction(null);
      session.setTransactionState(TransactionState.STATE_ENDED);
    }
  }

  public DataSource getDataSource() {
    return transactionConfig.getDataSource();
  }

  public void setDataSource(DataSource ds) {
    transactionConfig.setDataSource(ds);
  }

  public boolean isForceCommit() {
    return forceCommit;
  }

  public void setForceCommit(boolean forceCommit) {
    this.forceCommit = forceCommit;
  }

}

 

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

分享到:
评论
7 楼 C_J 2010-07-16  
回楼上:

简单工厂,虽然取名叫Factory,但我也感觉有点怪,这里的数据源为后面的事务模块服务,所以现在还未能完全解答你的疑问。


………………………………………………………………

嗯,ibatis2.3好像还是有很多BUG和有待优化的地方,像连接池的用的ArrayList,像delete from xxx where 1=1的问题等,但不知道3.0版本如何。
6 楼 liujun999999 2010-07-16  
2.3有一个问题,不知道楼主发现没有,调用 sybase的存储过程,如果返回多个结果集,那么在存储过程的2个select之间,不能出现set语句,如果出现set,后面的结果集就出不来了
5 楼 shangtang004 2010-07-16  
您在《RE:ibatis2.3源码之数据源&连接池浅析(待续)》的回贴,内容为:

引用
我也想学习,晚上回去研究下你的成果!

被JavaEye用户投票评为差帖,积分-30分。
这有可能是因为你的回贴是灌水性回贴,JavaEye严禁灌水性回贴,您在发贴前请仔细阅读 JavaEye版规和提问的智慧,如有异议,可以在JavaEye站务讨论圈子申诉。

唉,早上做了十多分钟的测试,才能回复
我晚上真回去认真看了你的内容的,

上面的那个SimpleDataSourceFactory是属于简单工厂,还是抽象工厂?这种工厂,我看不出比直接new SimpldeDataSource好哟?
4 楼 C_J 2010-07-15  
<div class="quote_title">gogole_09 写道</div>
<div class="quote_div">
<div class="quote_title">C_J 写道</div>
<div class="quote_div">
<p><span style="color: #ff0000;">疑问:这句activeConnections.remove(conn);是否存在一定的风险?,ArrayList的remove操作为:</span></p>
<p><span style="color: #ff0000;">elementData[--size] = null; // Let gc do its work </span></p>
<p><span style="color: #ff0000;">而实际上这个conn对象还需要被下面用到,如果GC恰好回收对象,是否会出现NULLPointerException异常呢?</span></p>
</div>
<p> </p>
<p>  不会引发NullPointerException ,因为GC回收的是数组持有的过期引用,而并非是回收conn对象。  </p>
<p> 这种方式在&lt;Effective Java&gt;第一版(第2章 第5条)中是被推荐的.</p>
</div>
<p><br>嗯,多谢提醒,这里并非回收了conn对象,只是少个引用,疏忽了。</p>
<p> ………………………………………………cutline</p>
<p> </p>
<p>回楼上,你要实现JDBC接口吗?</p>
<p> </p>
3 楼 shangtang004 2010-07-15  
我刚写了个小程序,一个数据库连接,顺序打开了N个statement,有查,有添加,有删。

有没有能写出监控驱动程序和数据库服务器交互的程序,这要知道驱动程序和服务器交互的协议,我想写个这个程序,看看到底事务怎么做,批量怎么做。手动提交,自动提交怎么做。可无从下手哟。
2 楼 shangtang004 2010-07-15  
我也想学习,晚上回去研究下你的成果!
1 楼 gogole_09 2010-07-15  
<div class="quote_title">C_J 写道</div>
<div class="quote_div">
<p><span style="color: #ff0000;">疑问:这句activeConnections.remove(conn);是否存在一定的风险?,ArrayList的remove操作为:</span></p>
<p><span style="color: #ff0000;">elementData[--size] = null; // Let gc do its work </span></p>
<p><span style="color: #ff0000;">而实际上这个conn对象还需要被下面用到,如果GC恰好回收对象,是否会出现NULLPointerException异常呢?</span></p>
</div>
<p> </p>
<p>  不会引发NullPointerException ,因为GC回收的是数组持有的过期引用,而并非是回收conn对象。  </p>
<p> 这种方式在&lt;Effective Java&gt;第一版(第2章 第5条)中是被推荐的.</p>

相关推荐

    ibatis2.3-src

    《深入解析iBatis 2.3源码》 iBatis,作为一款经典的Java持久层框架,以其轻量级、灵活的特性深受开发者喜爱。本文将深入剖析iBatis 2.3的源码,帮助读者理解其内部机制,提升开发与优化数据库访问的能力。 1. **...

    ibatis2.3源码

    【标题】"ibatis2.3源码"指的是开源的SQL映射框架iBATIS的2.3版本的源代码。iBATIS是Java平台上的一种轻量级持久层框架,它将SQL语句与Java代码分离,使得开发者可以更加灵活地处理数据库操作。 【描述】中的"可以...

    ibatis2.3例子代码

    XML配置文件通常包含数据库连接信息,如数据源配置、事务管理等。SQL映射文件则包含了具体的SQL语句和结果映射,它是iBatis与数据库交互的关键。SqlSession是iBatis的主要工作接口,用于执行SQL语句和管理事务。...

    ibatis2.3.4.726增删改查源码实例

    总的来说,这个"Ibatis2.3.4.726增删改查源码实例"为你提供了一个完整的Ibatis应用示例,你可以通过阅读源代码学习如何配置Ibatis,如何编写Mapper接口和XML文件,以及如何在Java代码中调用Ibatis进行数据库操作。...

    ibatis2.3 jar包

    - **配置环境**:在项目中引入Ibatis 2.3的jar包,并在配置文件中指定数据源、事务管理器和SqlSessionFactory。 - **编写SQL映射文件**:在resource目录下创建XML文件,定义SQL语句、参数映射和结果集映射。 - **...

    ibatis2.3.4.8.jar 和 ibatis-2.3.4.726.jar两个版本的下载

    2. 配置Ibatis的主配置文件(mybatis-config.xml),设置数据源、事务管理器等核心参数。 3. 创建SQL映射文件,编写SQL语句,并定义结果映射。 4. 在Java代码中创建SqlSessionFactory,然后通过SqlSessionFactory...

    struts2_spring2.5_ibatis2.3_mysql架构

    *架构struts2_spring2.5_ibatis2.3 *mysql5.0 *jdk 1.6 *带有所有jar包,可直接运行 本实例实现了用户登陆,用户信息CRUD相关操作。让你感受到了ibatis做o/r mapping的方便快捷。 下次集成dwr进来 create ...

    ibatis2.3 jar (ibatis pdf 教程)

    通过阅读这个PDF教程和实际操作Ibatis-2.3.4.726.jar,开发者可以深入理解Ibatis的工作原理,并能熟练地在项目中运用Ibatis进行数据访问。无论你是Java新手还是经验丰富的开发者,掌握Ibatis都能提升你的开发效率,...

    spring3.0.3+ibatis2.3.4.7分页

    1. **配置**:在Spring配置文件中,定义数据源、事务管理器和iBATIS的SqlSessionFactory。还需要将DAO接口与XML配置文件关联,指定SQL语句和结果映射。 2. **分页参数**:在服务层,创建一个包含分页参数的对象,如...

    ibatis2.3.chm

    ibatis2.3 api,chm 格式,方面快速查询ibatis 的相关接口

    iBATIS2.3-JavaDoc.rar

    通过深入学习iBATIS 2.3的JavaDoc,开发者可以了解每个类、接口和方法的作用,更好地利用这个框架来构建高效、可维护的数据访问层。例如,`SqlMapConfig.xml`配置文件的解析、`SqlMapClientBuilder`的使用、`...

    ibatis-2.3.0.677.zip

    8. 数据源:iBATIS允许开发者配置多种数据源,如单数据库、多数据库或分布式数据库,以适应不同规模和复杂性的应用需求。 在实际使用iBATIS时,开发者通常需要完成以下步骤: 1. 创建SQL Maps XML文件,定义SQL语句...

    iBATIS-DAO-2.3.4.726.rar_com.ibatis.dao_iBATIS dao 2_iBatis DAO_

    在这个2.3.4.726版本的源码中,我们可以深入理解iBATIS DAO的工作原理,并通过添加注释来帮助我们更好地掌握其实现细节。 首先,iBATIS DAO的核心概念是SQL Maps,它们定义了数据库操作的SQL语句,并将其映射到Java...

    ibatis-2.3

    例如,`ibatis-2.3.0`中的`SqlMapConfig.xml`是整个Ibatis系统的配置中心,它包含了数据源、事务管理器、Mappers等信息。 在Ibatis中,SQL的执行通过Statement进行,Statement分为两种类型:PreparedStatement...

    ibatis2.3.4.726.jar

    ibatis2.3.4.726.jar ibatis2.3.4.726.jar ibatis2.3.4.726.jar ibatis2.3.4.726.jar

    ibatis-2.3.4.726-src-源代码

    《深入解析iBatis 2.3.4.726源码》 iBatis,作为一款轻量级的Java持久层框架,以其灵活、高效的特点,在许多项目中得到了广泛应用。本文将针对iBatis 2.3.4.726版本的源代码进行详尽解读,帮助开发者深入了解其内部...

    ibatis2.3 API.CHM

    ibatis2.3 API CHM 帮助文档 ibatis 开发人员必备

    ibatis2.3.4.8.jar 下载

    提供ibatis2.3.4.8.jar包下载.

Global site tag (gtag.js) - Google Analytics