package jef.database.innerpool;
import java.sql.SQLException;
import java.util.Iterator;
import javax.sql.DataSource;
import jef.common.log.LogUtil;
import jef.database.DbCfg;
import jef.database.datasource.DataSources;
import jef.database.datasource.IRoutingDataSource;
import jef.database.datasource.SimpleDataSource;
import jef.tools.JefConfiguration;
import jef.tools.StringUtils;
import org.easyframe.enterprise.spring.TransactionMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PoolService {
private static Logger log = LoggerFactory.getLogger(PoolService.class);
/**
* 获得一个可用的池
*
* @param ds
* @param profile
* @param max 当Max==0时等同于Nopool
* @return
*/
public static IUserManagedPool getPool(DataSource ds, int min,int max,TransactionMode txMode) {
String noPoolStr = JefConfiguration.get(DbCfg.DB_NO_POOL, "auto");
if(txMode==TransactionMode.JDBC || txMode==TransactionMode.JTA){
max=0;
}
boolean auto = "auto".equalsIgnoreCase(noPoolStr) && max>0;
boolean noPool = StringUtils.toBoolean(noPoolStr, false) || max==0 ;
if(min==0){
min = JefConfiguration.getInt(DbCfg.DB_CONNECTION_POOL, 3);
}
IUserManagedPool result;
if (ds instanceof IRoutingDataSource) {
IRoutingDataSource rds = (IRoutingDataSource) ds;
if (auto && !noPool) {
result= new RoutingManagedConnectionPool(rds, max, min, auto);
} else {
result= new RoutingDummyConnectionPool(rds);
}
} else {
if (auto) {
noPool = DataSources.isPool(ds);
if (noPool) {
log.info("There is Connection-Pool in datasource {}, EF-Inner Pool was disabled.", ds.getClass());
} else {
log.info("There is NO Connection-Pool detected in datasource {}, EF-Inner Pool was enabled.", ds.getClass());
}
}
if (noPool) {
result= new SingleDummyConnectionPool(ds);
} else {
result= new SingleManagedConnectionPool(ds, min, max);
}
}
return result.setTransactionMode(txMode);
}
public static DataSource getPooledDatasource(String url, String driverClass, String user, String password, int min, int max) {
SimpleDataSource ds = new SimpleDataSource();
ds.setUrl(url);
ds.setDriverClass(driverClass);
ds.setUser(user);
ds.setPassword(password);
return new SingleManagedConnectionPool(ds, min, max);
}
/**
* 正常情況下,關閉時兩者應該相等
*
* @param pollCount
* @param offerCount
*/
static void logPoolStatic(String name, long pollCount, long offerCount) {
log.info("The connection {} poll-count:{} offer-count:{}", name, pollCount, offerCount);
}
// synchronized (pool) {
// LogUtil.info("Checked [{}]. total:{}, invalid:{}", pool, total, invalid);
//}
/**
* 描述连接可被检查的行为特性
* @author jiyi
*
*/
static interface CheckableConnection{
/**
* 标记当前连接失效,在业务发生错误时,或者在检查线程检查出问题时,都可能使用此方法来标记连接失效。
*/
public void setInvalid();
/**
* 执行检查
* @param 测试用SQL
* @return true表示连接正常,false或者抛出异常表示连接不可用
*/
public boolean checkValid(String testSql)throws SQLException;
/**
* 执行检查,原先是isValid方法,但是该方法与JDBC4同名方法一致,如果一个类同时实现了两个接口。javac在编译时会出现委派不确定错误,因此更名为checkValid
* @param timeout
* @return true表示连接正常,false或者抛出异常表示连接不可用
*/
public boolean checkValid(int timeout)throws SQLException;
/**
* 是否被占用
* @return
*/
boolean isUsed();
}
/**
* 立刻检查
*
* @param pool
* @return 无效的连接数. -1表示连接池无法进行检测
*/
public static int doCheck(String testSql,Iterator<? extends CheckableConnection> connectionsToCheck) {
int invalid = 0;
boolean useJDbcValidation = false;
if (StringUtils.isBlank(testSql) || "jdbc4".equals(testSql)) {
useJDbcValidation = true;
}else if("false".equalsIgnoreCase(testSql) || "disable".equalsIgnoreCase(testSql)){
return 0;
}
for (;connectionsToCheck.hasNext();) {
CheckableConnection conn = connectionsToCheck.next();
if (conn.isUsed()) {// 仅对空闲连接进行检查
continue;
}
boolean flag = false;
try {
if (useJDbcValidation) {
try{
flag = conn.checkValid(5);
}catch(AbstractMethodError e){ //JDBC未实现此方法
//LogUtil.exception(e);无需输入堆栈
LogUtil.warn("The Connection Check was disabled since the JDBC Driver doesn't support 'isValid(I)Z'"+conn.toString());
return -1;
}
} else {
flag = conn.checkValid(testSql);
}
} catch (SQLException e) {
LogUtil.exception(e);
}
if (!flag) {
conn.setInvalid();
invalid++;
}
}
return invalid;
}
}