注意:为事务管理器指定的 DataSource 必须和用来创建 SqlSessionFactoryBean 的是同一个数据源,否则事务管理器就无法工作了。 why?

 

一 、mybatis单独使用

构建SqlSessionFactory

String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

该处返回的是一个DefaultSqlSessionFactory ,构建过程不是本篇的重点。

从 SqlSessionFactory 中获取 SqlSession

try (SqlSession session = sqlSessionFactory.openSession()) {
  Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
}

该处返回的是一个DefaultSqlSession, 分析关键步骤。

获取SqlSession 

DefaultSqlSessionFactory

private SqlSession openSessionFromConnection(ExecutorType execType, Connection connection) {
    try {
      boolean autoCommit;
      try {
        autoCommit = connection.getAutoCommit();
      } catch (SQLException e) {
        // Failover to true, as most poor drivers
        // or databases won't support transactions
        autoCommit = true;
      }      
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      final Transaction tx = transactionFactory.newTransaction(connection);
      final Executor executor = configuration.newExecutor(tx, execType);
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

可以看出,enviroment中获取了TranSactionFactory ,接着有从TransactionFactory中获取了Transaction, 然后根据Transaction构建了Executor (默认为SimpleExecutor),然后根据executor构建出了DefaultSqlSession 。这个TranSactionFactory和Transaction非常关键.

执行sql,获取连接

会发现, 获取连接最终委派给了Transaction的getConnection方法

二、 mybatis整合spring使用,如何使用不做分析,只分析

spring.xml 配置

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
</bean>

mpper类 

public interface UserMapper {
  @Select("SELECT * FROM users WHERE id = #{userId}")
  User getUser(@Param("userId") String userId);
} 

mapper.xml 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.mybatis.example.BlogMapper">
  <select id="selectBlog" resultType="Blog">
    select * from Blog where id = #{id}
  </select>
</mapper>

 简单使用

try (SqlSession session = sqlSessionFactory.openSession()) {
  BlogMapper mapper = session.getMapper(BlogMapper.class);
  Blog blog = mapper.selectBlog(101);
}

 这里只分析SqlSessionFactoryBean, 通过查看源码可以发现, 该类的层次结构如下:

 

该类实现了FactoryBean(一旦某个bean实现了此接口,那么通过getBean方法获取bean时其实就是此类,getObject返回的实例).废话不多说,直接上代码

@Override
  public SqlSessionFactory getObject() throws Exception {
    if (this.sqlSessionFactory == null) {
      afterPropertiesSet();
    }

    return this.sqlSessionFactory;
  }
 @Override
  public void afterPropertiesSet() throws Exception {
    not
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,下面是基于Spring Boot的多数据源切换,通过事务管理器对多个数据源切换进行事务管理,手动添加事务应用于一个list集合插入到DB1和DB2,其中一个DB失败则对两个DB的事务都进行回滚的详细代码: 首先,在application.yml文件中配置两个数据源,例如: ``` spring: datasource: test1: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: root test2: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: root ``` 然后,创建两个数据源的配置类,例如: ``` @Configuration @MapperScan(basePackages = "com.example.demo.mapper.test1", sqlSessionTemplateRef = "test1SqlSessionTemplate") public class Test1DataSourceConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.test1") public DataSource test1DataSource() { return DataSourceBuilder.create().build(); } @Bean public SqlSessionFactory test1SqlSessionFactory(@Qualifier("test1DataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/test1/*.xml")); return bean.getObject(); } @Bean public SqlSessionTemplate test1SqlSessionTemplate(@Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception { return new SqlSessionTemplate(sqlSessionFactory); } @Bean(name = "test1TransactionManager") public DataSourceTransactionManager test1TransactionManager(@Qualifier("test1DataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } } @Configuration @MapperScan(basePackages = "com.example.demo.mapper.test2", sqlSessionTemplateRef = "test2SqlSessionTemplate") public class Test2DataSourceConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.test2") public DataSource test2DataSource() { return DataSourceBuilder.create().build(); } @Bean public SqlSessionFactory test2SqlSessionFactory(@Qualifier("test2DataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/test2/*.xml")); return bean.getObject(); } @Bean public SqlSessionTemplate test2SqlSessionTemplate(@Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception { return new SqlSessionTemplate(sqlSessionFactory); } @Bean(name = "test2TransactionManager") public DataSourceTransactionManager test2TransactionManager(@Qualifier("test2DataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } } ``` 其中,@MapperScan注解用于指定Mapper接口的扫描路径,@Qualifier注解用于指定注入的Bean名称。 接着,创建DAO层接口和实现类,例如: ``` public interface Test1Mapper { int insert(Test1 test1); } public interface Test2Mapper { int insert(Test2 test2); } @Repository public class Test1MapperImpl implements Test1Mapper { @Autowired private SqlSessionTemplate test1SqlSessionTemplate; @Override public int insert(Test1 test1) { return test1SqlSessionTemplate.insert("com.example.demo.mapper.test1.Test1Mapper.insert", test1); } } @Repository public class Test2MapperImpl implements Test2Mapper { @Autowired private SqlSessionTemplate test2SqlSessionTemplate; @Override public int insert(Test2 test2) { return test2SqlSessionTemplate.insert("com.example.demo.mapper.test2.Test2Mapper.insert", test2); } } ``` 然后,创建Service层接口和实现类,例如: ``` public interface TestService { void insert(List<Test1> test1List, List<Test2> test2List) throws Exception; } @Service public class TestServiceImpl implements TestService { @Autowired private Test1Mapper test1Mapper; @Autowired private Test2Mapper test2Mapper; @Autowired @Qualifier("test1TransactionManager") private PlatformTransactionManager test1TransactionManager; @Autowired @Qualifier("test2TransactionManager") private PlatformTransactionManager test2TransactionManager; @Override @Transactional(rollbackFor = Exception.class) public void insert(List<Test1> test1List, List<Test2> test2List) throws Exception { TransactionStatus test1TransactionStatus = null; TransactionStatus test2TransactionStatus = null; DefaultTransactionDefinition test1TransactionDefinition = new DefaultTransactionDefinition(); DefaultTransactionDefinition test2TransactionDefinition = new DefaultTransactionDefinition(); test1TransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); test2TransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); try { test1TransactionStatus = test1TransactionManager.getTransaction(test1TransactionDefinition); for (Test1 test1 : test1List) { test1Mapper.insert(test1); } test2TransactionStatus = test2TransactionManager.getTransaction(test2TransactionDefinition); for (Test2 test2 : test2List) { test2Mapper.insert(test2); } test1TransactionManager.commit(test1TransactionStatus); test2TransactionManager.commit(test2TransactionStatus); } catch (Exception e) { if (test1TransactionStatus != null) { test1TransactionManager.rollback(test1TransactionStatus); } if (test2TransactionStatus != null) { test2TransactionManager.rollback(test2TransactionStatus); } throw e; } } } ``` 其中,@Transactional注解用于指定事务管理器和回滚策略,test1TransactionManager和test2TransactionManager分别对应不同的数据源事务管理器,test1TransactionStatus和test2TransactionStatus分别对应不同的数据源事务状态。 最后,创建Controller层接口和实现类,例如: ``` @RestController public class TestController { @Autowired private TestService testService; @PostMapping("/test") public void test(@RequestBody TestRequest request) throws Exception { testService.insert(request.getTest1List(), request.getTest2List()); } } public class TestRequest { private List<Test1> test1List; private List<Test2> test2List; // getter和setter方法省略 } ``` 至此,就完成了基于Spring Boot的多数据源切换,通过事务管理器对多个数据源切换进行事务管理,手动添加事务应用于一个list集合插入到DB1和DB2,其中一个DB失败则对两个DB的事务都进行回滚的代码实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值