【从零开始学Spring Boot】-13.Spring Boot Jpa多数据源


1.简介

1.1 概述

在实际项目中一般是一个数据源,但是在某些特殊场景可能需要多个数据源,这里以 spring boot jpa 为例演示一下多数据源的配置和使用。

2.演示环境

  1. JDK 1.8.0_201
  2. Spring Boot 2.2.0.RELEASE
  3. 构建工具(apache maven 3.6.3)
  4. 开发工具(IntelliJ IDEA )

3.演示代码

3.1 代码说明

配置两个数据源,分别是 masterDataSource 和 slaveDataSource,它们由两个配置类 MasterConfiguration 和 SlaveConfiguration 来加载,分别扫描不同路径下的 repository。最后通过测试类来调用。

3.2 代码结构

3.3 maven 依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

3.4 配置文件

application.properties

# master 数据源
spring.datasource.master.jdbc-url=jdbc:mysql://172.16.11.125:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.master.username=root
spring.datasource.master.password=123456
spring.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver

# slave 数据源
spring.datasource.slave.jdbc-url=jdbc:mysql://172.16.11.125:3306/test_jpa?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.slave.username=root
spring.datasource.slave.password=123456
spring.datasource.slave.driver-class-name=com.mysql.cj.jdbc.Driver

# 打印sql、自动建表、格式化sql
spring.jpa.show-sql=true
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.hbm2ddl.auto=create
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

# 日志打印
logging.level.root=INFO
logging.level.org.hibernate=INFO
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
logging.level.org.hibernate.type.descriptor.sql.BasicExtractor=TRACE
logging.level.com.soulballad.usage=DEBUG

3.5 java代码

UserModel.java

@Entity
@Table(name = "t_user")
public class UserModel {
    @Id
    @GeneratedValue
    private Long id;
    @Column(nullable = false, unique = true, length = 32)
    private String name;
    @Column(nullable = false)
    private Integer age;
    @Column(length = 32)
    private String birthday;
    private String address;
    @Column(nullable = false, length = 16)
    private String phone;

    public UserModel() {}

    public UserModel(String name, Integer age, String birthday, String address, String phone) {
        this.name = name;
        this.age = age;
        this.birthday = birthday;
        this.address = address;
        this.phone = phone;
    }

    // get&set&toString
}

MasterUserRepository.java

@Repository
public interface MasterUserRepository extends JpaRepository<UserModel, Long> {

    UserModel findByName(String name);

    UserModel findByPhone(String phone);
}

SlaveUserRepository.java

@Repository
public interface SlaveUserRepository extends JpaRepository<UserModel, Long> {

    UserModel findByName(String name);

    UserModel findByPhone(String phone);
}

DataSourceConfig.java

@Configuration
public class DataSourceConfig {

    @Autowired
    private JpaProperties jpaProperties;

    @Autowired
    private HibernateProperties hibernateProperties;

    @Primary
    @Bean(name = "masterDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource masterDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "slaveDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.slave")
    public DataSource slaveDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "vendorProperties")
    public Map<String, Object> getVendorProperties() {
        return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
    }
}

MasterConfiguration.java

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactoryMaster",
    transactionManagerRef = "transactionManagerMaster",
    basePackages = "com.soulballad.usage.springboot.repository.master") // repo(dao)所在位置
public class MasterConfiguration {

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

    @Autowired
    @Qualifier("vendorProperties")
    private Map<String, Object> vendorProperties;

    @Primary
    @Bean(name = "entityManagerFactoryMaster")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder) {
        return builder.dataSource(masterDataSource).properties(vendorProperties)
            .packages("com.soulballad.usage.springboot.model") // 实体类所在位置
            .persistenceUnit("masterPersistenceUnit").build();
    }

    @Primary
    @Bean(name = "entityManagerMaster")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
        return entityManagerFactoryBean(builder).getObject().createEntityManager();
    }

    @Primary
    @Bean(name = "transactionManagerMaster")
    PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(entityManagerFactoryBean(builder).getObject());
    }
}

SlaveConfiguration.java

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "entityManageFactorySlave",
    transactionManagerRef = "transactionManagerSlave",
    basePackages = "com.soulballad.usage.springboot.repository.slave")
public class SlaveConfiguration {

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

    @Autowired
    @Qualifier("vendorProperties")
    private Map<String, Object> vendorProperties;

    @Bean(name = "entityManageFactorySlave")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder) {
        return builder.dataSource(slaveDataSource).properties(vendorProperties)
            .packages("com.soulballad.usage.springboot.model").persistenceUnit("slavePersistenceUnit").build();
    }

    @Bean(name = "entityManageSlave")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
        return entityManagerFactoryBean(builder).getObject().createEntityManager();
    }

    @Bean(name = "transactionManagerSlave")
    PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
        return new JpaTransactionManager(entityManagerFactoryBean(builder).getObject());
    }
}

测试类

UserRepositoryTest.java

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserRepositoryTest {

    @Autowired
    private MasterUserRepository masterUserRepository;

    @Autowired
    private SlaveUserRepository slaveUserRepository;

    @Before
    public void save() {
        UserModel user1 = new UserModel("zhangsan", 20, "2000-01-01", "shenzhen", "13888888888");
        UserModel user2 = new UserModel("lisi", 21, "1999-01-01", "shanghai", "13777777777");
        UserModel user3 = new UserModel("wangwu", 22, "1998-01-01", "beijing", "13666666666");
        UserModel user4 = new UserModel("zhaoliu", 23, "1997-01-01", "guangzhou", "13555555555");
        UserModel user5 = new UserModel("sunqi", 24, "1996-01-01", "wuhan", "13444444444");

        List<UserModel> userList = Arrays.asList(user1, user2, user3, user4, user5);

        masterUserRepository.saveAll(userList);
        slaveUserRepository.saveAll(userList);
    }

    @Test
    public void test_findByName() {
        UserModel masterUser = masterUserRepository.findByName("zhangsan");
        UserModel slaveUser = slaveUserRepository.findByName("zhangsan");
        System.err.println(masterUser);
        System.err.println(slaveUser);
    }

    @Test
    public void test_findUserByPhone() {
        UserModel masterUser = masterUserRepository.findByPhone("13666666666");
        UserModel slaveUser = slaveUserRepository.findByPhone("13666666666");
        System.err.println(masterUser);
        System.err.println(slaveUser);
    }
}

3.6 git 地址

spring-boot/spring-boot-06-jdbc/spring-boot-multi-datasource

4.效果展示

启动 SpringBootMultiDatasourceApplication.main 方法,执行测试类 UserRepositoryTest 中方法,观察结果是否符合预期。

UserRepositoryTest#test_findByName

UserRepositoryTest#test_findByName


文章作者: Soulballad
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Soulballad !
评论
 上一篇
【从零开始学Spring Boot】-14.Spring Boot WebFlux初体验 【从零开始学Spring Boot】-14.Spring Boot WebFlux初体验
1.简介1.1 概述 Spring WebFlux is the new reactive web framework introduced in Spring Framework 5.0. Unlike Spring MVC, it do
下一篇 
【源码分析-Spring Boot】-12.Spring Boot Mybatis 查询流程及实现原理 【源码分析-Spring Boot】-12.Spring Boot Mybatis 查询流程及实现原理
Spring Boot Mybatis:【从零开始学Spring Boot】-12.Spring Boot Mybatis操作数据库 以 UserServiceImpl#findUserByName 为例,分析一下相关源码。 1.myb
2020-07-23
  目录