mybatis:Creating a new SqlSession Closing non transactional SqlSession[通俗易懂]

mybatis:Creating a new SqlSession Closing non transactional SqlSession[通俗易懂]CreatinganewSqlSessionSqlSession[org.apache.ibatis.session.defaults.DefaultSqlSession@42607e80]wasnotregisteredforsynchronizationbecausesynchronizationisnotactiveJDBCConnection[com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@56ebc6bb]w.

大家好,又见面了,我是你们的朋友全栈君。

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@42607e80] was not registered for synchronization because synchronization is not active
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@56ebc6bb] will not be managed by Spring
==>  Preparing: SELECT app_id, app_code, app_name FROM t_sys_application 
==> Parameters: 
<==    Columns: app_id, app_code, app_name
<==      Total: 2
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@42607e80]

在springboot配置了mybatis、Druid数据库连接池后,发现每次sql执行mybatis都:

Creating a new SqlSession 
Closing non transactional SqlSession

以为数据库连接池没有生效,就去看了一下。直接上结论:

        mybatis的sqlSession和数据库连接池中维护的数据库连接Collection不是同一个概念,SqlSession是mybatis框架中的概念,是mybatis持久层框架的顶层API。在sqlSession中操作数据库的时候会去获取collection,collection的获取是去连接池中取的!所以Creating a new SqlSession并不是每次都去创建了数据库新连接,底层使用的collection还是连接池提供的。至于每次事务执行sql,mybatis都Creating a new SqlSession而不是共享SqlSession,是为了保证sql会话独立避免发生脏数据,从而保证会话线程安全。

源码随笔:

org.mybatis.spring.SqlSessionUtils.getSqlSession():

  public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType,
      PersistenceExceptionTranslator exceptionTranslator) {

    notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
    notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);

    SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);

    SqlSession session = sessionHolder(executorType, holder);
    if (session != null) {
      return session;
    }

    LOGGER.debug(() -> "Creating a new SqlSession");
    //获取SqlSession
    session = sessionFactory.openSession(executorType);

    registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);

    return session;
  }

sessionFactory.openSession(executorType)的实现:DefaultSqlSessionFactory.openSession()

  @Override
  public SqlSession openSession(ExecutorType execType) {
    return openSessionFromDataSource(execType, null, false);
  }

  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      //通过Confuguration对象去获取Mybatis相关配置信息, Environment对象包含了数据源和事务的配置
      // execType为执行器类型,配置文件中定义
      // SimpleExecutor -- SIMPLE 就是普通的执行器。
      //ReuseExecutor -执行器会重用预处理语句(prepared statements)
      //BatchExecutor --它是批量执行器
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      //定义执行器,是对statement的封装
      final Executor executor = configuration.newExecutor(tx, execType);
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

得到SqlSession对象之后就可以利用SqlSession提供的方法进行CRUD操作了。Connection对象是在SqlSession对象创建之后进行CURD操作中创建的。深入查找之后找到在ManagedTransaction类中找到获取Connection对象的关键代码如下:

  protected void openConnection() throws SQLException {
    if (log.isDebugEnabled()) {
      log.debug("Opening JDBC Connection");
    }
    //dataSource 来源有三种,JndiDatasource,PooledDataSource,UnpooledDataSource,配置文件中定义
    this.connection = this.dataSource.getConnection();
    if (this.level != null) {
      this.connection.setTransactionIsolation(this.level.getLevel());
    }
  }

PooledDataSource和UnPooledDataSource的区别是PooledDataSource使用了连接池。为什么使用连接池呢?因为创建一个Connection对象的过程,在底层就相当于和数据库建立的通信连接,在建立通信连接的过程,消耗了非常多的时间,而往往我们建立连接后(即创建Connection对象后),就执行一个简单的SQL语句,然后就要抛弃掉,这是一个非常大的资源浪费!mybatis针对这一个问题提出的PooledDataSource使用了连接池。

补充:

在MyBatis中,多个SqlSession可以复用同一个Connection。

在service方法上添加@Transactional 开启事务,把数据库事务委托给spring管理,这样多个sql执行就在同一事务中了,即同一个SqlSession中。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/149063.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • css只设置背景图片半透明,css 设置背景色或图片半透明的方法(图文)

    css只设置背景图片半透明,css 设置背景色或图片半透明的方法(图文)css设置背景颜色半透明或者设置背景图片半透明,但有的时候只需要设置最外层的div为半透明里面的内容不需要设置下面介绍一下这两种情况1.设置html元素你面内颜色和图片都为半透明状态支持IE浏览器.bg1{background:#000;opacity:0.5;filter:progid:DXImageTransform.Microsoft.alpha(opacity=50);}2.设置htm…

    2022年7月16日
    22
  • 计算机的139 135 445端口关闭_系统端口设置在哪里

    计算机的139 135 445端口关闭_系统端口设置在哪里近期永恒之蓝勒索病毒迅速传播,基本上都是通过135,137,138,139,445等端口入侵,关闭445135137138139端口是有效预防入侵的方式之一,同时更新微软最新补丁,及时备份重要数据,才能从容应对病毒侵袭,下面重点介绍关闭135,137,138,139,445端口方法。关闭445135137138139端口方法教程方法一:方法二:1、打开Windows徽标(开始菜单)…

    2022年8月31日
    7
  • 单片机最小系统的通俗易懂讲解

    单片机最小系统的通俗易懂讲解我是一名单片机工程师,下面的讲解你参考一下.51单片机共有40只引脚.下面这个就是最小系统原理图,就是靠这四个部分,这个单片机就可以运行起来了.(看下面的数字标记,1234)我们来一,一讲解一下:1第一部分:电源组(标记为1的部分)40脚接电源5V(右上角),20脚接电源负极(左下角),在单片机里面,负极也可以叫GND或者”地”,我们在单片机的应用中,习惯说负极为”地”,上面GND就…

    2022年6月5日
    46
  • Idea激活码最新教程2019.3.1版本,永久有效激活码,亲测可用,记得收藏

    Idea激活码最新教程2019.3.1版本,永久有效激活码,亲测可用,记得收藏Idea 激活码教程永久有效 2019 3 1 激活码教程 Windows 版永久激活 持续更新 Idea 激活码 2019 3 1 成功激活

    2025年5月24日
    6
  • redis slowlog

    redis slowlog

    2021年10月16日
    58
  • 转换流实现了字节流和字符流之间的互相转换_java输出流输出文件

    转换流实现了字节流和字符流之间的互相转换_java输出流输出文件1、转换流–OutputStreamWriter简介:OutputStreamWriterextendsWriter,转换流也是继承自超类Writer,因此可以使用Writer中的共性方法:write(intc),write(char[]ch),…,flash(),close(),…OutputStreamWriter常用的构造方法:1)OutputStreamWr…

    2025年9月1日
    6

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号