当前位置:首页 >综合 >如何扒开 SqlSession 的外衣 会把事务交给容器来管理

如何扒开 SqlSession 的外衣 会把事务交给容器来管理

2024-06-30 16:51:54 [百科] 来源:避面尹邢网

如何扒开 SqlSession 的何扒外衣

作者:田维常 运维 数据库运维 如果我们配置的是MANAGED,会把事务交给容器来管理,外衣比如JBOSS,何扒Weblogic。外衣因为我们是何扒本地跑的程序,如果配置成MANAGED就会不有任何事务。外衣

[[360740]]

老规矩,何扒先上案例代码,外衣我们按照这个案例一步一步的何扒搞定Mybatis源码。

如何扒开 SqlSession 的外衣 会把事务交给容器来管理

  1. public class MybatisApplication {  
  2.     public static final String URL = "jdbc:mysql://localhost:3306/mblog"; 
  3.     public static final String USER = "root"; 
  4.     public static final String PASSWORD = "123456"; 
  5.  
  6.     public static void main(String[] args) {  
  7.         String resource = "mybatis-config.xml"; 
  8.         InputStream inputStream = null; 
  9.         SqlSession sqlSession = null; 
  10.         try {  
  11.             inputStream = Resources.getResourceAsStream(resource); 
  12.             SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 
  13.             sqlSession = sqlSessionFactory.openSession(); 
  14.             UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 
  15.             System.out.println(userMapper.selectById(1)); 
  16.  
  17.         } catch (Exception e) {  
  18.             e.printStackTrace(); 
  19.         } finally {  
  20.             try {  
  21.                 inputStream.close(); 
  22.             } catch (IOException e) {  
  23.                 e.printStackTrace(); 
  24.             } 
  25.             sqlSession.close(); 
  26.         } 
  27.     } 

由于很多小伙伴在催,外衣说Mybatis源码系列好像何时才有下文了,何扒为此老田熬夜写了这篇。外衣

如何扒开 SqlSession 的外衣 会把事务交给容器来管理

 

如何扒开 SqlSession 的外衣 会把事务交给容器来管理

继续开撸~~

  1. SqlSession sqlSession = sqlSessionFactory.openSession(); 

前面那篇文章已经分析了,何扒这里的外衣sqlSessionFactory其实就是DefaultSqlSessionFactory。

所以这里,何扒我们就从DefaultSqlSessionFactory里的openSession方法开始。

  1. public class DefaultSqlSessionFactory implements SqlSessionFactory {  
  2.  
  3.   private final Configuration configuration; 
  4.  
  5.   public DefaultSqlSessionFactory(Configuration configuration) {  
  6.     this.configuration = configuration; 
  7.   } 
  8.   //创建session,这个方法直接调用本类中的另外一个方法 
  9.   @Override 
  10.   public SqlSession openSession() {  
  11.     return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false); 
  12.   } 
  13.   //其实是调用这个方法 
  14.   private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {  
  15.     Transaction tx = null; 
  16.     try {  
  17.       //对应xml标签<environments> ,这个在配置文件解析的时候就已经存放到configuration中了。 
  18.       final Environment environment = configuration.getEnvironment(); 
  19.       final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment); 
  20.       tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit); 
  21.       //创建一个executor来执行SQL   
  22.       final Executor executor = configuration.newExecutor(tx, execType); 
  23.       //这里也说明了,为什么我们代码里的SqlSession是DefaultSqlSession 
  24.       return new DefaultSqlSession(configuration, executor, autoCommit); 
  25.     } catch (Exception e) {  
  26.       closeTransaction(tx); // may have fetched a connection so lets call close() 
  27.       throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e); 
  28.     } finally {  
  29.       ErrorContext.instance().reset(); 
  30.     } 
  31.   } 
  32.    
  33.     private TransactionFactory getTransactionFactoryFromEnvironment(Environment environment) {  
  34.     if (environment == null || environment.getTransactionFactory() == null) {  
  35.       return new ManagedTransactionFactory(); 
  36.     } 
  37.     return environment.getTransactionFactory(); 
  38.   } 

这个方法中的主要内容有:

 

下面我们就来逐个攻破。

创建事务Transaction

事务工厂类型可以配置为JDBC类型或者MANAGED类型。

