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 的区 ...
随机推荐
- k3 cloud提示超出产品激活有效期
k3 cloud提示超出产品激活有效期,请联系系统管理员登录管理中心进行产品激活(激活路径:许可中心-许可管理-产品激活) 首先进入管理中心:一次点击许可中心-产品激活 复制激活串号并点击金蝶正版验证 ...
- Docker守护式容器的创建和登录
创建守护式容器 如果对于一个需要长期运行的容器来说,我们可以创建一个守护式容器(后台运行的容器). 创建(-d)并运行(-i)守护式容器命令如下(容器名称不能重复): docker run -id - ...
- 解密Qt安装目录的结构
http://c.biancheng.net/view/3866.html 了解 Qt 安装目录的结构虽然不是编程必须的,但是它能练就我们的内功,让我们对 Qt 的编程环境了如指掌.Windows 和 ...
- bzoj4326: NOIP2015 运输计划(二分+LCA+树上差分)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4326 题目大意:有一颗含有n个顶点的树,每两个点之间有一个边权,现在有m个运输计划,每个 ...
- AlphaStar: Mastering the Real-Time Strategy Game StarCraft II 博客要点
original blog: https://deepmind.com/blog/alphastar-mastering-real-time-strategy-game-starcraft-ii S ...
- UVa11538 A Chess Queen
A Chess Queen Problem A Chess Queen Input: Standard Input Output: Standard Output You probably know ...
- Kafka---系统学习
1.Topics 1.1.Topic 就是 数据主题: 1.2.作用:数据记录 发布的地方,用来 区分 业务系统: 1.3.每个Topic 可以有多个 消费者 订阅它的数据: 1.4.每个T ...
- axios中put和patch的区别(都是update , put是需要提交整个对象资源,patch是可以修改局部)
patch方法用来更新局部资源,这句话我们该如何理解? 假设我们有一个UserInfo,里面有userId, userName, userGender等10个字段.可你的编辑功能因为需求,在某个特别的 ...
- 【NOIP2016A组模拟7.13】亚瑟王之宫
题目 分析 我们定义\(dis_{x,y,x1,y2}\)表示\((x,y)\)到\((x1,y1)\)的距离.这个用spfa求. 接着,枚举两个集合点\((x,y).(x1,y1)\), 得出这两个 ...
- 适用于填空题出题 的随机算法 PHP
<?php #寻找一个满足给定空数和题数要求的随机方案,事先需统计出每题空格数情况队列$m_blk,以及这些题分别有多少个$m_que. #以下算法将找到一个随机方案,若未找到将返回假值,如果不 ...