package jef.database.innerpool;
import java.sql.SQLException;
import java.util.Collection;
import jef.common.Callback;
import org.easyframe.enterprise.spring.TransactionMode;
/**
* <strong>什么是IUserManagedPool</strong>
* <p>
* <pre>
* 支持可重入特性的连接池。在线程或者事务反复拿连接时范围同一个连接以节约使用,因此设计了这个接口,用于返回重复的连接。
* 目前DbClient中使用的还是IUserManagedPool。
* 该连接池没有按照J2EE规范使用DataSource PooledConnection等实现,但JEF-ORM可以选择不启用连接池。此时可以通过外部配置的方式用DataSource来实现一个第三方的连接池。详见下面的列表。
* </pre>
*
* 以下情况下,需要禁用嵌入式连接池,启用第三方连接池
* <li>1、希望使用使用了c3p0等外部连接池的</li>
* <li>2、使用了Oracle驱动内建的连接池,来实现类似于RAC FCF等自动切换功能的。</li>
* <li>3、使用了XA来实现分布式事务的,由于XA连接本身就是连接池,也需要禁用内嵌池</li>
* <br>
*
* 目前设计的实现
* <table BORDER CELLPADDING=3 CELLSPACING=1>
* <tr>
* <td></td>
* <td ALIGN=CENTER><em>Name</em></td>
* <td ALIGN=CENTER><em>Implementation</em></td>
* <td ALIGN=CENTER><em>Using</em></td>
* </tr>
* <tr>
* <td><b>A1</b></td>
* <td>内嵌单连接池</td>
* <td>{@link SingleManagedConnectionPool}</td>
* <td>没有外部连接池时,并且只有一个数据源</td>
* </tr>
* <tr>
* <td><b>A2</b></td>
* <td>外部单连接池</td>
* <td>{@link SingleDummyConnectionPool}</td>
* <td>使用外部连接池时,并且只有一个数据源</td>
* </tr>
* <tr>
* <td><b>B1</b></td>
* <td>内嵌多连接池</td>
* <td>{@link RoutingManagedConnectionPool}</td>
* <td>使用 {@link jef.database.datasource.RoutingDataSource} 来路由到多个数据源,并且未启用XA的场景</td>
* </tr>
* <tr>
* <td><b>B2</b></td>
* <td>外部多连接池</td>
* <td>{@link RoutingDummyConnectionPool}</td>
* <td>使用 {@link jef.database.datasource.RoutingDataSource} 来路由到多个数据源,并且这些数据源本身已经配置成连接池</td>
* </tr>
* <tr>
* <td><b>C</b></td>
* <td>外部XA连接池</td>
* <td>{@link RoutingDummyConnectionPool}</td>
* <td>当使用外部的XA时。此时每个XA数据源本身包含了连接池,因此JEF内嵌连接池不允许使用</td>
* </tr>
* </table>
* <ul>
* * 在多数据库支持的场合,IConnection已经包含了多数据库的支持。因此JEF上层只要关心IConnection的状态就可以操作多个数据库。
* <p>
* 针对内嵌连接池和第三方连接池,IConnection和其对应的ConnectionPool对象已经处理了这一关系。因此JEF上层也不用关心这个连接到底是新建的,还是从某个池里拿出来的。
*
*
* IConnection针对以下5种场景,可能有不同的实现。
* 1 .单数据库场景
* 具备重连特性的数据库连接
* 场景A1:使用内嵌连接池的JEF-ORM,具有连接管理,自动重连,线程复用等调度机制
*
* 场景A2:使用外部连接池。相应的重连等特性不再支持,一切连接池的维护管理功能由datasource的下层来管理
*
* 2 .在使用了Routing Datasource的场合下,用来封装事务用到的多个连接,使得它们能一起提交一起回滚(所谓多重JPA)
*
* 场景B1:使用内嵌连接池,配置了RoutingDatasource,一个DbClient。在事务中,每次操作需要getConnection,判断本次操作的连接关键字。
* 该操作数位于datasource之上的,如果沿用JEF-ORM内嵌连接池的API,也就意味着要为这种datasource设计专门的连接池。
* 这个连接池内部分为许多的小池子,同时每个事务要在多个小池子中占用一个连接。而这种连接池所返回的IConnection是一个复杂实现,类似与连接缓存,会记录当前事务所用到的多个连接,
* 如果事务要访问一个用过的数据库,那么返回缓存的连接,否则要将事务操作状态(dbKey)设计进API,来保证routingDatasource能路由出正确的次Connection对象。
*
* 延续B2的设计,IConnection内部包含若干小池。(其实我们可以将B2的场景中的也用dummy池实现,即将带池的DataSource统一用实现内部简单池接口)
*
* 场景B2:使用外部连接池
* 这种设计比上一种要简单。我们将多个数据源单独包装为连接池的datasourece,然后聚合为一个routingDatasource.内部处理的时候,直接将多个datasource记录到IConnection对象上。
* 事务对象得到IConnection,IConnection在被事务取用的时候,实际上并未为其分配任何一个连接。只有在事务用到一个连接的时候,IConnection得到这个连接,并缓存在其中。
* 当事务提交时,提交全部使用过的连接。(注意要只读事务优化是在Transaction上的,即Transaction不会调用只读事务的commit).
*
* 这个IConnection也必须要实现某个RoutingAPI,从而判断出当前应该提供的连接。(其实就是在每次create Statement时进行计算。有状态的)
*
* 3. 在底层使用了其他第三方连接池的时候,(包括XA)的时候,基于XA来实现JTA事务
* 场景C: 使用XA连接池,禁用内部连接池
*
*
* 这种场景下,事务操作全部禁用。由JTA控制器去操作。但是连接路由管理功能还是一样不变的。
* 因此我们参考实现是B2实现。除了事务不提交不回滚之外,其他和B2一样。(事务的提交回滚一切由Spring和JTA控制器完成.)
* @author jiyi
*/
public interface IUserManagedPool extends IPool<ReentrantConnection>,MetadataService{
/**
* 获取一个连接,如果连接池已经为指定的事务分配过连接,那么还是返回这个连接。
* 注意:这个版本开始,连接池不再负责设置AutoCommit的状态
*
* @param transaction 事务对象
* @return Connection
* @throws SQLException
*/
IConnection getConnection(Object transaction) throws SQLException;
/**
* 返回全部的datasource名称。
* 對於只支持但数据源的连接池实现,返回空集合即可
* @return
*/
Collection<String> getAllDatasourceNames();
/**
* 是否为路由池
* @return 如果是路由的连接池返回true,反之
*/
boolean isRouting();
/**
* 是否为假连接池
* @return 如果为非缓存的连接池实现,返回true,反之
*/
boolean isDummy();
/**
* 可以注册一个回调函数,当数据库在首次初始化的时候执行
* @param callback 回调函数
*/
void registeDbInitCallback(Callback<String, SQLException> callback);
/**
* 是否为多种异构数据库
* @return
*/
// boolean isMultipleRdbms();
IUserManagedPool setTransactionMode(TransactionMode txMode);
TransactionMode getTransactionMode();
}