JdbcTransactionFactory生产JdbcTransaction。

ManagedTransactionFactory生产ManagedTransaction。

如果配置的JDBC,则会使用Connection对象的commit()、rollback()、close()方法来管理事务。

如果我们配置的是MANAGED,会把事务交给容器来管理,比如JBOSS,Weblogic。因为我们是本地跑的程序,如果配置成MANAGED就会不有任何事务。

但是,如果我们项目中是Spring集成Mybatis,则没有必要配置事务,因为我们会直接在applicationContext.xml里配置数据源和事务管理器,从而覆盖Mybatis的配置。

创建执行器Executor

调用configuration的newExecutor方法创建Executor。

  1. final Executor executor = configuration.newExecutor(tx, execType); 
  2. //Configuration中 
  3. public Executor newExecutor(Transaction transaction, ExecutorType executorType) {  
  4.     executorType = executorType == null ? defaultExecutorType : executorType; 
  5.     executorType = executorType == null ? ExecutorType.SIMPLE : executorType; 
  6.     Executor executor; 
  7.     //第一步 
  8.     if (ExecutorType.BATCH == executorType) {  
  9.       executor = new BatchExecutor(this, transaction); 
  10.     } else if (ExecutorType.REUSE == executorType) {  
  11.       executor = new ReuseExecutor(this, transaction); 
  12.     } else {  
  13.       executor = new SimpleExecutor(this, transaction); 
  14.     } 
  15.     //第二步 
  16.     if (cacheEnabled) {  
  17.       executor = new CachingExecutor(executor); 
  18.     } 
  19.     //第三步 
  20.     executor = (Executor) interceptorChain.pluginAll(executor); 
  21.     return executor; 
  22.   } 

此方法分三个步骤。

第一步:创建执行器

Executor的基本类型有三种:

  1. public enum ExecutorType {  
  2.   SIMPLE, REUSE, BATCH 

SIMPLE为默认类型。

 

为什么要让抽象类BaseExecutor实现Executor接口,然后让具体实现类继承抽象类呢?

这就是模板方法模式的实现。

模板方法模式就是定义一个算法骨架,并允许子类为一个或者多个步骤提供实现。模板方法是得子类可以再不改变算法结构的情况下,重新定义算法的某些步骤。

抽象方法是在子类汇总实现的,每种执行器自己实现自己的逻辑,BaseExecutor最终会调用到具体的子类中。

抽象方法

  1. protected abstract int doUpdate(MappedStatement ms, Object parameter) throws SQLException; 
  2.  
  3. protected abstract List<BatchResult> doFlushStatements(boolean isRollback) throws SQLException; 
  4.  
  5. protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException; 
  6.  
  7. protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)  throws SQLException; 

第二步:缓存装饰

在上面代码中的第二步

  1. if (cacheEnabled) {  
  2.       executor = new CachingExecutor(executor); 

如果cacheEnabled=true,会用装饰器设计模式对Executor进行装饰。

第三步:插件代理缓存装饰完后,就会执行

  1. executor = (Executor) interceptorChain.pluginAll(executor); 

这里会对Executor植入插件逻辑。

比如:分页插件中就需要把插件植入的Executor

 

好了,到此,执行器创建的就搞定了。

创建DefaultSqlSession对象

把前面解析配置文件创建的Configuration对象和创建的执行器Executor赋给DefaultSqlSession中的属性。

  1. public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {  
  2.   this.configuration = configuration; 
  3.   this.executor = executor; 
  4.   this.dirty = false; 
  5.   this.autoCommit = autoCommit; 

到这里,SqlSession(DefaultSqlSession)对象就创建完毕。

总结

本文我们讲了如何创建SqlSession的几个步骤,最后我们获得一个DefaultSqlSession对象,里面包含了执行器Executor和配置对象Configuration。Executor是SQL的实际执行对象。Configuration里保存着配置文件内容。

本文源码分析的整个流程如下图:

本文转载自微信公众号「Java后端技术全栈」,可以通过以下二维码关注。转载本文请联系Java后端技术全栈公众号。

 

责任编辑:武晓燕 来源: Java后端技术全栈 SqlSession 程序Executor

(责任编辑:焦点)

    推荐文章
    热点阅读