Mybatis SqlSessionFactory与SqlSession详细讲解

作者:氵奄不死的鱼 时间:2021-12-24 22:42:56 

SqlssionFactory

1.SqlSessionFactory是MyBatis的关键对象,它是个单个数据库映射关系经过编译后的内存镜像。

2.SqlSessionFactory对象的实例可以通过SqlSessionFactoryBuilder对象类获得,而SqlSessionFactoryBuilder则可以从XML配置文件或一个预先定制的Configuration的实例构建出SqlSessionFactory的实例。

3.每一个MyBatis的应用程序都以一个SqlSessionFactory对象的实例为核心。

4.SqlSessionFactory是线程安全的,SqlSessionFactory一旦被创建,应该在应用执行期间都存在。在应用运行期间不要重复创建多次,建议使用单例模式。

5.SqlSessionFactory是创建SqlSession的工厂。

SqlSessionFactory接口源码如下所示

package org.apache.ibatis.session;
import java.sql.Connection;
public interface SqlSessionFactory {
 SqlSession openSession();//这个方法最经常用,用来创建SqlSession对象。
 SqlSession openSession(boolean autoCommit);
 SqlSession openSession(Connection connection);
 SqlSession openSession(TransactionIsolationLevel level);
 SqlSession openSession(ExecutorType execType);
 SqlSession openSession(ExecutorType execType, boolean autoCommit);
 SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
 SqlSession openSession(ExecutorType execType, Connection connection);
 Configuration getConfiguration();
}

创建SqlSessionFactory

.mybatis框架主要是围绕着SqlSessionFactory进行的,创建过程大概如下:

就从mybatis默认实现的MybatisAutoConfiguration来看看

@Bean
 @ConditionalOnMissingBean
 public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
   //创建SqlSessionFactoryBean对象
    SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
     //设置数据源
   factory.setDataSource(dataSource);
   factory.setVfs(SpringBootVFS.class);
   if (StringUtils.hasText(this.properties.getConfigLocation())) {
    //mybatis ,Xml配置文件路径
       、factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
   }
     //应用配置文件
   applyConfiguration(factory);
     //Mybatis额外的配置文件
   if (this.properties.getConfigurationProperties() != null) {
     factory.setConfigurationProperties(this.properties.getConfigurationProperties());
   }
     //设置mybatis *
   if (!ObjectUtils.isEmpty(this.interceptors)) {
     factory.setPlugins(this.interceptors);
   }
   ···
     //设置*mapper.xml扫描路径
   if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
     factory.setMapperLocations(this.properties.resolveMapperLocations());
   }
   ····
       //获取创建SqlSessionFactoryBean对象
   return factory.getObject();
 }

经过一系列设置创建出SqlSessionFactory

注意仅有当数据源只有一个实现时,MybatisAutoConfiguration才会生效,如果时多数据源的情况下,那么需要自己编写定义SqlSessionFactory的创建逻辑

SqlSessionTemplate

SqlSessionTemplate是线程安全的,生命周期由spring管理的,同spring事务一起协作来保证真正执行的SqlSession是在spring的事务中的一个SqlSession的实现类

创建SqlSessionTemplate

@Bean
 @ConditionalOnMissingBean
 public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
   ExecutorType executorType = this.properties.getExecutorType();
   if (executorType != null) {
     return new SqlSessionTemplate(sqlSessionFactory, executorType);
   } else {
     return new SqlSessionTemplate(sqlSessionFactory);
   }
 }

SqlSessionTemplate是作为一个bean被spring管理的

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是对sqlSession做的代理

处理类是SqlSessionInterceptor

Mybatis SqlSessionFactory与SqlSession详细讲解

SqlSessionTemplate继承自SqlSession,实现了sqlSession的所有操作

@Override
 public int insert(String statement, Object parameter) {
   return this.sqlSessionProxy.insert(statement, parameter);
 }
·········

可以看出来,SqlSessionTemplate就是对SqlSession套了个壳子,具体实现还是有代理的sqlSessionProxy去执行

接下类进入

SqlSessionInterceptor

@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;
     }
 }

先获取一个sqlSession,这里也是sqlSession线程安全的原因

getSqlSession方法拿到DefaultSqlSession实例,getSqlSession方法里面处理了sqlSession的线程安全问题(通过ThreadLocal实现)。

SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
   SqlSession session = sessionHolder(executorType, holder);
   if (session != null) {
     return session;
   }
   LOGGER.debug(() -> "Creating a new SqlSession");
   session = sessionFactory.openSession(executorType);
   registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);

sqlSession与线程绑定,如果当前线程未绑定sqlSession,会创建并绑定。保证了一个sqlSession一定只能被一个线程使用。

另外如果在一个事务下,那么肯定是在同一个线程,事务内的操作会共用一个sqlSession,并且,每一步操作完毕之后不会自动提交事务。

SqlSession

1.SqlSession是MyBatis的关键对象,是执行持久化操作的独享,类似于JDBC中的Connection。

2.它是应用程序与持久层之间执行交互操作的一个单线程对象,也是MyBatis执行持久化操作的关键对象。

3.SqlSession对象完全包含以数据库为背景的所有执行SQL操作的方法,它的底层封装了JDBC连接,可以用SqlSession实例来直接执行被映射的SQL语句。

4.每个线程都应该有它自己的SqlSession实例。

