mybatis 如何关闭connection
1.前言
最开始操作数据库是使用jdbc操作数据库,每次创建一个连接都需要关闭连接,避免占用资源.比如
Class.forName("com.jdbc.mysql.Driver");
Connection con = DriverManager.getConnection("url",
"username",
"password");
Statement sta = null;
try {
//执行sql语句
sta = con.createStatement();
sta.execute("");
} finally {
//关闭连接
sta.close();
con.close();
}
最后需要通过 close 关闭连接;
2.mybatis 是如何管理连接资源的
public class DefaultSqlSession implements SqlSession {
@Override
public void close() {
try {
executor.close(isCommitOrRollbackRequired(false));//关闭执行器
closeCursors();
dirty = false;
} finally {
ErrorContext.instance().reset();
}
} }
这里只列举出了sqlsession中的close方法,可以看到sqlsession通过执行executor的close方法关闭连接.
public abstract class BaseExecutor implements Executor {
@Override
public void close(boolean forceRollback) {
try {
try {
rollback(forceRollback);//回滚事务
} finally {
if (transaction != null) {
transaction.close();关闭事务
}
}
} catch (SQLException e) {
// Ignore. There's nothing that can be done at this point.
log.warn("Unexpected exception on closing transaction. Cause: " + e);
} finally {
transaction = null;
deferredLoads = null;
localCache = null;
localOutputParameterCache = null;
closed = true;
}
}
}
在BaseExecutor中,通过关闭事务来进行关闭的.我们继续往下挖.
public class ManagedTransaction implements Transaction { private static final Log log = LogFactory.getLog(ManagedTransaction.class); private DataSource dataSource;
private TransactionIsolationLevel level;
private Connection connection;//java.sql.Connection 就是我们常用的jdbc连接 Connection
private final boolean closeConnection;
@Override
public void close() throws SQLException {
if (this.closeConnection && this.connection != null) {
if (log.isDebugEnabled()) {
log.debug("Closing JDBC Connection [" + this.connection + "]");
}
this.connection.close();//在close方法中进行关闭
}
}
}
在Transaction这个类中,通过执行Connection中的close方法关闭连接,但是这个方法需要通过自己手动写sqlsession.close(),那么为什么在具体的开发中不需要自己管理close()的调用呢?
答案就在spring与mybatis整合的jar包中.
public class SqlSessionTemplate implements SqlSession, DisposableBean { //这里实现了sqlSession,一般可以把SqlSessionTemplate当作sqlsession来使用 public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
PersistenceExceptionTranslator exceptionTranslator) { notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
notNull(executorType, "Property 'executorType' is required"); this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator;
this.sqlSessionProxy = (SqlSession) newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[] { SqlSession.class },
new SqlSessionInterceptor());//在构造方法中,我们看到sqlSessionProxy这个代理类是通过内部类SqlSessionInterceptor来生成
}
/**
* {@inheritDoc}
*/
@Override
public <T> T selectOne(String statement, Object parameter) {
return this.sqlSessionProxy.<T> selectOne(statement, parameter);
} /**
* {@inheritDoc}
*/
@Override
public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
return this.sqlSessionProxy.<K, V> selectMap(statement, mapKey); //而且sql执行大部分都是通过代理类来调用,所以关键就是这个内部类
}
private class SqlSessionInterceptor implements InvocationHandler { //这个就是内部类,实现了InvocationHandler接口,因为要通过代理方式完成关闭连接
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = getSqlSession(
SqlSessionTemplate.this.sqlSessionFactory,
SqlSessionTemplate.this.executorType,
SqlSessionTemplate.this.exceptionTranslator);
try {
Object result = method.invoke(sqlSession, args); //这里执行被代理的方法
if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
// force commit even on non-dirty sessions because some databases require
// a commit/rollback before calling close()
sqlSession.commit(true);
}
return result;
} catch (Throwable t) {
Throwable unwrapped = unwrapThrowable(t);
if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
// release the connection to avoid a deadlock if the translator is no loaded. See issue #22
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory); //可以看到如果报错在catch语句中会关闭sqlsession,也就是我们刚刚分析的一系列类最终关闭Connection
sqlSession = null;
Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw unwrapped;
} finally {
if (sqlSession != null) {
closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);//如果不报错,finally也关闭sqlsession
}
}
}
} }
spring一般生成SqlSessionTemplate用来实现SqlSession接口,可以把SqlSessionTemplate看成是SqlSession,在这个类中通过代理来关闭session,所以就不需要我们手动去执行close方法
public static void closeSqlSession(SqlSession session, SqlSessionFactory sessionFactory) {
notNull(session, NO_SQL_SESSION_SPECIFIED);
notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED); SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
if ((holder != null) && (holder.getSqlSession() == session)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Releasing transactional SqlSession [" + session + "]");
}
holder.released();
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Closing non transactional SqlSession [" + session + "]");
}
session.close(); //关闭session
}
}
上面的代码就是SqlSessionUtils封装的关闭sqlsession的静态方法,因为是通过 import static 方法导入的,所以就不需要通过类名 SqlSessionUtils.closeSqlSession调用.
3.总结
mybatis 和 spring 是通过代理方式完成 connection连接的关闭.而且是通过jdk的代理.
mybatis 如何关闭connection的更多相关文章
- Mybatis 中获得 connection
转: Mybatis 中获得 connection 2012年07月30日 19:02:21 dqsweet 阅读数:13861 @Autowired private SqlSession sql ...
- [JDBC]你真的会正确关闭connection吗?
Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { conn = DriverManag ...
- DataUtils对Connection的获取、释放和关闭的操作学习
DataSourceUitls介绍 DataSourceUitls类位于org.springframework.jdbc.datasource包下,提供了很多的静态方法去从一个javax.sql.Da ...
- Mybaits 源码解析 (十二)----- Mybatis的事务如何被Spring管理?Mybatis和Spring事务中用的Connection是同一个吗?
不知道一些同学有没有这种疑问,为什么Mybtis中要配置dataSource,Spring的事务中也要配置dataSource?那么Mybatis和Spring事务中用的Connection是同一个吗 ...
- IBatis 2.x 和 MyBatis 3.0.x 的区别(从 iBatis 到 MyBatis)
从 iBatis 到 MyBatis,你准备好了吗? 对于从事 Java EE 的开发人员来说,iBatis 是一个再熟悉不过的持久层框架了,在 Hibernate.JPA 这样的一站式对象 / 关系 ...
- Mybatis原理分析之一:从JDBC到Mybatis
1.引言 本文主要讲解JDBC怎么演变到Mybatis的渐变过程,重点讲解了为什么要将JDBC封装成Mybaits这样一个持久层框架.再而论述Mybatis作为一个数据持久层框架本身有待改进之处. 2 ...
- ibatis 到 MyBatis区别(zz)
简介: 本文主要讲述了 iBatis 2.x 和 MyBatis 3.0.x 的区别,以及从 iBatis 向 MyBatis 移植时需要注意的地方.通过对本文的学习,读者基本能够了解 MyBatis ...
- iBatis 和MyBatis区别
从 iBatis 到 MyBatis ,你准备好了吗? 对于从事 Java EE 的开发人员来说,iBatis 是一个再熟悉不过的持久层框架了,在 Hibernate.JPA 这样的一站式对象 ...
- ibatis 到 MyBatis区别
http://blog.csdn.net/techbirds_bao/article/details/9235309 简介: 本文主要讲述了 iBatis 2.x 和 MyBatis 3.0.x 的区 ...
随机推荐
- 使用NPOI读取Excel数据并写入SQLite
首先,我们来建一个数据库,我们就叫Hello.db(不一定是db后缀,你可以sqlite,sqlite3,db3)都可以作为识别,然后往里面建一个空的表格,如下图所示 然后建一个Excel表格,往表格 ...
- (ES6)数据处理常用工具方法收集(更新状态: on)
1. 扁平数组转成tree结构(来源: StackOverflow的印度老哥写的) // Data Set // One top level comment var comments = [{ id: ...
- Python RSA操作
公钥加密.私钥解密 # -*- coding: utf-8 -*- import rsa # rsa加密 def rsaEncrypt(str): # 生成公钥.私钥 (pubkey, privkey ...
- 【Git】error: RPC failed; HTTP 413 curl 22 The requested URL returned error:413 Request Entity Too Large
error: RPC failed; HTTP 413 curl 22 The requested URL returned error:413 Request Entity Too Large fa ...
- 判断用户输入YES或NO
#!bin/bash#作者:liusingbon#功能:判断用户输入的是 Yes 或 NOread -p "Are you sure?[y/n]:" surecase $sure ...
- Ubuntu18 给terminal改个漂亮的命令行提示符
重新安装了VMware和Ubuntu,但是命令行提示符太单调,不美观,如何更改呢.于是在网上巴拉巴拉搜寻一番. 1.更改PS1环境变量,这俩都可以,我选择第一个: export PS1="\ ...
- 强化学习(Reinfment Learning) 简介
本文内容来自以下两个链接: https://morvanzhou.github.io/tutorials/machine-learning/reinforcement-learning/ https: ...
- 格式化你的git message
https://github.com/angular/angular.js/blob/f3377da6a748007c11fde090890ee58fae4cefa5/CONTRIBUTING.md# ...
- Flutter-常用插件庫
alibaba/flutter_boost:路由 install_plugin 2.0.0#app下载更新插件 audio_recorder: any #录音.播放 flutter_sound: ^1 ...
- React Native 中不用手点击,代码实现切换底部tabBar
参考:https://www.jianshu.com/p/02c630ed7725 tabBar1页面有按钮,点击切换到tabBar2 直接用this.props.navigation.navigat ...