描述:
现有的数据库连接方式是每次调用MySQL.getConnection均会从连接池获取一个真实的连接,如下图所示。
此种数据库连接方式,假设action中使用循环调用service的方法,或者同一个action的种方法中调用了多个service, 则每个service中的connection均是从连接池获取的连接,如此种方式消耗的数据库连接太多,很容易爆满。上面的链接方式是//方式一
方式二
在一般情况下,从接收请求到返回响应所经过的所有程序调用都同属于一个线程, 从action中调用下面的service均是顺序调用的,即不会存在并发访问,一个sesion请求,web服务器会开启一个线程进行处理,即从拦截器开始可以认为是单线程下运行的,这样来看实际只需要一个数据库连接即可。
使用线程局部变量在保存首次获取的连接,在下次请求是再此返回同一个连接,直到方法执行完毕在释放次连接,看下面的应用本地线程变量写的程序
public class ConnectionManager{
private static Log log = LogFactory.getLog(ConnectionManager.class);
private static final ThreadLocal threadConection = new ThreadLocal();
public static Connection getConnection() throws SQLException {
//方式二
/**
* 优点: 基于线程sesion管理连接,同一个线程由于是顺序操作,只用一个数据库连接即可,无需手动关闭,可统一关闭连接,大大降低数据库连接池资源的消耗,增加数据库并发连接
* 缺点: 对于service调用service的代码部分,如果子service关闭了连接,主service方法需要再次获取连接,对现有代码需要改动
* 弥补: 自定义一个Connection的实现,拦截close方法,统一使用拦截器自动管理连接
*/
Connection conn = (Connection) threadConection.get();
try {
if (conn == null || conn.isClosed()) {
conn = dataSources.getConnection();
conn.setAutoCommit(false);
if (conn != null) {
connectionCountOpened++;
threadConection.set(conn);
}
}
} catch (Exception e) {
e.printStackTrace();
}
getConectionString();
return conn;
}
public static void closeConection(){
Connection conn = (Connection)threadConection.get();
try {
if (conn != null && !conn.isClosed()) {
conn.close();
log.info(Thread.currentThread()+" close database connection.");
}
}catch(Exception e){
e.printStackTrace();
log.error(e);
}
}
}
在给出service方法的拦截器,在service的方法执行完毕后再关闭连接
public class ServiceMethodInterceptor implements MethodInterceptor {
private static Log log = LogFactory.getLog(ServiceMethodInterceptor.class);
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
String info = invocation.getMethod().getDeclaringClass()+ "." + invocation.getMethod().getName() + "()";
Object[] ars = invocation.getArguments();
log.warn("service method "+invocation.getMethod()+"");
// 判断该方法是否加了@LoginRequired 注解
// if(invocation.getMethod().isAnnotationPresent(LoginRequired.class)){
// System.out.println("----------this method is added @LoginRequired-------------------------");
// }
try{
Object result = invocation.proceed();
ConnectionManager.closeConection();
return result;
}catch(Exception e){
e.printStackTrace();
log.error(e);
}finally{
log.info(info);
}
return null;
}
}
* 优点: 基于线程sesion管理连接,同一个线程由于是顺序操作,只用一个数据库连接即可,无需手动关闭,可统一关闭连接,大大降低数据库连接池资源的消耗,增加数据库并发连接
* 缺点: 对于service调用service的此种结构部分,如果子service关闭了连接,主service方法需要再次获取连接,对现有代码需要改动
* 改进: 自定义一个Connection的实现,拦截close方法,统一使用拦截器自动管理连接
本文原址: