数据库连接方式改进

描述:

现有的数据库连接方式是每次调用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方法,统一使用拦截器自动管理连接


本文原址: 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值