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


相关推荐

  • java中main方法的作用

    java中main方法的作用main方法是我们学习Java语言学习的第一个方法,也是每个java使用者最熟悉的方法,每个Java应用程序都必须有且仅有一个main方法。在eclipse里可以使用输入main,在按住Alt+/的方式快速创建main方法。可以说main方法是最简单的方法,因为main方法几乎是固定不变得,除了String[]args可以写成Stringargs[],以及args的名称可以改变外,其它所有均不…

    2022年5月25日
  • armv8处理器有哪些_arm是精简指令集

    armv8处理器有哪些_arm是精简指令集ARMv8是ARM版本升级以来最大的一次改变,ARMv8的架构继承以往ARMv7与之前处理器技术的基础,除了现有的16/32bit的Thumb2指令支持外,也向前兼容现有的A32(ARM32bit)指令集,扩充了基于64bit的AArch64架构,除了新增A64(ARM64bit)指令集外,也扩充了现有的A32(ARM32bit)和T32(Thumb232bit)指令集;ARMv8拥有两种…

    2022年10月16日
  • C语言银行家算法

    C语言银行家算法算法简介银行家算法(Banker’sAlgorithm)是一个避免死锁(Deadlock)的著名算法,是由艾兹格·迪杰斯特拉在1965年为T.H.E系统设计的一种避免死锁产生的算法。它以银行借贷系统的分配策略为基础,判断并保证系统的安全运行。算法目的为了了解系统的资源分配情况,假定系统的任何一种资源在任意时刻只能被一个进程使用,任何进程已经占用的资源只能由进程自己释放,而不能由其他进…

    2022年6月14日
  • Mac突然连不上WiFi解决步骤「建议收藏」

    Mac突然连不上WiFi解决步骤「建议收藏」事件描述:上午用图书馆无线看电视过程中,莫名就网断了,开始以为是图书馆网问题,后来手机开热点也无法连接。去年刚买Mac时也出现过这种问题,后来换了主板,心慌还以为又要去修理了o(╯□╰)o 开始无用尝试部分: 1.打开设置-网络-位置,更改为自动 2.关机,立即同时按下command+option+R+P,听到三声后松手 解决步骤:移除网络配置和偏好文件 手动删除网络plist…

    2022年6月18日
  • gps运用了什么原理_北斗和gps频段区别

    gps运用了什么原理_北斗和gps频段区别GPS入门知识。

    2022年10月28日
  • 韦根36协议_韦根26协议

    韦根36协议_韦根26协议)ID[5]=DM;}RcvWG[0]=0;RcvWG[1]=0;RcvWG[2]=0;RcvEven=0;RcvOdd=0;CheckEven=0;CheckOdd=1;temp=0;Rcnt=0;RWGcnt=0;RCVOK=1;}}if(RCVOK)//读卡成功后,延时,再开始读下一次{EX0=0;for(i=200;i>0;i–)delay();EX0=1;}if(ClrDo…

    2022年11月2日

发表回复

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

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