依赖版本

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.0</version>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.2.1</version>
</dependency>

问题1:

异常重现步骤: 1. 独立库A,独立库B,在其中分别建立同名表table1 2. 配置多数据源,分别配置库A与库B 3. 使用@Transactional注解向库B的table1中写入数据

异常表现: 打印结果显示写入成功后,库A与库B中均无数据。

问题2:

异常重现步骤: 1. 在问题1的库A中建立table2_1,库B中建立table2_2,二者同名,但字段不同。 2. table2_2中设定外键,外键引用table1的字段 3. 使用@Transactional注解,向table1与table2_2中依次写入数据

异常表现: 写入table2_2异常,无法找到字段写入失败

以上问题在不加事务时均不会出现。

建表代码:

CREATE TABLE `table1`  (
  `id` int NOT NULL,
  `key` varchar(255) NULL COMMENT '被引用的字段',
  `name` varchar(255) NULL COMMENT '当前行名称',
  PRIMARY KEY (`id`)
);
CREATE TABLE `table2_1`  (
  `id` int NOT NULL,
  `name` varchar(255) NULL COMMENT '当前行名称',
  `fkey` varchar(255) NULL COMMENT '外键',
  PRIMARY KEY (`id`),
  CONSTRAINT `tablefkey` FOREIGN KEY (`fkey`) REFERENCES `database_a`.`table1` (`key`) ON DELETE RESTRICT ON UPDATE RESTRICT
)

CREATE TABLE `table1`  (
  `id` int NOT NULL,
  `key` varchar(255) NULL COMMENT '被引用的字段',
  `name` varchar(255) NULL COMMENT '当前行名称',
  PRIMARY KEY (`id`)
);
CREATE TABLE `table2_2`  (
  `id` int NOT NULL,
  `name` varchar(255) NULL COMMENT '当前行名称',
  `fkey` varchar(255) NULL COMMENT '外键',
  `extra_col` varchar(255) NULL COMMENT '额外字段'
  PRIMARY KEY (`id`),
  CONSTRAINT `tablefkey` FOREIGN KEY (`fkey`) REFERENCES `database_b`.`table1` (`key`) ON DELETE RESTRICT ON UPDATE RESTRICT
)

Comment From: huayanYu

不支持事务切换

Comment From: WilliamChen-luckbob

你是指只能对Primary标记的库加事务吗?目前这边都是简单的单表操作或者对同一个库中的多个表进行操作,不涉及跨库和事务传递。

不支持事务切换

你是指只能对Primary标记的库加事务吗?目前这边都是简单的单表操作或者对同一个库中的多个表进行操作,不涉及跨库和事务传递。

Comment From: huayanYu

@transactional 下不能切换数据源,理解这句话就对了

Comment From: WilliamChen-luckbob

@transactional 下不能切换数据源,理解这句话就对了

这样子的话是不是出了primary之外的数据源均无法使用事务呢? 我的配置是这样子的:

  datasource:
    dynamic:
      primary: database-a
      strict: true
      datasource:
        database-a:
          url: jdbc:mysql://192.168.24.201:3306/database_a?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
          username: root
          password: 123456
          driver-class-name: com.mysql.cj.jdbc.Driver
        database-b:
          url: jdbc:mysql://192.168.24.201:3306/database_b?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
          username: root
          password: 123456
          driver-class-name: com.mysql.cj.jdbc.Driver

接口MpTable2_2Service的实现类由@DS("database-b")标记,直接向table2_2中写入数据,带事务就失败,不带事务的话就正常,是不是因为@Transactional注解实际上是把事务加在datasource-a上了

@SpringBootTest
@RunWith(SpringRunner.class)
@ActiveProfiles("test")
public class DynamicDataSourceTest {
    @Resource
    private MpTable2_2Service service;

    @Test
    @Transactional(rollbackFor = Exception.class)
    public void savingTest() {
        Table2_2 table = new Table2_2();
        service.save(table);
    }
}

Comment From: WilliamChen-luckbob

@transactional 下不能切换数据源,理解这句话就对了

如此一来是否有办法对非Primary数据源的表加上事务呢?这种场景下两个库是非主从关系的,只是迫不得已要放进同一个服务中。

Comment From: zz630

@transactional 下不能切换数据源,理解这句话就对了

这样子的话是不是出了primary之外的数据源均无法使用事务呢? 我的配置是这样子的:

datasource: dynamic: primary: database-a strict: true datasource: database-a: url: jdbc:mysql://192.168.24.201:3306/database_a?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver database-b: url: jdbc:mysql://192.168.24.201:3306/database_b?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver

接口MpTable2_2Service的实现类由@DS("database-b")标记,直接向table2_2中写入数据,带事务就失败,不带事务的话就正常,是不是因为@transactional注解实际上是把事务加在datasource-a上了

``` @SpringBootTest @RunWith(SpringRunner.class) @ActiveProfiles("test") public class DynamicDataSourceTest { @Resource private MpTable2_2Service service;

@Test
@Transactional(rollbackFor = Exception.class)
public void savingTest() {
    Table2_2 table = new Table2_2();
    service.save(table);
}

} ```

先开启事务,再切换数据源,变分布式事务了

Comment From: WilliamChen-luckbob

@transactional 下不能切换数据源,理解这句话就对了

这样子的话是不是出了primary之外的数据源均无法使用事务呢? 我的配置是这样子的: datasource: dynamic: primary: database-a strict: true datasource: database-a: url: jdbc:mysql://192.168.24.201:3306/database_a?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver database-b: url: jdbc:mysql://192.168.24.201:3306/database_b?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver

接口MpTable2_2Service的实现类由@DS("database-b")标记,直接向table2_2中写入数据,带事务就失败,不带事务的话就正常,是不是因为@transactional注解实际上是把事务加在datasource-a上了 ``` @SpringBootTest @RunWith(SpringRunner.class) @ActiveProfiles("test") public class DynamicDataSourceTest { @Resource private MpTable2_2Service service;

@Test
@Transactional(rollbackFor = Exception.class)
public void savingTest() {
    Table2_2 table = new Table2_2();
    service.save(table);
}

} ```

先开启事务,再切换数据源,变分布式事务了

嗯嗯,这个问题我已经解决了,原因确实是先开了事务。 现在@Transactional与@DS平级或在@DS之后,便不会出现此类问题。 同时我还意识到,如果我使用propagation = Propagation.REQUIRES_NEW传播级别,似乎是可以正确地在事务中开启新事务从而切换数据源的,那么在这个场景中,我试图通过propagation = Propagation.REQUIRES_NEW来执行一些从库的处理。 然而我发现,除了主库的表外,从库均能够正常切换数据源并各自写入成功,而主库仅有日志显式插入行成功,但未能提交。 此时当我单独测试向主库简单插入时,发现单表插入执行成功但事务确实未能提交,不知道是为啥呢,这个是我新提的issue 地址