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的更多相关文章

  1. Mybatis 中获得 connection

    转: Mybatis 中获得 connection 2012年07月30日 19:02:21 dqsweet 阅读数:13861   @Autowired private SqlSession sql ...

  2. [JDBC]你真的会正确关闭connection吗?

    Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { conn = DriverManag ...

  3. DataUtils对Connection的获取、释放和关闭的操作学习

    DataSourceUitls介绍 DataSourceUitls类位于org.springframework.jdbc.datasource包下,提供了很多的静态方法去从一个javax.sql.Da ...

  4. Mybaits 源码解析 (十二)----- Mybatis的事务如何被Spring管理?Mybatis和Spring事务中用的Connection是同一个吗?

    不知道一些同学有没有这种疑问,为什么Mybtis中要配置dataSource,Spring的事务中也要配置dataSource?那么Mybatis和Spring事务中用的Connection是同一个吗 ...

  5. IBatis 2.x 和 MyBatis 3.0.x 的区别(从 iBatis 到 MyBatis)

    从 iBatis 到 MyBatis,你准备好了吗? 对于从事 Java EE 的开发人员来说,iBatis 是一个再熟悉不过的持久层框架了,在 Hibernate.JPA 这样的一站式对象 / 关系 ...

  6. Mybatis原理分析之一:从JDBC到Mybatis

    1.引言 本文主要讲解JDBC怎么演变到Mybatis的渐变过程,重点讲解了为什么要将JDBC封装成Mybaits这样一个持久层框架.再而论述Mybatis作为一个数据持久层框架本身有待改进之处. 2 ...

  7. ibatis 到 MyBatis区别(zz)

    简介: 本文主要讲述了 iBatis 2.x 和 MyBatis 3.0.x 的区别,以及从 iBatis 向 MyBatis 移植时需要注意的地方.通过对本文的学习,读者基本能够了解 MyBatis ...

  8. iBatis 和MyBatis区别

    从  iBatis  到  MyBatis ,你准备好了吗? 对于从事 Java EE 的开发人员来说,iBatis 是一个再熟悉不过的持久层框架了,在 Hibernate.JPA 这样的一站式对象 ...

  9. ibatis 到 MyBatis区别

    http://blog.csdn.net/techbirds_bao/article/details/9235309 简介: 本文主要讲述了 iBatis 2.x 和 MyBatis 3.0.x 的区 ...

随机推荐

  1. js实现完整轮播

    1.封装一个简单的动画函数 function animate(obj,target,callback){ clearInterval(obj.timer);//清除定时器防止定时器重复添加 obj.t ...

  2. 常用技术blog

    淘宝核心系统团队 http://csrd.aliapp.com/ 淘宝搜索技术博客 http://www.searchtb.com 淘宝量子恒道官方博客 http://blog.linezing.co ...

  3. 010-流程控制 while 与 until 语句

    流程控制 while 与 until 语句 while循环是不定循环,也称作条件循环,只要条件成立,循环就一直继续.与for的固定循环不同 until只要条件不成立,循环就一直继续 #!/bin/ba ...

  4. zookeeper分布式之学习搭建

    一.下载: 下载地址:https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/  下载解压到 C:\Users\Administrator\Desk ...

  5. Linux之文件内容查阅

    1. 直接查看文件内容 (1)cat命令,由第一行开始显示文件内容 -b,列出行号,仅显示出非空白行,空白行不标行号 -n,列出行号,空白行也会标行号 (2)tac命令,由最后一行到第一行反向在屏幕上 ...

  6. pandas 的axis参数的理解

    # pandas的axis参数怎样理解? # axis=0 或者 "index": # 如果是单行操作,就指的是某一行 # 如果是聚合操作,指的是跨行cross rows # ax ...

  7. HC-42蓝牙模块-nRF52832-数传蓝牙

    资料下载地址:链接:https://pan.baidu.com/s/1RRajrI5NvNY8tRVuYbOTug    提取码:31ho 我的蓝牙模块淘宝购买地址:https://detail.tm ...

  8. Centos logrotate截断tomcat日志文件

    1. 设置logrotate轮转日志文件 tomcat日志目录:/usr/local/tomcat/apache-tomcat-8.5.34/logs /etc/logrotate.d/目录下创建to ...

  9. python-jsonpath、findall返回值提取

    findall import re """ "d"表示取数字0-9, "D"表示不要数字, "w"在正则里面代 ...

  10. 在 centos7.5 使用 DockerFile 构建镜像时报错 "Error parsing reference:"microsoft/dotnet:2.2-aspnetcore-runtime AS base"is not a valid repository/tag: invalid reference format"

    运行 dockerfile 时报出的错误 FROM microsoft/dotnet:2.2-aspnetcore-runtime AS base Error parsing reference: & ...