- 浏览: 106778 次
- 性别:
- 来自: 北京
文章分类
最新评论
jndi+rmi+proxool应用负载下的远程数据源2
问题的由来和分析,请看http://mazhen2010.iteye.com/blog/654366
远程数据源应用于正式环境有一段时间了。期间未收到bug提交。
查看了从6月2日-6月12日的日志,发现两种error错误。经调查这两种错误都是由于业务逻辑错误造成的,和数据源无关。(意外收获,还能检查逻辑漏洞)
学习了微软的was性能测试工具,想做个全面的性能测试。
以TTLB Avg为参考值,远程数据源相较普通方式性能提升18.11%
5分钟内点击量增加271次,每秒连接数增加0.91次
名词解释:TTFB Avg:从第一个请求发出到测试工具接收到服务器应答数据的第一个字节之间的平均时间。
TTLB Avg:从第一个请求发出到测试工具接收到服务器应答数据的最后一个字节之间的平均时间
虽然应用到了实际项目中,但这个项目pv不是很高。现在不太敢用到大型项目中,把服务端代码公布出来,如果有兴趣,可以看看,帮我找找问题,共同探讨。
为每个proxool别名创建一个对象,并保存在内存中
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Hashtable;
import org.apache.log4j.Logger;
import org.logicalcobwebs.proxool.ProxoolFacade;
public class ConnectionFactoryPools extends UnicastRemoteObject implements Factory {
/**
*
*/
private static final long serialVersionUID = -9094038611699927527L;
private static Logger log = Logger.getLogger(ConnectionFactoryPools.class);
private static Hashtable<String, ConnectionFactory> factoryPools = null;
static {
String[] aliases = ProxoolFacade.getAliases();
if (aliases.length > 0) {
factoryPools = new Hashtable<String, ConnectionFactory>();
for (int i = 0; i < aliases.length; i++) {
ConnectionFactory factory = new ConnectionFactory(aliases[i]);
factoryPools.put(aliases[i], factory);
}
}
}
public ConnectionFactoryPools() throws RemoteException {}
public String authenticateAlias(ConnectionParam param) throws RemoteException {
log.info("Authenticate alias=" + param.getAlias());
String aliasKey = "90";
if (factoryPools != null && param.getAlias() != null) {
ConnectionFactory factory = factoryPools.get(param.getAlias());
if (factory != null) {
int flag = factory.checkConConfig(param);
if (flag == 0) {
aliasKey = factory.toString();
}
} else {
aliasKey = "91";
}
}
return aliasKey;
}
/**
* <p>Title: createQueryConnection</p>
* <p>Description: 创建查询的connection环境</p>
* @author mazhen
* @return 0:参数正常 1:参数不全 2: 连接池中没有数据源
* 3:用户名错误 4:密码错误 5:没有指定别名的数据源
* 90:工厂池为空 91:指定的数据库别名没有工厂对象 99:异常
*/
public String createQueryConnection(String alias, String aliasKey, String sql) throws RemoteException {
String conKey = "90";
if (factoryPools != null && aliasKey != null && alias != null) {
ConnectionFactory factory = factoryPools.get(alias);
if (factory != null && aliasKey.equals(factory.toString())) {
conKey = factory.createQueryConnection(sql);
} else {
conKey = "91";
}
}
return conKey;
}
/**
* <p>Title: createQueryConnection</p>
* <p>Description: 创建查询的connection环境</p>
* @author mazhen
* @return 0:参数正常 1:参数不全 2: 连接池中没有数据源
* 3:用户名错误 4:密码错误 5:没有指定别名的数据源
* 90:工厂池为空 91:指定的数据库别名没有工厂对象 99:异常
*/
public String createQueryConnection(ConnectionParam param, String sql) throws RemoteException {
String conKey = "90";
if (factoryPools != null && param.getAlias() != null) {
ConnectionFactory factory = factoryPools.get(param.getAlias());
if (factory != null) {
conKey = factory.createQueryConnection(param, sql);
} else {
conKey = "91";
}
}
return conKey;
}
public void releaseQueryConnection(String alias, String conKey) throws RemoteException {
MConnection con = (MConnection) NamingManager.lookup(conKey);
boolean flag = false;
if (factoryPools != null && alias != null) {
ConnectionFactory factory = factoryPools.get(alias);
if (factory != null) {
flag = factory.activateConnectionInPools(con.getSql());
}
}
//工厂激活链接失败,则强制关闭链接
if (flag == false) {
con.releaseQueryConfig();
}
}
/**
* <p>Title: createProcedureConnection</p>
* <p>Description: 创建存储过程的connection环境</p>
* @author mazhen
* @return 0:参数正常 1:参数不全 2: 连接池中没有数据源
* 3:用户名错误 4:密码错误 5:没有指定别名的数据源
* 90:工厂池为空 91:指定的数据库别名没有工厂对象 99:异常
*/
public String createProcedureConnection(ConnectionParam param, String procedure) throws RemoteException {
String conKey = "90";
if (factoryPools != null && param.getAlias() != null) {
ConnectionFactory factory = factoryPools.get(param.getAlias());
if (factory != null) {
conKey = factory.createProcedureConnection(param, procedure);
} else {
conKey = "91";
}
}
return conKey;
}
}
proxool别名工厂,创建链接和释放。会缓存常用sql的链接,以提升效率
import java.rmi.RemoteException;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Properties;
import java.util.Map.Entry;
import java.lang.ClassNotFoundException;
import org.apache.log4j.Logger;
import org.logicalcobwebs.proxool.ConnectionPoolDefinitionIF;
import org.logicalcobwebs.proxool.ProxoolFacade;
import com.changyou.proxool.PBEStringDecryptor;
public class ConnectionFactory {
//private boolean isEncrypt = true; //Is password been encrypted?
private int maxCount = 2; //use proxool's MinimumConnectionCount
private String alias = null;
private String user = null;
private String password = null;
private static Hashtable<String, MConnectionVo> connectionPools = null;
private static Logger log = Logger.getLogger(ConnectionFactory.class);
public ConnectionFactory(String alias) {
log.info("Initialising data source '" + alias + "' start.");
try {
ConnectionPoolDefinitionIF def = ProxoolFacade.getConnectionPoolDefinition(alias);
maxCount = def.getMinimumConnectionCount();
Properties p = def.getDelegateProperties();
Iterator j = p.keySet().iterator();
while (j.hasNext()) {
String name = (String)j.next();
String value = p.getProperty(name);
//比较用户名
if ((name.toLowerCase().indexOf("user") > -1)) {
this.user = value;
}
//比较密码
if ((name.toLowerCase().indexOf("password") > -1)
|| (name.toLowerCase().indexOf("passwd") > -1)) {
this.password = value;
}
}
this.alias = alias;
log.info("Initialising data source '" + alias + "' success.");
} catch(Exception e) {
maxCount = 2;
alias = null;
user = null;
password = null;
log.error("Initialising data source '" + alias + "' failed.");
log.error(e.toString());
}
connectionPools = new Hashtable<String, MConnectionVo>();
}
/**
* <p>Title: createQuerySource</p>
* <p>Description: 利用sql创建数据库链接和preparedStatement</p>
* @author mazhen
* @param sql
* @return 0:参数正常 1:参数不全 2: 连接池中没有数据源
* 3:用户名错误 4:密码错误 5:没有指定别名的数据源 99:异常
*/
public synchronized String createQueryConnection(ConnectionParam param, String sql) {
String conKey = "99";
int flag = checkConConfig(param);
if (flag == 0) {
//首先看看常用sql的链接池中是否有这个sql的链接
String hasCon = getConnectionFromPools(sql);
if (hasCon != null) {
//如果池中有此sql链接,则直接掉用池中的链接
conKey = hasCon;
} else {
//没有链接或者链接被占用
try {
Connection connection = DriverManager.getConnection("proxool." + alias);
PreparedStatement statement = connection.prepareStatement(sql);
MConnection mcon = new MConnectionImpl(connection, statement);
mcon.setSql(sql);
conKey = mcon.toString();
NamingManager.bind(conKey, mcon);
//如果池中没有此sql的链接,则添加一个,如果有则重置最后访问时间
addConnectionToPools(sql, mcon);
} catch (Exception e) {
log.error("Created query connection with user and password!alias=" + alias);
log.error("sql=" + sql);
log.error(e.toString());
}
}
} else {
conKey = new Integer(flag).toString();
}
return conKey;
}
public synchronized String createQueryConnection(String sql) {
String conKey = "99";
//首先看看常用sql的链接池中是否有这个sql的链接
String hasCon = getConnectionFromPools(sql);
if (hasCon != null) {
//如果池中有此sql链接,则直接掉用池中的链接
conKey = hasCon;
} else {
//没有链接或者链接被占用
try {
Connection connection = DriverManager.getConnection("proxool." + alias);
PreparedStatement statement = connection.prepareStatement(sql);
MConnection mcon = new MConnectionImpl(connection, statement);
mcon.setSql(sql);
conKey = mcon.toString();
NamingManager.bind(conKey, mcon);
//如果池中没有此sql的链接,则添加一个,如果有则重置最后访问时间
addConnectionToPools(sql, mcon);
} catch (Exception e) {
log.error("Created query connection without user and password!alias=" + this.alias);
log.error("sql=" + sql);
log.error(e.toString());
}
}
return conKey;
}
/**
* <p>Title: createProcedureConnection</p>
* <p>Description: 检查数据库链接别名,用户名,密码是否正确</p>
* @author mazhen
* @param procedure
* @return 0:参数正常 1:参数不全 2: 连接池中没有数据源
* 3:用户名错误 4:密码错误 5:没有指定别名的数据源 99:异常
*/
public synchronized String createProcedureConnection(ConnectionParam param, String sql) {
String conKey = "99";
int flag = checkConConfig(param);
if (flag == 0) {
//首先看看常用sql的链接池中是否有这个sql的链接
String hasCon = getConnectionFromPools(sql);
if (hasCon != null) {
//如果池中有此sql链接,则直接掉用池中的链接
conKey = hasCon;
} else {
//没有链接或者链接被占用
try {
Connection connection = DriverManager.getConnection("proxool." + alias);
CallableStatement statement = connection.prepareCall(sql);
MConnection mcon = new MConnectionImpl(connection, statement);
mcon.setSql(sql);
conKey = mcon.toString();
NamingManager.bind(conKey, mcon);
//如果池中没有此sql的链接,则添加一个,如果有则重置最后访问时间
addConnectionToPools(sql, mcon);
} catch (Exception e) {
log.error("Created Procedure connection with user and password!alias=" + alias);
log.error("sql=" + sql);
log.error(e.toString());
}
}
} else {
conKey = new Integer(flag).toString();
}
return conKey;
}
public synchronized String createProcedureConnection(String sql) {
String conKey = "99";
//首先看看常用sql的链接池中是否有这个sql的链接
String hasCon = getConnectionFromPools(sql);
if (hasCon != null) {
//如果池中有此sql链接,则直接掉用池中的链接
conKey = hasCon;
} else {
//没有链接或者链接被占用
try {
Connection connection = DriverManager.getConnection("proxool." + alias);
CallableStatement statement = connection.prepareCall(sql);
MConnection mcon = new MConnectionImpl(connection, statement);
mcon.setSql(sql);
conKey = mcon.toString();
NamingManager.bind(conKey, mcon);
//如果池中没有此sql的链接,则添加一个,如果有则重置最后访问时间
addConnectionToPools(sql, mcon);
} catch (Exception e) {
log.error("Created Procedure connection without user and password!alias=" + this.alias);
log.error("sql=" + sql);
log.error(e.toString());
}
}
return conKey;
}
/**
* <p>Title: checkConConfig</p>
* <p>Description: 检查数据库链接别名,用户名,密码是否正确</p>
* @author mazhen
* @return 0:参数正常 1:参数不全 2: 连接池中没有数据源
* 3:用户名错误 4:密码错误 5:没有指定别名的数据源 99:异常
*/
public int checkConConfig(ConnectionParam param) {
int flag = 99;
if (param.getAlias() == null || param.getUser() == null || param.getPassword() == null) {
//1:参数不全
flag = 1;
} else {
if (param.getAlias().equals(this.alias) && user != null && password != null) {
//比较用户名
if (param.getUser().equals(user) == false) {
//3:用户名错误
flag = 3;
}
//比较密码
String dePassword = param.getPassword();
try {
//利用了运行时异常和编译时异常,在有PBEStringEncryptor时,则解密
//没有PBEStringEncryptor这个接口时,虽然PBEStringDecryptor编译错误,但是当前工厂可以编译通过,且不走PBEStringDecryptor的分支
if (Class.forName("org.jasypt.encryption.pbe.PBEStringEncryptor").isInterface() == true) {
dePassword = PBEStringDecryptor.decrypt(dePassword);
if (dePassword == null) {
dePassword = param.getPassword();
}
}
} catch (ClassNotFoundException c) {
log.info("Don't need decrypt! alias=" + param.getAlias());
} catch (Exception e) {
log.error("PBEStringEncryptor decrypt password faild! alias=" + param.getAlias());
log.error(e.toString());
}
if (password.equals(dePassword) == false) {
//4:密码错误
flag = 4;
}
//0:参数正确
if (flag != 3 && flag != 4) {
flag = 0;
}
}
}
return flag;
}
/**
* <p>Title: getConnectionFromPools</p>
* <p>Description: 查找连接池中是否存在此sql的链接</p>
* @author mazhen
* @return null:连接池中没有此sql的链接 con:连接的字符串
*/
private String getConnectionFromPools(String sql) {
String returnValue = null;
MConnectionVo vo = connectionPools.get(sql);
if (vo != null) {
//验证此链接是否还活着?
try {
if (vo.getCon().checkClose() == false) {
if (vo.isUsing() == false) {
vo.setUsing(true);
vo.setLastUsedTime(System.currentTimeMillis());
returnValue = vo.getCon().toString();
}
} else {
connectionPools.remove(sql);
}
} catch(RemoteException e) {
connectionPools.remove(sql);
log.error("Check connection is openning faild!alias=" + this.alias);
log.error("sql=" + sql);
log.error(e.toString());
}
}
return returnValue;
}
/**
* <p>Title: addConnectionToPools</p>
* <p>Description: 向连接池中添加链接</p>
* @author mazhen
*/
private void addConnectionToPools(String sql, MConnection con) {
//如果此sql对应的链接在池中存在
MConnectionVo vo = connectionPools.get(sql);
if (vo != null) {
vo.setLastUsedTime(System.currentTimeMillis());
return;
}
if (connectionPools.size() < this.maxCount) {
vo = new MConnectionVo();
vo.setCon(con);
connectionPools.put(sql, vo);
} else {
//找到访问时间最久远的sql
Iterator it = connectionPools.entrySet().iterator();
String lastUsedSql = null;
long lastUsedTime = System.currentTimeMillis();
while (it.hasNext()) {
Entry<String, MConnectionVo> entry = (Entry) it.next();
MConnectionVo value = entry.getValue();
if (lastUsedTime > value.getLastUsedTime()) {
lastUsedTime = value.getLastUsedTime();
lastUsedSql = entry.getKey();
}
}
//release last connection
try {
vo = connectionPools.get(lastUsedSql);
vo.getCon().releaseQueryConfig();
vo.getCon().releaseProcedureConfig();
vo = null;
} catch(Exception e) {
log.error("Release last connection faild!sql=" + sql);
} finally {
vo = null;
}
vo = new MConnectionVo();
vo.setCon(con);
connectionPools.remove(lastUsedSql);
connectionPools.put(sql, vo);
}
}
/**
* <p>Title: activateConnectionInPools</p>
* <p>Description: 激活链接,供下次访问使用</p>
* @author mazhen
* @return true:激活成功 false:激活失败
*/
public boolean activateConnectionInPools(String sql) {
boolean returnValue = false;
MConnectionVo vo = connectionPools.get(sql);
if (vo != null) {
vo.setUsing(false);
returnValue = true;
}
return returnValue;
}
}
链接对象,处理数据库操作
import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Vector;
import java.util.HashMap;
import java.sql.ResultSetMetaData;
import java.sql.Types;
import javax.sql.rowset.CachedRowSet;
import org.apache.log4j.Logger;
//import com.sun.rowset.CachedRowSetImpl;
//import com.sun.rowset.internal.Row;
public class MConnectionImpl extends UnicastRemoteObject implements MConnection {
/**
*
*/
private static final long serialVersionUID = -2338044775116389138L;
private String sql = null;
private static Logger log = Logger.getLogger(MConnectionImpl.class);
public MConnectionImpl(Connection con, PreparedStatement statement) throws RemoteException {
this.connection = con;
this.preparedStatement = statement;
}
public MConnectionImpl(Connection con, CallableStatement statement) throws RemoteException {
this.connection = con;
this.callableStatement = statement;
}
private Connection connection = null;
private PreparedStatement preparedStatement = null;
private CallableStatement callableStatement = null;
private ResultSet resultSet = null;
private CachedRowSet rowSet = null;
public void releaseQueryConfig() throws RemoteException {
try {
if (connection != null) {
NamingManager.unbind(this.toString());
connection.close();
}
if (preparedStatement != null) {
preparedStatement.close();
}
if (resultSet != null) {
resultSet.close();
}
} catch(Exception e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
}
public void releaseProcedureConfig() throws RemoteException {
try {
if (connection != null) {
NamingManager.unbind(this.toString());
connection.close();
}
if (callableStatement != null) {
callableStatement.close();
}
} catch(Exception e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
}
public void setStringPreparedSmt(int index, String parameter) throws RemoteException {
try {
if (this.preparedStatement != null) {
this.preparedStatement.setString(index, parameter);
}
} catch (Exception e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
}
public void setIntPreparedSmt(int index, int parameter) throws RemoteException {
try {
if (this.preparedStatement != null) {
this.preparedStatement.setInt(index, parameter);
}
} catch (Exception e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
}
public void setDatePreparedSmt(int index, Date parameter) throws RemoteException {
try {
if (this.preparedStatement != null) {
this.preparedStatement.setDate(index, parameter);
}
} catch (Exception e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
}
public void execPreparedSmt() throws RemoteException {
try {
//long st_temp = System.currentTimeMillis();
this.resultSet = this.preparedStatement.executeQuery();
//long end_temp = System.currentTimeMillis();
//System.out.println("execute used "+(end_temp - st_temp));
} catch(Exception e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
}
public int execPreparedSmtForUpdate() throws RemoteException {
int returnValue = -1;
try {
//long st_temp = System.currentTimeMillis();
returnValue = this.preparedStatement.executeUpdate();
//long end_temp = System.currentTimeMillis();
//System.out.println("execute used "+(end_temp - st_temp));
} catch(Exception e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
return returnValue;
}
// public void setStringCallableSmt(int index, String parameter) throws RemoteException {
// try {
// if (this.callableStatement != null) {
// this.callableStatement.setString(index, parameter);
// }
// } catch (Exception e) {
// e.printStackTrace();
// }
//
// }
//
// public void execCallableSmt() throws RemoteException {
// try {
// this.resultSet = this.preparedStatement.executeQuery();
// } catch(Exception e) {
// e.printStackTrace();
// }
// }
public String getStringResult(String column) throws RemoteException {
String returnValue = null;
try {
if (this.resultSet.next()) {
returnValue = this.resultSet.getString(column);
}
} catch(SQLException e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
return returnValue;
}
public int getIntResult(String column) throws RemoteException {
int returnValue = -1;
try {
if (this.resultSet.next()) {
returnValue = this.resultSet.getInt(column);
}
} catch(SQLException e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
return returnValue;
}
public Collection getResultSet() throws RemoteException {
Vector returnValue = new Vector();
try {
ResultSetMetaData meta = resultSet.getMetaData();
String name = null;
while (resultSet.next()) {
java.util.Map row = new HashMap();
for (int column = 1; column <= meta.getColumnCount(); column++) {
int type = meta.getColumnType(column);
name = meta.getColumnName(column);
//System.out.println(name+"/////"+type);
if (Types.CHAR == type || Types.VARCHAR == type
|| Types.CLOB == type) {
String value = resultSet.getString(column);
row.put(name, value);
} else if (Types.INTEGER == type || Types.TINYINT == type
|| Types.NUMERIC == type) {
int value = resultSet.getInt(column);
row.put(name, value);
} else if (Types.DATE == type || Types.TIME == type
|| Types.TIMESTAMP == type) {
java.util.Date value = resultSet.getDate(column);
row.put(name, value);
}
}
returnValue.add(row);
}
} catch(Exception e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
return returnValue;
}
public String getSql() throws RemoteException {
return sql;
}
public void setSql(String sql) throws RemoteException {
this.sql = sql;
}
public boolean checkClose() throws RemoteException {
boolean flag = true;
try {
flag = this.connection.isClosed();
} catch(SQLException e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
return flag;
}
}
主要就是这3个类,其他还有些接口就不放上来了。
远程数据源应用于正式环境有一段时间了。期间未收到bug提交。
查看了从6月2日-6月12日的日志,发现两种error错误。经调查这两种错误都是由于业务逻辑错误造成的,和数据源无关。(意外收获,还能检查逻辑漏洞)
学习了微软的was性能测试工具,想做个全面的性能测试。
以TTLB Avg为参考值,远程数据源相较普通方式性能提升18.11%
5分钟内点击量增加271次,每秒连接数增加0.91次
名词解释:TTFB Avg:从第一个请求发出到测试工具接收到服务器应答数据的第一个字节之间的平均时间。
TTLB Avg:从第一个请求发出到测试工具接收到服务器应答数据的最后一个字节之间的平均时间
虽然应用到了实际项目中,但这个项目pv不是很高。现在不太敢用到大型项目中,把服务端代码公布出来,如果有兴趣,可以看看,帮我找找问题,共同探讨。
为每个proxool别名创建一个对象,并保存在内存中
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Hashtable;
import org.apache.log4j.Logger;
import org.logicalcobwebs.proxool.ProxoolFacade;
public class ConnectionFactoryPools extends UnicastRemoteObject implements Factory {
/**
*
*/
private static final long serialVersionUID = -9094038611699927527L;
private static Logger log = Logger.getLogger(ConnectionFactoryPools.class);
private static Hashtable<String, ConnectionFactory> factoryPools = null;
static {
String[] aliases = ProxoolFacade.getAliases();
if (aliases.length > 0) {
factoryPools = new Hashtable<String, ConnectionFactory>();
for (int i = 0; i < aliases.length; i++) {
ConnectionFactory factory = new ConnectionFactory(aliases[i]);
factoryPools.put(aliases[i], factory);
}
}
}
public ConnectionFactoryPools() throws RemoteException {}
public String authenticateAlias(ConnectionParam param) throws RemoteException {
log.info("Authenticate alias=" + param.getAlias());
String aliasKey = "90";
if (factoryPools != null && param.getAlias() != null) {
ConnectionFactory factory = factoryPools.get(param.getAlias());
if (factory != null) {
int flag = factory.checkConConfig(param);
if (flag == 0) {
aliasKey = factory.toString();
}
} else {
aliasKey = "91";
}
}
return aliasKey;
}
/**
* <p>Title: createQueryConnection</p>
* <p>Description: 创建查询的connection环境</p>
* @author mazhen
* @return 0:参数正常 1:参数不全 2: 连接池中没有数据源
* 3:用户名错误 4:密码错误 5:没有指定别名的数据源
* 90:工厂池为空 91:指定的数据库别名没有工厂对象 99:异常
*/
public String createQueryConnection(String alias, String aliasKey, String sql) throws RemoteException {
String conKey = "90";
if (factoryPools != null && aliasKey != null && alias != null) {
ConnectionFactory factory = factoryPools.get(alias);
if (factory != null && aliasKey.equals(factory.toString())) {
conKey = factory.createQueryConnection(sql);
} else {
conKey = "91";
}
}
return conKey;
}
/**
* <p>Title: createQueryConnection</p>
* <p>Description: 创建查询的connection环境</p>
* @author mazhen
* @return 0:参数正常 1:参数不全 2: 连接池中没有数据源
* 3:用户名错误 4:密码错误 5:没有指定别名的数据源
* 90:工厂池为空 91:指定的数据库别名没有工厂对象 99:异常
*/
public String createQueryConnection(ConnectionParam param, String sql) throws RemoteException {
String conKey = "90";
if (factoryPools != null && param.getAlias() != null) {
ConnectionFactory factory = factoryPools.get(param.getAlias());
if (factory != null) {
conKey = factory.createQueryConnection(param, sql);
} else {
conKey = "91";
}
}
return conKey;
}
public void releaseQueryConnection(String alias, String conKey) throws RemoteException {
MConnection con = (MConnection) NamingManager.lookup(conKey);
boolean flag = false;
if (factoryPools != null && alias != null) {
ConnectionFactory factory = factoryPools.get(alias);
if (factory != null) {
flag = factory.activateConnectionInPools(con.getSql());
}
}
//工厂激活链接失败,则强制关闭链接
if (flag == false) {
con.releaseQueryConfig();
}
}
/**
* <p>Title: createProcedureConnection</p>
* <p>Description: 创建存储过程的connection环境</p>
* @author mazhen
* @return 0:参数正常 1:参数不全 2: 连接池中没有数据源
* 3:用户名错误 4:密码错误 5:没有指定别名的数据源
* 90:工厂池为空 91:指定的数据库别名没有工厂对象 99:异常
*/
public String createProcedureConnection(ConnectionParam param, String procedure) throws RemoteException {
String conKey = "90";
if (factoryPools != null && param.getAlias() != null) {
ConnectionFactory factory = factoryPools.get(param.getAlias());
if (factory != null) {
conKey = factory.createProcedureConnection(param, procedure);
} else {
conKey = "91";
}
}
return conKey;
}
}
proxool别名工厂,创建链接和释放。会缓存常用sql的链接,以提升效率
import java.rmi.RemoteException;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Properties;
import java.util.Map.Entry;
import java.lang.ClassNotFoundException;
import org.apache.log4j.Logger;
import org.logicalcobwebs.proxool.ConnectionPoolDefinitionIF;
import org.logicalcobwebs.proxool.ProxoolFacade;
import com.changyou.proxool.PBEStringDecryptor;
public class ConnectionFactory {
//private boolean isEncrypt = true; //Is password been encrypted?
private int maxCount = 2; //use proxool's MinimumConnectionCount
private String alias = null;
private String user = null;
private String password = null;
private static Hashtable<String, MConnectionVo> connectionPools = null;
private static Logger log = Logger.getLogger(ConnectionFactory.class);
public ConnectionFactory(String alias) {
log.info("Initialising data source '" + alias + "' start.");
try {
ConnectionPoolDefinitionIF def = ProxoolFacade.getConnectionPoolDefinition(alias);
maxCount = def.getMinimumConnectionCount();
Properties p = def.getDelegateProperties();
Iterator j = p.keySet().iterator();
while (j.hasNext()) {
String name = (String)j.next();
String value = p.getProperty(name);
//比较用户名
if ((name.toLowerCase().indexOf("user") > -1)) {
this.user = value;
}
//比较密码
if ((name.toLowerCase().indexOf("password") > -1)
|| (name.toLowerCase().indexOf("passwd") > -1)) {
this.password = value;
}
}
this.alias = alias;
log.info("Initialising data source '" + alias + "' success.");
} catch(Exception e) {
maxCount = 2;
alias = null;
user = null;
password = null;
log.error("Initialising data source '" + alias + "' failed.");
log.error(e.toString());
}
connectionPools = new Hashtable<String, MConnectionVo>();
}
/**
* <p>Title: createQuerySource</p>
* <p>Description: 利用sql创建数据库链接和preparedStatement</p>
* @author mazhen
* @param sql
* @return 0:参数正常 1:参数不全 2: 连接池中没有数据源
* 3:用户名错误 4:密码错误 5:没有指定别名的数据源 99:异常
*/
public synchronized String createQueryConnection(ConnectionParam param, String sql) {
String conKey = "99";
int flag = checkConConfig(param);
if (flag == 0) {
//首先看看常用sql的链接池中是否有这个sql的链接
String hasCon = getConnectionFromPools(sql);
if (hasCon != null) {
//如果池中有此sql链接,则直接掉用池中的链接
conKey = hasCon;
} else {
//没有链接或者链接被占用
try {
Connection connection = DriverManager.getConnection("proxool." + alias);
PreparedStatement statement = connection.prepareStatement(sql);
MConnection mcon = new MConnectionImpl(connection, statement);
mcon.setSql(sql);
conKey = mcon.toString();
NamingManager.bind(conKey, mcon);
//如果池中没有此sql的链接,则添加一个,如果有则重置最后访问时间
addConnectionToPools(sql, mcon);
} catch (Exception e) {
log.error("Created query connection with user and password!alias=" + alias);
log.error("sql=" + sql);
log.error(e.toString());
}
}
} else {
conKey = new Integer(flag).toString();
}
return conKey;
}
public synchronized String createQueryConnection(String sql) {
String conKey = "99";
//首先看看常用sql的链接池中是否有这个sql的链接
String hasCon = getConnectionFromPools(sql);
if (hasCon != null) {
//如果池中有此sql链接,则直接掉用池中的链接
conKey = hasCon;
} else {
//没有链接或者链接被占用
try {
Connection connection = DriverManager.getConnection("proxool." + alias);
PreparedStatement statement = connection.prepareStatement(sql);
MConnection mcon = new MConnectionImpl(connection, statement);
mcon.setSql(sql);
conKey = mcon.toString();
NamingManager.bind(conKey, mcon);
//如果池中没有此sql的链接,则添加一个,如果有则重置最后访问时间
addConnectionToPools(sql, mcon);
} catch (Exception e) {
log.error("Created query connection without user and password!alias=" + this.alias);
log.error("sql=" + sql);
log.error(e.toString());
}
}
return conKey;
}
/**
* <p>Title: createProcedureConnection</p>
* <p>Description: 检查数据库链接别名,用户名,密码是否正确</p>
* @author mazhen
* @param procedure
* @return 0:参数正常 1:参数不全 2: 连接池中没有数据源
* 3:用户名错误 4:密码错误 5:没有指定别名的数据源 99:异常
*/
public synchronized String createProcedureConnection(ConnectionParam param, String sql) {
String conKey = "99";
int flag = checkConConfig(param);
if (flag == 0) {
//首先看看常用sql的链接池中是否有这个sql的链接
String hasCon = getConnectionFromPools(sql);
if (hasCon != null) {
//如果池中有此sql链接,则直接掉用池中的链接
conKey = hasCon;
} else {
//没有链接或者链接被占用
try {
Connection connection = DriverManager.getConnection("proxool." + alias);
CallableStatement statement = connection.prepareCall(sql);
MConnection mcon = new MConnectionImpl(connection, statement);
mcon.setSql(sql);
conKey = mcon.toString();
NamingManager.bind(conKey, mcon);
//如果池中没有此sql的链接,则添加一个,如果有则重置最后访问时间
addConnectionToPools(sql, mcon);
} catch (Exception e) {
log.error("Created Procedure connection with user and password!alias=" + alias);
log.error("sql=" + sql);
log.error(e.toString());
}
}
} else {
conKey = new Integer(flag).toString();
}
return conKey;
}
public synchronized String createProcedureConnection(String sql) {
String conKey = "99";
//首先看看常用sql的链接池中是否有这个sql的链接
String hasCon = getConnectionFromPools(sql);
if (hasCon != null) {
//如果池中有此sql链接,则直接掉用池中的链接
conKey = hasCon;
} else {
//没有链接或者链接被占用
try {
Connection connection = DriverManager.getConnection("proxool." + alias);
CallableStatement statement = connection.prepareCall(sql);
MConnection mcon = new MConnectionImpl(connection, statement);
mcon.setSql(sql);
conKey = mcon.toString();
NamingManager.bind(conKey, mcon);
//如果池中没有此sql的链接,则添加一个,如果有则重置最后访问时间
addConnectionToPools(sql, mcon);
} catch (Exception e) {
log.error("Created Procedure connection without user and password!alias=" + this.alias);
log.error("sql=" + sql);
log.error(e.toString());
}
}
return conKey;
}
/**
* <p>Title: checkConConfig</p>
* <p>Description: 检查数据库链接别名,用户名,密码是否正确</p>
* @author mazhen
* @return 0:参数正常 1:参数不全 2: 连接池中没有数据源
* 3:用户名错误 4:密码错误 5:没有指定别名的数据源 99:异常
*/
public int checkConConfig(ConnectionParam param) {
int flag = 99;
if (param.getAlias() == null || param.getUser() == null || param.getPassword() == null) {
//1:参数不全
flag = 1;
} else {
if (param.getAlias().equals(this.alias) && user != null && password != null) {
//比较用户名
if (param.getUser().equals(user) == false) {
//3:用户名错误
flag = 3;
}
//比较密码
String dePassword = param.getPassword();
try {
//利用了运行时异常和编译时异常,在有PBEStringEncryptor时,则解密
//没有PBEStringEncryptor这个接口时,虽然PBEStringDecryptor编译错误,但是当前工厂可以编译通过,且不走PBEStringDecryptor的分支
if (Class.forName("org.jasypt.encryption.pbe.PBEStringEncryptor").isInterface() == true) {
dePassword = PBEStringDecryptor.decrypt(dePassword);
if (dePassword == null) {
dePassword = param.getPassword();
}
}
} catch (ClassNotFoundException c) {
log.info("Don't need decrypt! alias=" + param.getAlias());
} catch (Exception e) {
log.error("PBEStringEncryptor decrypt password faild! alias=" + param.getAlias());
log.error(e.toString());
}
if (password.equals(dePassword) == false) {
//4:密码错误
flag = 4;
}
//0:参数正确
if (flag != 3 && flag != 4) {
flag = 0;
}
}
}
return flag;
}
/**
* <p>Title: getConnectionFromPools</p>
* <p>Description: 查找连接池中是否存在此sql的链接</p>
* @author mazhen
* @return null:连接池中没有此sql的链接 con:连接的字符串
*/
private String getConnectionFromPools(String sql) {
String returnValue = null;
MConnectionVo vo = connectionPools.get(sql);
if (vo != null) {
//验证此链接是否还活着?
try {
if (vo.getCon().checkClose() == false) {
if (vo.isUsing() == false) {
vo.setUsing(true);
vo.setLastUsedTime(System.currentTimeMillis());
returnValue = vo.getCon().toString();
}
} else {
connectionPools.remove(sql);
}
} catch(RemoteException e) {
connectionPools.remove(sql);
log.error("Check connection is openning faild!alias=" + this.alias);
log.error("sql=" + sql);
log.error(e.toString());
}
}
return returnValue;
}
/**
* <p>Title: addConnectionToPools</p>
* <p>Description: 向连接池中添加链接</p>
* @author mazhen
*/
private void addConnectionToPools(String sql, MConnection con) {
//如果此sql对应的链接在池中存在
MConnectionVo vo = connectionPools.get(sql);
if (vo != null) {
vo.setLastUsedTime(System.currentTimeMillis());
return;
}
if (connectionPools.size() < this.maxCount) {
vo = new MConnectionVo();
vo.setCon(con);
connectionPools.put(sql, vo);
} else {
//找到访问时间最久远的sql
Iterator it = connectionPools.entrySet().iterator();
String lastUsedSql = null;
long lastUsedTime = System.currentTimeMillis();
while (it.hasNext()) {
Entry<String, MConnectionVo> entry = (Entry) it.next();
MConnectionVo value = entry.getValue();
if (lastUsedTime > value.getLastUsedTime()) {
lastUsedTime = value.getLastUsedTime();
lastUsedSql = entry.getKey();
}
}
//release last connection
try {
vo = connectionPools.get(lastUsedSql);
vo.getCon().releaseQueryConfig();
vo.getCon().releaseProcedureConfig();
vo = null;
} catch(Exception e) {
log.error("Release last connection faild!sql=" + sql);
} finally {
vo = null;
}
vo = new MConnectionVo();
vo.setCon(con);
connectionPools.remove(lastUsedSql);
connectionPools.put(sql, vo);
}
}
/**
* <p>Title: activateConnectionInPools</p>
* <p>Description: 激活链接,供下次访问使用</p>
* @author mazhen
* @return true:激活成功 false:激活失败
*/
public boolean activateConnectionInPools(String sql) {
boolean returnValue = false;
MConnectionVo vo = connectionPools.get(sql);
if (vo != null) {
vo.setUsing(false);
returnValue = true;
}
return returnValue;
}
}
链接对象,处理数据库操作
import java.rmi.server.UnicastRemoteObject;
import java.rmi.RemoteException;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Vector;
import java.util.HashMap;
import java.sql.ResultSetMetaData;
import java.sql.Types;
import javax.sql.rowset.CachedRowSet;
import org.apache.log4j.Logger;
//import com.sun.rowset.CachedRowSetImpl;
//import com.sun.rowset.internal.Row;
public class MConnectionImpl extends UnicastRemoteObject implements MConnection {
/**
*
*/
private static final long serialVersionUID = -2338044775116389138L;
private String sql = null;
private static Logger log = Logger.getLogger(MConnectionImpl.class);
public MConnectionImpl(Connection con, PreparedStatement statement) throws RemoteException {
this.connection = con;
this.preparedStatement = statement;
}
public MConnectionImpl(Connection con, CallableStatement statement) throws RemoteException {
this.connection = con;
this.callableStatement = statement;
}
private Connection connection = null;
private PreparedStatement preparedStatement = null;
private CallableStatement callableStatement = null;
private ResultSet resultSet = null;
private CachedRowSet rowSet = null;
public void releaseQueryConfig() throws RemoteException {
try {
if (connection != null) {
NamingManager.unbind(this.toString());
connection.close();
}
if (preparedStatement != null) {
preparedStatement.close();
}
if (resultSet != null) {
resultSet.close();
}
} catch(Exception e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
}
public void releaseProcedureConfig() throws RemoteException {
try {
if (connection != null) {
NamingManager.unbind(this.toString());
connection.close();
}
if (callableStatement != null) {
callableStatement.close();
}
} catch(Exception e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
}
public void setStringPreparedSmt(int index, String parameter) throws RemoteException {
try {
if (this.preparedStatement != null) {
this.preparedStatement.setString(index, parameter);
}
} catch (Exception e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
}
public void setIntPreparedSmt(int index, int parameter) throws RemoteException {
try {
if (this.preparedStatement != null) {
this.preparedStatement.setInt(index, parameter);
}
} catch (Exception e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
}
public void setDatePreparedSmt(int index, Date parameter) throws RemoteException {
try {
if (this.preparedStatement != null) {
this.preparedStatement.setDate(index, parameter);
}
} catch (Exception e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
}
public void execPreparedSmt() throws RemoteException {
try {
//long st_temp = System.currentTimeMillis();
this.resultSet = this.preparedStatement.executeQuery();
//long end_temp = System.currentTimeMillis();
//System.out.println("execute used "+(end_temp - st_temp));
} catch(Exception e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
}
public int execPreparedSmtForUpdate() throws RemoteException {
int returnValue = -1;
try {
//long st_temp = System.currentTimeMillis();
returnValue = this.preparedStatement.executeUpdate();
//long end_temp = System.currentTimeMillis();
//System.out.println("execute used "+(end_temp - st_temp));
} catch(Exception e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
return returnValue;
}
// public void setStringCallableSmt(int index, String parameter) throws RemoteException {
// try {
// if (this.callableStatement != null) {
// this.callableStatement.setString(index, parameter);
// }
// } catch (Exception e) {
// e.printStackTrace();
// }
//
// }
//
// public void execCallableSmt() throws RemoteException {
// try {
// this.resultSet = this.preparedStatement.executeQuery();
// } catch(Exception e) {
// e.printStackTrace();
// }
// }
public String getStringResult(String column) throws RemoteException {
String returnValue = null;
try {
if (this.resultSet.next()) {
returnValue = this.resultSet.getString(column);
}
} catch(SQLException e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
return returnValue;
}
public int getIntResult(String column) throws RemoteException {
int returnValue = -1;
try {
if (this.resultSet.next()) {
returnValue = this.resultSet.getInt(column);
}
} catch(SQLException e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
return returnValue;
}
public Collection getResultSet() throws RemoteException {
Vector returnValue = new Vector();
try {
ResultSetMetaData meta = resultSet.getMetaData();
String name = null;
while (resultSet.next()) {
java.util.Map row = new HashMap();
for (int column = 1; column <= meta.getColumnCount(); column++) {
int type = meta.getColumnType(column);
name = meta.getColumnName(column);
//System.out.println(name+"/////"+type);
if (Types.CHAR == type || Types.VARCHAR == type
|| Types.CLOB == type) {
String value = resultSet.getString(column);
row.put(name, value);
} else if (Types.INTEGER == type || Types.TINYINT == type
|| Types.NUMERIC == type) {
int value = resultSet.getInt(column);
row.put(name, value);
} else if (Types.DATE == type || Types.TIME == type
|| Types.TIMESTAMP == type) {
java.util.Date value = resultSet.getDate(column);
row.put(name, value);
}
}
returnValue.add(row);
}
} catch(Exception e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
return returnValue;
}
public String getSql() throws RemoteException {
return sql;
}
public void setSql(String sql) throws RemoteException {
this.sql = sql;
}
public boolean checkClose() throws RemoteException {
boolean flag = true;
try {
flag = this.connection.isClosed();
} catch(SQLException e) {
log.error("Sql=" + sql);
log.error(e.toString());
}
return flag;
}
}
主要就是这3个类,其他还有些接口就不放上来了。
相关推荐
### SpringMVC+JNDI+Tomcat配置数据源 #### 一、简介 在Java Web开发中,数据源(DataSource)是管理数据库连接的重要组件。SpringMVC框架结合Java Naming and Directory Interface (JNDI) 和Apache Tomcat服务器...
通过学习和实践这个"Struts+Jndi+Ajax"的示例,初学者可以更好地理解这三者如何协同工作,构建出功能丰富的Web应用。了解和掌握这些技术对于成为一名合格的Java Web开发者至关重要,因为它们在实际开发中被广泛使用...
### Spring + JOTM 多数据源事务管理详解(三):JNDI + Tomcat 在本篇文章中,我们将深入探讨如何利用Spring框架结合JOTM(Java Open Transaction Manager)来实现多数据源下的分布式事务管理。我们将通过具体实例...
在Java应用服务器中,数据源通常被注册到JNDI上下文中,以便于应用通过JNDI查找来获取数据源实例,从而进行数据库操作。 在Spring中配置JNDI数据源的步骤如下: 1. **环境配置**:在应用服务器中配置数据源。例如...
RMI(Remote Method Invocation)则是Java平台上的远程对象调用技术,允许程序在不同的Java虚拟机之间透明地调用方法。当我们结合Spring与RMI时,可以构建分布式系统,使得服务可以在网络中的不同节点上运行并交互。...
2. 实现远程接口:远程对象实现类必须扩展远程对象 java.rmi.UnicastRemoteObject 类,并实现所定义的远程接口。 JNDI(Java Naming and Directory Interface)是 Java 平台上的一个目录服务,它提供了一个统一的...
3. **配置 IbatisProject2.xml** - 在 Tomcat 的对应项目目录下配置数据源 JNDI。 4. **修改 sqlMapConfig.xml** - 更新 Ibatis 的配置文件,指定使用 JNDI 查找的数据源。 通过以上步骤,Ibatis 可以通过 JNDI ...
本文将深入解析如何在JBoss中配置MySQL的JNDI数据源,确保应用程序能够高效、稳定地访问数据库资源。 ### JBoss与JNDI的关联 JBoss作为一个高性能的Java应用服务器,提供了丰富的功能支持企业级应用开发。JNDI作为...
### Spring 获取 WebLogic JNDI 数据源的两种方式 在Spring框架中,通过JNDI(Java Naming and Directory Interface)可以方便地访问WebLogic服务器中的数据源。这为应用程序提供了高度解耦的数据访问机制,使得...
配置文件:jndi+spring注解配置
在Web应用中,JNDI常用来查找数据源,比如在应用服务器中配置的数据源。这样,应用程序可以通过JNDI名字查找数据库连接,而不是硬编码数据库连接信息,提高了应用的可移植性和安全性。 JDBC是Java连接数据库的标准...
在现代企业级应用开发中,多数据源切换和分布式事务管理是常见的需求,尤其是在大型分布式系统中。Spring框架因其强大的依赖注入和AOP(面向切面编程)特性,成为Java领域首选的轻量级框架。Druid是一个优秀的数据库...
在这个场景中,“intellij idea使用tomcat开发时自动部署jndi数据源”是一个重要的知识点,它涉及到如何在IDE中配置和管理数据库连接,以便于在应用运行时动态地查找和使用数据源。 JNDI(Java Naming and ...
在Java Web应用中,JNDI常用于查找数据源(DataSource),使得应用可以透明地连接到数据库,如MySQL。 5. **JDK 1.5**: JDK 1.5(也称为Java SE 5.0)是Java语言的一个重要版本,引入了许多新特性,如泛型、枚举...
JNDI主要用于Java应用中的命名和目录服务,它可以与RMI结合使用来查找和绑定远程对象: 1. **创建JNDI上下文**:在服务器端,使用`InitialContext`创建JNDI上下文并绑定远程对象。 2. **查找远程对象**:在客户端,...
SSH(Struts2+Spring3+Hibernate3)是一种常见的Java Web开发框架组合,它整合了...通过Spring管理数据源和事务,Hibernate处理数据持久化,Struts2处理用户交互,而Proxool则优化了数据库连接的使用,提高了系统性能。
4. **在应用中引用JNDI数据源**:在Java代码中,你可以通过JNDI查找来获取数据源。例如,在Servlet或JSP中: ```java InitialContext ic = new InitialContext(); DataSource ds = (DataSource) ic.lookup("java:...
JNDI(Java Naming and Directory Interface)数据源是Java应用程序中用于管理数据库连接的一种机制。它主要用于企业级应用服务器,如Tomcat、JBoss、WebLogic等,通过JNDI服务,开发者可以方便地查找和获取数据库...