java—使用spring boot在多个数据源中不获取正在进行的事务

blpfk2vs  于 2021-07-06  发布在  Java
关注(0)|答案(0)|浏览(407)

运行springboot2.3.0版本,配置了两个数据源。在尝试将实体保存到数据库时,出现以下异常。同样的代码使用的是单个数据源。我们遵循了此处找到的多个数据源的设置:https://www.baeldung.com/spring-data-jpa-multiple-databases
你知道会发生什么或者为什么找不到交易吗?

org.springframework.dao.InvalidDataAccessApiUsageException: no transaction is in progress; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress
    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:403)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:257)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528)
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:154)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:178)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
    at com.sun.proxy.$Proxy190.saveAndFlush(Unknown Source)
    at com.xyz.service.KeyHelperService.createKey(KeyHelperService.java:137)
    at com.xyz.service.KeyHelperService.lambda$0(KeyHelperService.java:86)
    at java.util.Optional.orElseGet(Optional.java:267)
    at com.xyz.service.KeyHelperService.createAndRotateKey(KeyHelperService.java:76)
    at com.xyz.service.KeyHelperService$$FastClassBySpringCGLIB$$6668f0c7.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:367)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:118)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)

keyhelperservice在发生异常的第行的代码段:

@Audited(...)
@PreAuthorize(...)
@Transactional
public EncryptionKeyMetadata createKey() {
    ...
    Entity e = new Entity();
    ...
    EncryptionKeyMetadata key = keyMetadataRepo.saveAndFlush(e);
    return key;
}

主数据源配置:

@Configuration
@EnableTransactionManagement
@ConfigurationProperties("spring.datasource")
public class DataSourceConfigWrite extends HikariConfig {

    @Autowired
    private HikariWriteProperties hikariWriteProperties;

    @Autowired
    private HibernateConfig hibernateConfig;

    @PostConstruct
    public void setHikariProps() {
        setPoolName(hikariWriteProperties.getPoolName());
        setMinimumIdle(hikariWriteProperties.getMinimumIdle());
        setMaximumPoolSize(hikariWriteProperties.getMaximumPoolSize());
        setIdleTimeout(hikariWriteProperties.getIdleTimeout());
    }

    @Bean(name = "writeDataSource")
    @Primary
    public HikariDataSource dataSourceWrite() {
        return new HikariDataSource(this);
    }

    @Bean(name = "entityManagerFactoryWrite")
    @Primary
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryWrite(
            final @Qualifier("writeDataSource") HikariDataSource dataSourceWrite) {
        LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
        entityManager.setJpaDialect(new HibernateExtendedJpaDialect());
        DataSourceReadWriteUtil.setEntityManagerProperties(entityManager, dataSourceWrite, hikariWriteProperties.getPackageNames(), hikariWriteProperties.getType(), hibernateConfig);
        return entityManager;
    }

    @Bean
    @Primary
    public PlatformTransactionManager transactionManagerWrite(@Qualifier("entityManagerFactoryWrite") EntityManagerFactory entityManagerFactoryWrite) {
        return new JpaTransactionManager(entityManagerFactoryWrite);
    }
}

数据源配置代码段:

@Configuration
@ConfigurationProperties("spring.datasource")
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactoryWrite",
        transactionManagerRef = "transactionManagerWrite",
        basePackages = {"com.xyz.db.repo"}
)
public class CustomDataSourceConfigWrite {
}

application.yml代码段:

spring:
  jpa:
    hibernate:
      ddl-auto: none
    properties:
      hibernate.dialect: org.hibernate.dialect.MySQL5Dialect
      hibernate.jdbc.time_zone: UTC
  main:
    banner-mode: "off"
  datasource-read:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: 'jdbc:mysql://${db.host:localhost}:${db.port:3336}/xyz_n'
    jdbcUrl: 'jdbc:mysql://${db.host:localhost}:${db.port:3336}/xyz_n'
    username: xyz_n
    password: xyz_n
    platform: mysql
    hikari:
      idle-timeout: 10000
      maximum-pool-size: 10
      minimum-idle: 5
      pool-name: ReadHikariPool
      package-Names: com.xyz.db.repo
      type: read
  datasource:
    url: 'jdbc:mysql://${db.host:localhost}:${db.port:3336}/xyz'
    jdbcUrl: 'jdbc:mysql://${db.host:localhost}:${db.port:3336}/xyz'
    username: xyz
    password: xyz
    initialSize: 5
    minIdle: 5
    maxActive: 30
    maxIdle: 30
    maxWait: 1000000
    defaultAutoCommit: false
    validationQuery: SELECT 1
    testOnBorrow: true
    testWhileIdle: true
    timeBetweenEvictionRunsMillis: 10000
    minEvictableIdleTimeMillis: 30000
    jmxEnabled: true
    removeAbandonedTimeout: 120
    removeAbandoned: true
    driver-class-name: com.mysql.cj.jdbc.Driver
    hikari:
      maximum-pool-size: 100
      minimum-idle: 5
      connection-timeout: 30000
      max-lifetime: 5000
      idle-timeout: 1000
      pool-name: WriteHikariPool
      package-Names: com.xyz.db.repo
      type: write

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题