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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • linux直接运行py文件_linux的系统调用

    linux直接运行py文件_linux的系统调用python下编译py成pyc和pyo(文件加密)需要注意的是,编译成pyc或者pyo文件后需要将命名改成与源Python命名一致,将其放在源目录下,虽然其他python文件调用pyd时显示不能检测到该模块,但实际上可以运行。由于pyc的编译收到python版本的影响,所以当将编译后的pyc迁移到另一台电脑中时,最好保持python环境一致。将python文件.py编译成pyc二进制文件:pyt…

    2025年8月7日
    3
  • docker-compose 集群_docker集群管理

    docker-compose 集群_docker集群管理前言实际工作中我们部署一个应用,一般不仅仅只有一个容器,可能会涉及到多个,比如用到数据库,中间件MQ,web前端和后端服务,等多个容器。我们如果一个个去启动应用,当项目非常多时,就很难记住了,所有

    2022年7月30日
    9
  • Kali 2.0 使用 Reaver 的注意事项[通俗易懂]

    Kali 2.0 使用 Reaver 的注意事项[通俗易懂]1、刚一开始使用这条命令airmon-ngstartwlan0就可以开始了,需要注意的是,在Kali2.0里开启的不再是mon0了,而是wlan0mon,所以不要和Kali1.X的版本代码混淆2、Kali1.X的命令无效在Kali2.0中必须自己手动开启网卡的监听模式,所以在执行完上面之后,需要自己手动开启监听模式ifconfigwlan0mondowniwconfig

    2022年5月9日
    154
  • 前端对接口是什么意思_接口返回json格式

    前端对接口是什么意思_接口返回json格式什么是JSON?

    2022年10月12日
    2
  • 关于大学毕业 总结的文章2000_如何写大学学期总结

    关于大学毕业 总结的文章2000_如何写大学学期总结本文十天后设置为粉丝可见,喜欢的提前关注不要白嫖请点赞不要白嫖请点赞不要白嫖请点赞文中提到的书我都有电子版,可以评论邮箱发给你。文中提到的书我都有电子版,可以评论邮箱发给你。文中提到的书我都有电子版,可以评论邮箱发给你。本篇文章应该算是Java后端开发技术栈的,但是大部分是基础知识,所以我觉得对任何方向都是有用的。1、数据结构数据结构是计算机存储、…

    2025年9月21日
    5
  • DSP FPGA_fpga oddr

    DSP FPGA_fpga oddr序曲:今年(2021年)7月4日至24日,我指导电子信息工程专业18级的12位同学进行小学期的课程实践。多年以来,我一直想鼓励同学们基于国产的FPGA进行设计和实践,今年终于进行了大胆的尝试。为了课程实践顺利进行,我和12位同学提前了近2个月进行准备。从5月17日(周一)早晨8:00第一次讨论会开始,我和12位同学每周都坚持查阅、学习国内FPGA的资料,每周开讨论会研讨学习进展。研讨会辗转于海空学院会议室、控制学院会议室、新图书馆研讨室……由于同学们课多且分散,同时我的其他…

    2022年10月9日
    5

发表回复

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

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