Springboot+Mybatis - JPA と JDBC の競合により @Transactional トランザクションが有効にならず、ロールバックされない問題を解決

Springboot+Mybatis - JPA と JDBC の競合により @Transactional トランザクションが有効にならず、ロールバックされない問題を解決

環境

  • スプリングブーツ 1.5.6
  • マイボット 3.5.3
  • Mybatis プラス 3.3.1

問題の原因

トランザクション マネージャーを出力すると、Mybatis 環境のトランザクション マネージャー インスタンスが JpaTransactionManager オブジェクトであることがわかりますが、これは明らかに間違っています。

Mybatis トランザクションで JPA トランザクション管理を使用すると、トランザクションの失敗とロールバックが発生します。ORM

トランザクション マネージャーの対応関係は次のとおりです。

  • Mybatis -> org.springframework.jdbc.datasource.DataSourceTransactionManager@50061d56
  • JPA -> org.springframework.orm.jpa.JpaTransactionManager@204d101

解決

@Bean 構成を追加し、jdbc トランザクション マネージャー DataSourceTransactionManager を登録します。dataSource はフレームワークによって自動的に挿入されます。

プロジェクトに jpa と mybatis が混在している場合は、@Bean("xxx") を使用して登録オブジェクトにアノテーションを付ける必要があります。それを dataSource、sqlSessionFactory、および DataSourceTransactionManager 構成に表示します。

//注册
@Configuration
public class MybatisConfig {
    @Bean("jdbcTransactionManager")
    public PlatformTransactionManager txManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}
//使用
@Transactional(value = "jdbcTransactionManager",rollbackFor = {Exception.class})
public void TestTran4Salf(){
    ...
}

トラブルシューティングのプロセス

出力SQL実行処理

3 つの構成方法:

  • yml 構成

    構成オブジェクト: org.apache.ibatis.session.Configuration
mybatis:
  configuration:
    #事务注册日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

mybatis-plus:
  mapper-locations: classpath:/mapper/**/**.xml
  configuration:
    #事务注册日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

logging:
  level:
    root: info
    #事务提交回滚日志
    org.springframework.jdbc.datasource.DataSourceTransactionManager: debug    
  • SqlSessionFactory プロパティを変更する
@Configuration
public class MybatisConfig {
    @Autowired
    private List<SqlSessionFactory> sqlSessionFactoryList;
    @PostConstruct
    public void addSqlInterceptor() {
        for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
            sqlSessionFactory.getConfiguration().addInterceptor(interceptor);
            sqlSessionFactory.getConfiguration().setCallSettersOnNulls(true);//返回查询中的null值
            sqlSessionFactory.getConfiguration().setLogImpl(org.apache.ibatis.logging.stdout.StdOutImpl.class);//输出执行SQL
        }
    }
}
  • カスタム ConfigurationCustomizer オブジェクト
@Configuration
public class MybatisConfig {
    @Bean
    public ConfigurationCustomizer configurationCustomizer() {
        return configuration -> {
            configuration.setObjectWrapperFactory(new MybatisMapWrapperFactory());
            configuration.setCallSettersOnNulls(true);//返回查询中的null值
            configuration.setMapUnderscoreToCamelCase(false);//表字段使用下划线命名
            configuration.setLogImpl(org.apache.ibatis.logging.stdout.StdOutImpl.class);//输出执行SQL
        };
    }
}

トランザクションサポートが有効かどうか

注釈 @EnableTransactionManagement はトランザクションを有効にすることをマークしますが、トランザクションを追加しないと機能しません。また、セッション オブジェクトの rollback() を手動で呼び出すことも無効です。

@EnableTransactionManagement
@SpringBootApplication()
public class StartApplication {
	public static void main(String[] args) {
		SpringApplication.run(StartApplication.class, args);
	}
}

プラットフォームマネージャーは正しいですか

トランザクション マネージャー インスタンスを挿入し、それを出力して、インスタンス オブジェクトが現在の ORM と一致するかどうかを確認します。

@Autowired
PlatformTransactionManager platformTransactionManager;

@Test
public String testTran() {
        System.out.print(">>>>>事务管理器:"+platformTransactionManager);
        ....
}

トランザクション実行プロセスを表示するために、実行された SQL をコンソールに出力します。

打开Mybatis执行SQL日志,方便滚出事务执行情况;
>>>>>事务管理器:org.springframework.jdbc.datasource.DataSourceTransactionManager@2fbbdcaCreating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6]  --事务
JDBC Connection [ProxyConnection[PooledConnection[org.postgresql.jdbc.PgConnection@14fc5be1]]] will be managed by Spring
==>  Executing: select * from mytable; 
<==      Total: 2
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6]  --事务
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6] from current transaction  --事务
==>  Preparing: insert into mytable(log_id, create_date) VALUES ('1678872584952_1',now()); 
==> Parameters: 
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6]  --事务
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6] from current transaction  --事务
==>  Preparing: insert into mytable(log_id, create_date) VALUES ('1678872584952_2',now()); 
==> Parameters: 
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6]  --事务
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6] from current transaction  --事务
==>  Preparing: insert into mytable(log_id, create_date) VALUES ('1678872584952_2',now()); 
==> Parameters: 
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6]  --事务
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6]  --事务
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1149ccc6]  --事务

トランザクションの失敗を引き起こすいくつかの落とし穴

ピット 1: Spring トランザクション ホスティングが有効になっていない

@EnableTransactionManagement アノテーションをスタートアップ クラスに表示する必要があります。そうしないと、トランザクションは有効になりません。

ピット 2: ORM の混合使用により、複数のプラットフォームのトランザクション マネージャーが発生する

Mybatis と JPA トランザクション マネージャー間の通信:

  • Mybatis -> org.springframework.jdbc.datasource.DataSourceTransactionManager@50061d56
  • JPA -> org.springframework.orm.jpa.JpaTransactionManager@204d101

ピット 3: デフォルトのビジネス例外はロールバックされない

@Transactional() が指定されていない場合、ランタイム例外のみがロールバックされます。

@Transactional(rollbackFor = {Exception.class}) はこの時点ですべての例外をロールバックします。

ピット 4: 例外をスローせずに手動でキャッチすると、トランザクションも失敗します。

try {
    mapper.insert(sql1);
    mapper.insert(sql2);
}catch (Exception e){
    e.printStackTrace();
    throw e;  //注释掉这行将不回滚
}

ピット 5: @Transaction アノテーションは public という名前のメソッドに対してのみ有効であり、他のものは無効になります。

おすすめ

転載: blog.csdn.net/xxj_jing/article/details/129584476