使用 spring-boot 和 bitronix JTA 管理器将 XA 数据源配置为 mysql 8 DB 失败并出现 SqlException XAERR_RMERR

Configuring a XA datasource to mysql 8 DB with spring-boot and bitronix JTA manager fails with SqlException XAERR_RMERR

我创建了一个 Spring Boot 2 (2.1.6.RELEASE) 项目,依赖于 spring-boot-starter-data-jpa 和 spring spring-boot-starter-jta-bitronix 为 Mysql DB (8.0.16) 配置了 XA 数据源。

应用程序 属性 文件(针对与 <> 之间的占位符值的相关性进行了修剪)包含以下配置:

spring:
  datasource:
    url: jdbc:mysql://<host>:<port>/<dbName>
    username: <username>
    password: <password>
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    database-platform: org.hibernate.dialect.MySQL8Dialect
    hibernate:
      ddl-auto: none
  jta:
    bitronix:
      properties:
        server-id: <serverid>

启动 spring 引导应用程序时,我收到以下错误堆栈跟踪:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Unsatisfied dependency expressed through method 'entityManagerFactory' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'entityManagerFactoryBuilder' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Unsatisfied dependency expressed through method 'entityManagerFactoryBuilder' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaVendorAdapter' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.JpaVendorAdapter]: Factory method 'jpaVendorAdapter' threw exception; nested exception is bitronix.tm.resource.ResourceConfigurationException: cannot create JDBC datasource named dataSource
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'entityManagerFactoryBuilder' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Unsatisfied dependency expressed through method 'entityManagerFactoryBuilder' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaVendorAdapter' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.JpaVendorAdapter]: Factory method 'jpaVendorAdapter' threw exception; nested exception is bitronix.tm.resource.ResourceConfigurationException: cannot create JDBC datasource named dataSource
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaVendorAdapter' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.JpaVendorAdapter]: Factory method 'jpaVendorAdapter' threw exception; nested exception is bitronix.tm.resource.ResourceConfigurationException: cannot create JDBC datasource named dataSource
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.orm.jpa.JpaVendorAdapter]: Factory method 'jpaVendorAdapter' threw exception; nested exception is bitronix.tm.resource.ResourceConfigurationException: cannot create JDBC datasource named dataSource
Caused by: bitronix.tm.resource.ResourceConfigurationException: cannot create JDBC datasource named dataSource
Caused by: bitronix.tm.recovery.RecoveryException: failed recovering resource dataSource
Caused by: com.mysql.cj.jdbc.MysqlXAException: XAER_RMERR: Fatal error occurred in the transaction branch - check your data for consistency
Caused by: java.sql.SQLException: XAER_RMERR: Fatal error occurred in the transaction branch - check your data for consistency

免责声明:我正在自我记录我自己的问题,希望能帮助其他人,因为令人惊讶的是,这个问题/问题很难解决。

通过在 github https://github.com/bitronix/btm/issues/100 上验证 bitronix 问题跟踪器,虽然问题已经关闭但没有直接回答,但解决方案并不是很明显。

阅读 https://github.com/bitronix/btm/wiki/FAQ 上的 bitronix FAQ 给出了有关该问题的提示,尽管与 Oracle 相关,它指的是缺少用户权限。

进一步的调查导致 MySQL 8 权限文档页面 https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html 并在以下部分特别突出显示。

Prior to MySQL 8.0, any user could execute the XA RECOVER statement to discover the XID values for outstanding prepared XA transactions, possibly leading to commit or rollback of an XA transaction by a user other than the one who started it. In MySQL 8.0, XA RECOVER is permitted only to users who have the XA_RECOVER_ADMIN privilege, which is expected to be granted only to administrative users who have need for it. This might be the case, for example, for administrators of an XA application if it has crashed and it is necessary to find outstanding transactions started by the application so they can be rolled back. This privilege requirement prevents users from discovering the XID values for outstanding prepared XA transactions other than their own. It does not affect normal commit or rollback of an XA transaction because the user who started it knows its XID.

因此,我在MySQL中通过以下命令为数据源用户添加了所需的权限(根据需要替换用户名和主机部分)。

GRANT XA_RECOVER_ADMIN ON *.* TO 'username'@'%';
FLUSH PRIVILEGES;

进行此更改后,spring 引导应用程序可以毫无问题地启动。