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. vue中获取滚动table的可视页面宽度,调整表头与列对齐(每列宽度不都相同)

    mounted() { // 在mounted中监听表格scroll事件 this.$refs.scrollTable.addEventListener( 'scroll',(event) => ...

  2. Python 中Semaphore 信号量对象、Event事件、Condition

    Semaphore 信号量对象 信号量是一个更高级的锁机制.信号量内部有一个计数器而不像锁对象内部有锁标识,而且只有当占用信号量的线程数超过信号量时线程才阻塞.这允许了多个线程可以同时访问相同的代码区 ...

  3. 关于Mysql 修改密码的记录

    初次安装后完毕,使用管理员身份进入cmd界面, 输入" mysql -u root -p",出现"Enter password:",直接回车输入" s ...

  4. 树状数组求LIS模板

    如果数组元素较大,需要离散化. #include <iostream> #include <cstdio> #include <cstring> #include ...

  5. socket keepalive 服务端异常断线

    异常断线  客户端检测不到  没有重连

  6. index 索引

    1.创建表 drop table if exists kg_fk_user;create table kg_fk_user(id int,name string)row format delimite ...

  7. bzoj4238 & loj2881 电压 二分图判定+dfs树

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4238 https://loj.ac/problem/2881 题解 如果想要让每一条边都有电流 ...

  8. QQ输入法用户评价

    1.用户界面 用户界面简洁,并且可以随用户喜好自己更换,人性化,优化性比较大 2.记住用户选择 当输入一个字时,下一次输入这个拼音第一位的字就是上一次,或者使用次数最多的字.假如所使用的的字在后边,输 ...

  9. java: Set类及子类:TreeSet有序子类,HashSet无序子类:重复元素

    Set类及子类: TreeSet有序子类: HashSet无序(散列)子类 HashSet子类的内容是没有顺序的,单个元素也不会重复的(对象除外). Set<String> allSet ...

  10. 【bzoj4552】【Tjoi2016&Heoi2016】【NOIP2016模拟7.12】排序

    题目 在2016年,佳媛姐姐喜欢上了数字序列.因而他经常研究关于序列的一些奇奇怪怪的问题,现在他在研究一个难题,需要你来帮助他.这个难题是这样子的:给出一个1到n的全排列,现在对这个全排列序列进行m次 ...