Spring-boot + Spring-data-jpa 在配置多数据源时,第二个数据源不可写入,只能读

Spring-boot + Spring-data-jpa
在配置多数据源时,第二个数据源不可写入,只能读
报的主要异常是no transaction in process,也有roll-back only等异常
spring-boot版本为2.1.4
spring-data-jpa版本为2.1.6
spring-framework版本为5.1.6

我第一和第二数据源配置都一样,除了第一个数据源上加了@Primary注解
同时,第二个数据源读取数据时无异常。
我查阅很多资料,基本上很难找到相同情况,或者可行的解决方案。
而且也在Service上加过注解@Transactional(transactionManager = “transactionManagerGym”),仍无法解决问题。("transactionManagerGym"是我的第二个数据源transactionManager的Bean的名字)

修改后第二数据源的Transaction配置如下,注解部分为原来的配置(第二数据源只能读,不能写。第一数据源由于可读可写,所以未作修改,两种配置方法都可用),此时Service也不用加注解@Transactional
GymDataSource.java

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.Properties;

@Slf4j
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef="entityManagerFactoryGym",
        transactionManagerRef="transactionManagerGym",
        basePackages= {"repositoryGym"}) //设置Repository所在位置
public class GymDataSourceConfig {

    @Autowired
    @Qualifier("gymDataSource")
    private DataSource gymDataSource;

//    @Autowired
//    private JpaProperties jpaProperties;

//    @Bean(name = "entityManagerGym")
//    public EntityManager entityManagerGym(EntityManagerFactoryBuilder builder) {
//        return entityManagerFactoryGym(builder).getObject().createEntityManager();
//    }

    @Bean(name = "entityManagerFactoryGym")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryGym() {
        LocalContainerEntityManagerFactoryBean em
                = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(gymDataSource);
        em.setPackagesToScan(new String[] { "modelGym" });//设置实体类所在位置(包名)

        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        Properties properties = new Properties();
        properties.setProperty("hibernate.hbm2ddl.auto", "update");
//        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
        em.setJpaProperties(properties);

        return em;
    }
//    public LocalContainerEntityManagerFactoryBean entityManagerFactoryGym (EntityManagerFactoryBuilder builder) {
//        Map<String, String> properties = jpaProperties.getProperties();
//        properties.forEach((k,v)->log.info("key:"+k+" ##### "+"value"+v));
//        return builder
//                .dataSource(gymDataSource)
//                .properties(jpaProperties.getProperties())
//                .packages("modelGym") //设置实体类所在位置(包名)
//                .persistenceUnit("GymPersistenceUnit")
//                .build();
//    }

    @Bean(name = "transactionManagerGym")
//    @Resource
    public PlatformTransactionManager transactionManagerGym(DataSource gymDataSource) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactoryGym().getObject());

        return transactionManager;
//        return new DataSourceTransactionManager(gymDataSource);
    }

}

参考资料:
https://www.baeldung.com/the-persistence-layer-with-spring-and-jpa
https://www.baeldung.com/transaction-configuration-with-jpa-and-spring

另附配置文件及数据源的java文件(未删除的注释,是我参考网上别人的写法,但不确定是否有效)
application.properties

spring.datasource.user.url=jdbc:mysql://127.0.0.1:3306/app_user?useSSL=false
spring.datasource.user.username=root
spring.datasource.user.password=123456
spring.datasource.user.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.user.max-idle=10
spring.datasource.user.max-wait=10000
spring.datasource.user.min-idle=5
spring.datasource.user.initial-size=5
spring.datasource.gym.url=jdbc:mysql://127.0.0.1:3306/gym?useSSL=false
spring.datasource.gym.username=root
spring.datasource.gym.password=123456
spring.datasource.gym.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.gym.max-idle=10
spring.datasource.gym.max-wait=10000
spring.datasource.gym.min-idle=5
spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.show-sql=true
server.port=80
server.tomcat.uri-encoding=UTF-8
management.endpoints.web.exposure.include=*

MyDataSource.java

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;

@Slf4j
@Configuration
public class MyDataSource {
    @Bean
//    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.user")//配置文件中数据源的前缀
    public DataSourceProperties userDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean(name = "userDataSource")
//    @Qualifier("userDataSource")
    @Primary
    public DataSource userDataSource() {
        DataSourceProperties dataSourceProperties = userDataSourceProperties();

        return dataSourceProperties.initializeDataSourceBuilder().build();
    }


    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.gym")//配置文件中数据源的前缀
    public DataSourceProperties gymDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean(name = "gymDataSource")
//    @Qualifier("gymDataSource")
    public DataSource gymDataSource() {
        DataSourceProperties dataSourceProperties = gymDataSourceProperties();
//        log.info("gymdatasourceeeeeeeeeeeeee"+dataSourceProperties.getUrl());
        return dataSourceProperties.initializeDataSourceBuilder().build();
    }
}

UserDataSourceConfig.java

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import java.util.Map;

@Slf4j
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactoryUser",
        transactionManagerRef = "transactionManagerUser",
        basePackages = {"repositoryUser"}) //设置Repository所在位置(包名)
public class UserDataSourceConfig {

    @Autowired
    @Qualifier("userDataSource")
    private DataSource userDataSource;

    @Autowired
    private JpaProperties jpaProperties;



    @Primary
    @Bean(name = "entityManagerUser")
    public EntityManager entityManagerUser(EntityManagerFactoryBuilder builder) {
        return entityManagerFactoryUser(builder).getObject().createEntityManager();
    }

    @Primary
    @Bean(name = "entityManagerFactoryUser")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryUser(EntityManagerFactoryBuilder builder) {
        Map<String, String> properties = jpaProperties.getProperties();
        properties.forEach((k,v)->log.info("key:"+k+" ##### "+"value"+v));
        return builder
                .dataSource(userDataSource)
                .properties(jpaProperties.getProperties())
                .packages("modelUser") //设置实体类所在位置(包名)
                .persistenceUnit("UserPersistenceUnit")
                .build();
    }


    @Primary
    @Bean(name = "transactionManagerUser")
    public PlatformTransactionManager transactionManagerUser(DataSource userDataSource) {

        return new DataSourceTransactionManager(userDataSource);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值