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


相关推荐

  • 网络工程师考试大纲

    网络工程师考试大纲

    2021年7月25日
    66
  • python 多线程测试_【Python】多线程网站死链检测工具

    python 多线程测试_【Python】多线程网站死链检测工具最新作品,一个python写的多线程爬虫+链接检测,其实可以分开用。实测系统:30个线程(10个爬虫,20个检测)深度3MacOS64bit√CentOS64bit√Fedora1732bit√Windows764bit√思路:通过线程管理器,触发爬虫线程按照广度优先爬取链接,另一方面触发检测线程用来检测爬取的链接。爬过的链接如果正常不用再检测,否则需要再检测。第一天,大致设计,…

    2022年7月23日
    14
  • 二叉树的非递归遍历

    二叉树的非递归遍历

    2022年1月29日
    45
  • 常用邮件服务器软件(邮件服务器软件哪个好)

    常见邮件服务器软件1.微软ExchangeServer[3]​2.TurboMail3.Coremail4.U-Mail5.lifecube网络宝邮件服务器6.MDaemonServer7.WinWebMail8.IceWarp/MerakMailServer9.LotusDomino/Notes10.Postfix/Sendmail/Qm…

    2022年4月17日
    61
  • 业务测试用例模版与大数据测试用例模板

    业务测试用例模版与大数据测试用例模板前言:分享下业务测试用例模版与大数据测试用例模板业务测试用例模版与大数据测试用例模板一、业务测试用例模板二、业务测试用例模板一、业务测试用例模板需要下载模板请点击:业务测试用例模板下载二、业务测试用例模板需要下载模板请点击:大数据测试用例模板下载…

    2022年7月17日
    18
  • C语言xml配置文件换行的方法[通俗易懂]

    C语言xml配置文件换行的方法[通俗易懂]/options参数设定成XML_PARSE_NOBLANKS,否则的话是不会在结点后面添加回车的。/doc=xmlReadFile(docname,“UTF-8”,XML_PARSE_NOBLANKS);//读取xml文件时忽略空格/把xmlSaveFormatFile的format参数修改成1,否则在使用xmlReadFile打开的xml文件时,在生成的xml文件里是会把所有的结点都放到一行里显示。/xmlSaveFormatFile(docname,doc,1);以上内容

    2022年7月12日
    16

发表回复

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

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