5.SqlSession的实例不能被共享,同时SqlSession也是线程不安全的,绝对不能讲SqlSeesion实例的引用放在一个类的静态字段甚至是实例字段中。也绝不能将SqlSession实例的引用放在任何类型的管理范围中,比如Servlet当中的HttpSession对象中。

6.使用完SqlSeesion之后关闭Session很重要,应该确保使用finally块来关闭它。

package org.apache.ibatis.session;
import java.io.Closeable;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.executor.BatchResult;
public interface SqlSession extends Closeable {
 <T> T selectOne(String statement);
 <T> T selectOne(String statement, Object parameter);
 <E> List<E> selectList(String statement);
 <E> List<E> selectList(String statement, Object parameter);
 <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);
 <K, V> Map<K, V> selectMap(String statement, String mapKey);
 <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);
 <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);
 void select(String statement, Object parameter, ResultHandler handler);
 void select(String statement, ResultHandler handler);
 void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);
 int insert(String statement);
 int insert(String statement, Object parameter);
 int update(String statement);
 int update(String statement, Object parameter);
 int delete(String statement);
 int delete(String statement, Object parameter);
 void commit(); void commit(boolean force);
 void rollback();
 void rollback(boolean force);
 List<BatchResult> flushStatements();
 void close();
 void clearCache();
 Configuration getConfiguration();
 <T> T getMapper(Class<T> type);
 Connection getConnection();
}

创建一个SqlSession

看了前面我们知道了sqlSession通过SqlSessionTemplate进行创建的

org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSessionFromDataSource

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
   Transaction tx = null;
   try {
     final Environment environment = configuration.getEnvironment();
     final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
     tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
     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();
   }
 }

创建一个事务,创建一个Executor,构造DefaultSqlSession

public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
   this.configuration = configuration;
   this.executor = executor;
   this.dirty = false;
   this.autoCommit = autoCommit;
 }

dirty字段代表如果在在未提交之前有更新操作,会被更新未true,这时调用sqlSession的commit/rollbacl方法

调用 executor.commit都传的是true

@Override
 public void commit(boolean force) {
   try {
     executor.commit(isCommitOrRollbackRequired(force));
     dirty = false;
   } catch (Exception e) {
     throw ExceptionFactory.wrapException("Error committing transaction.  Cause: " + e, e);
   } finally {
     ErrorContext.instance().reset();
   }
 }

后续sqlSession的增删改查操作都通过executor完成,executor后面再继续研究

SqlSession生命周期

如果说SqlSessionFactory相当于数据库连接池,那么SqlSession就相当于一个数据库连接(Connection对象),

你可以在一个事务里面执行多条SQL,然后通过它的commit、rollback等方法,提交或者回滚事务。所以它应该存活在一个业务请求中,

处理完整个请求后,应该关闭这条连接,让它归还给SqlSessionFactory,否则数据库资源就很快被消耗精光,系统应付瘫痪,所以用try&hellip;catch&hellip;fanally语句来保证其正确关闭。

实际上MyBatis整合springBoot的情况下,SqlSession对象和线程进行绑定,对象本身可以循环被一个线程反复使用,但是依然保证了线程安全,在事务提交/回滚需要清理缓存,交换连接给数据库连接池

来源:https://blog.csdn.net/qq_37436172/article/details/127601927

标签:Mybatis,SqlSessionFactory,SqlSession
0
投稿

猜你喜欢

  • ShardingSphere jdbc集成多数据源的实现步骤

    2023-11-25 07:54:56
  • 使用Java桥接模式打破继承束缚优雅实现多维度变化

    2023-08-23 09:00:34
  • 基于java构造方法Vector删除元素源码分析

    2023-11-25 14:54:45
  • 关于@ConditionalOnProperty的作用及用法说明

    2023-11-24 02:39:19
  • 通过实例解析Spring argNames属性

    2023-09-14 10:43:13
  • spring cloud gateway如何获取请求的真实地址

    2023-11-28 20:20:12
  • Java虚拟机JVM性能优化(三):垃圾收集详解

    2021-10-16 10:38:49
  • 浅谈java中String StringBuffer StringBuilder的区别

    2023-11-29 13:34:40
  • c# socket编程udp客户端实现代码分享

    2023-06-16 05:03:31
  • 关于C#中的Invoke示例详解

    2023-06-20 10:17:14
  • JAVA操作MongoDB数据库实例教程

    2023-11-18 13:22:27
  • java使用IO流对数组排序实例讲解

    2023-09-04 02:24:19
  • Java序列化JSON丢失精度问题的解决方法(修复Long类型太长)

    2022-10-15 00:01:34
  • Spring基于注解的缓存声明深入探究

    2023-01-20 13:26:06
  • SpringBoot文件分片上传教程

    2023-07-21 21:08:40
  • JAVA8 十大新特性详解

    2023-07-02 10:03:27
  • java HttpClient传输json格式的参数实例讲解

    2023-08-08 13:21:26
  • 通过Docker启动Solace并在Spring Boot通过JMS整合Solace的操作方法

    2023-07-11 09:52:28
  • Java Vector和ArrayList的异同分析及实例讲解

    2023-12-03 17:27:10
  • Java IO之File 类详解

    2023-08-07 20:02:12
  • asp之家 软件编程 m.aspxhome.com