第 3-6 课:Spring Data JPA 多数据源的使⽤

耗尽温柔 提交于 2020-01-06 22:09:53
项⽬中使⽤多个数据源在以往⼯作中⽐较常⻅,微服务架构中不建议⼀个项⽬使⽤多个数据源。在微服务架
构下,⼀个微服务拥有⾃⼰独⽴的⼀个数据库,如果此微服务要使⽤其他数据库的数据,需要调⽤对应库的
微服务接⼝来调⽤,⽽不是在⼀个项⽬中连接使⽤多个数据库,这样微服务更独⽴、更容易⽔平扩展。
 
虽然在微服务架构下,不提倡⼀个项⽬拥有多个数据源,但在 Spring Boot 体系中,项⽬实现多数据源调⽤
却是⼀件很容易的事情,本节课将介绍 Spring Data JPA 多数据源的使⽤。
 
Spring Data JPA 使⽤多数据源的整体思路是,配置不同的数据源,在启动时分别加载多个数据源配置,并且
注⼊到不同的 repository 中。这样不同的 repository 包就有不同的数据源,使⽤时注⼊对应包下的
repository,就会使⽤对应数据源的操作。
 
对照前两课的示例项⽬,本课内容将会对项⽬结构有所调整,如下:
其中:
  • confifig 启动时加载、配置多数据源;GitChat
  • model 存放数据操作的实体类;
  • repository ⽬录下有两个包路径 test1 test2 ,分别代表两个不同数据源下的仓库,这两个包下的 repository 可以相同也可以不同。
下⾯演示⼀下项⽬。
 

多数据源的⽀持

配置 Spring Data JPA 对多数据源的使⽤,⼀般分为以下⼏步:
  • 创建数据库 test1 test2
  • 配置多数据源
  • 不同源的 repository 放⼊不同包路径
  • 声明不同的包路径下使⽤不同的数据源、事务⽀持
  • 不同的包路径下创建对应的 repository
  • 测试使⽤
上⾯的⼀些步骤我们在前⾯两课中已经讲过了,这⾥只补充不同的内容。
配置两个数据源:
spring.datasource.primary.jdbc-url=jdbc:mysql://localhost:3306/test1?serverTimezon
e=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.primary.username=root
spring.datasource.primary.password=root
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.secondary.jdbc-url=jdbc:mysql://localhost:3306/test2?serverTimez
one=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.secondary.username=root
spring.datasource.secondary.password=root
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver
#SQL 输出
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.hbm2ddl.auto=create
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
#format ⼀下 SQL 进⾏输出
spring.jpa.properties.hibernate.format_sql=true
设置将项⽬中的 SQL 格式化后打印出来,⽅便在开发过程中调试跟踪。
创建 DataSourceConfifig 添加 @Confifiguration 注解,在项⽬启动时运⾏初始化数据库资源。
 
@Configuration
public class DataSourceConfig {
}
DataSourceConfifig 类中加载配置⽂件,利⽤ ConfifigurationProperties ⾃动装配的特性加载两个数据源。
加载第⼀个数据源,数据源配置以 spring.datasource.primary 开头,注意当有多个数据源时,需要将其中⼀
个标注为 @Primary,作为默认的数据源使⽤。
@Bean(name = "primaryDataSource")
@Primary
@ConfigurationProperties("spring.datasource.primary")
public DataSource firstDataSource() {
 return DataSourceBuilder.create().build();
}
加载第⼆个数据源,数据源配置以 spring.datasource.secondary 为开头。
@Bean(name = "secondaryDataSource")
@ConfigurationProperties("spring.datasource.secondary")
public DataSource secondDataSource() {
 return DataSourceBuilder.create().build();
}
加载 JPA 的相关配置信息,JpaProperties JPA 的⼀些属性配置信息,构建
LocalEntityManagerFactoryBean 需要参数信息注⼊到⽅法中。
@Autowired
private JpaProperties jpaProperties;
@Autowired
private HibernateProperties hibernateProperties;
@Bean(name = "vendorProperties")
public Map<String, Object> getVendorProperties() {
 return hibernateProperties.determineHibernateProperties(jpaProperties.getPrope
rties(), new HibernateSettings());
}
第⼀个数据源的加载配置过程
 
⾸先来看第⼀个数据源的加载配置过程,创建 PrimaryConfifig 类,将上⾯创建好的第⼀个数据源注⼊到类
中,添加 @Confifiguration @EnableTransactionManagement 注解,第⼀个代表启动时加载,第⼆个注解
表示启⽤事务,同时将第⼀个数据源和 JPA 配置信息注⼊到类中。
 
@Configuration
@EnableTransactionManagement
public class PrimaryConfig {
 @Autowired
 @Qualifier("primaryDataSource")
 private DataSource primaryDataSource;
 @Autowired
 @Qualifier("vendorProperties")
 private Map<String, Object> vendorProperties;
}
LocalEntityManagerFactoryBean 负责创建⼀个适合于仅使⽤ JPA 进⾏数据访问的环境的 EntityManager
构建的时候需要指明提示实体类的包路径、数据源和 JPA 配置信息。
@Bean(name = "entityManagerFactoryPrimary")
@Primary
public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary (EntityM
anagerFactoryBuilder builder) {
 return builder
 .dataSource(primaryDataSource)
 .properties(vendorProperties)
 .packages("com.neo.model") //设置实体类所在位置
 .persistenceUnit("primaryPersistenceUnit")
 .build();
}
利⽤上⾯的 entityManagerFactoryPrimary() ⽅法构建好最终的 EntityManager
@Bean(name = "entityManagerPrimary")
@Primary
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
 return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
}
EntityManager JPA 中⽤于增、删、改、查的接⼝,它的作⽤相当于⼀座桥梁,连接内存中的 Java 对象
和数据库的数据存储。使⽤ EntityManager 中的相关接⼝对数据库实体进⾏操作的时候, EntityManager
跟踪实体对象的状态,并决定在特定时刻将对实体的操作映射到数据库操作上⾯。
同时给数据源添加上jpa事务。
@Bean(name = "transactionManagerPrimary")
@Primary
PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder b
uilder) {
 return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObjec
t());
}
最后⼀步最为关键,将我们在类中配置好的 EntityManager 和事务信息注⼊到对应数据源的 repository ⽬录
下,这样此⽬录下的 repository 就会拥有对应数据源和事务的信息。
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
 entityManagerFactoryRef="entityManagerFactoryPrimary",
 transactionManagerRef="transactionManagerPrimary",
 basePackages= { "com.neo.repository.test1" })//设置dao(repo)所在位置
public class PrimaryConfig {}
其中,basePackages ⽀持设置多个包路径,例
如, basePackages= { "com.neo.repository.test1","com.neo.repository.test3" }
到此第⼀个数据源配置完成了。
 
第⼆个数据源的加载配置过程
 
第⼆个数据源配置和第⼀个数据源配置类似,只是⽅法上去掉了注解:@Primary,第⼆个数据源数据源加载
配置类 SecondaryConfifig 完整代码如下:GitChat
 
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
 entityManagerFactoryRef="entityManagerFactorySecondary",
 transactionManagerRef="transactionManagerSecondary",
 basePackages= { "com.neo.repository.test2" })
public class SecondaryConfig {
 @Autowired
 @Qualifier("secondaryDataSource")
 private DataSource secondaryDataSource;
 @Autowired
 @Qualifier("vendorProperties")
 private Map<String, Object> vendorProperties;
 @Bean(name = "entityManagerFactorySecondary")
 public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary (E
ntityManagerFactoryBuilder builder) {
 return builder
 .dataSource(secondaryDataSource)
 .properties(vendorProperties)
 .packages("com.neo.model")
 .persistenceUnit("secondaryPersistenceUnit")
 .build();
 }
 @Bean(name = "entityManagerSecondary")
 public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
 return entityManagerFactorySecondary(builder).getObject().createEntityMana
ger();
 }
 @Bean(name = "transactionManagerSecondary")
 PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBui
lder builder) {
 return new JpaTransactionManager(entityManagerFactorySecondary(builder).ge
tObject());
 }
}
到此多数据源的配置就完成了,项⽬中使⽤哪个数据源的操作,就注⼊对应包下的 repository 进⾏操作即
可,接下来我们对上⾯配置好的数据源进⾏测试。
创建 UserRepositoryTests 测试类,将两个包下的 repository 都注⼊到测试类中:
 
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserRepositoryTests {
 @Resource
 private UserTest1Repository userTest1Repository;
 @Resource
 private UserTest2Repository userTest2Repository;
}
⾸先测试两个数据库中都存⼊数据,数据源1插⼊ 2 条⽤户信息,数据源2插⼊ 1 条⽤户信息。
@Test
public void testSave() throws Exception {
 Date date = new Date();
 DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFo
rmat.LONG);
 String formattedDate = dateFormat.format(date);
 userTest1Repository.save(new User("aa", "aa123456","aa@126.com", "aa", format
tedDate));
 userTest1Repository.save(new User("bb", "bb123456","bb@126.com", "bb", format
tedDate));
 userTest2Repository.save(new User("cc", "cc123456","cc@126.com", "cc", format
tedDate));
}
执⾏完测试⽤例后查看数据库,发现 test1 库有两条数据,test2 有⼀条,证明两个数据源均保存数据正常。
下⾯继续测试删除功能,使⽤两个数据源的 repository 将⽤户信息全部删除。
@Test
public void testDelete() throws Exception {
 userTest1Repository.deleteAll();
 userTest2Repository.deleteAll();
}
执⾏完测试⽤例后,发现 test1 库和 test2 库⽤户表的信息已经被清空,证明多数据源删除成功。
 

总结

Spring Data JPA 通过在启动时加载不同的数据源,并将不同的数据源注⼊到不同的 repository 包下,从⽽实
现项⽬多数据源操作,在项⽬中使⽤多数据源时,需要⽤到哪个数据源,只需要将对应包下的 repository
⼊操作即可。本课示例中以两个数据源作为演示,但其实三个或者更多数据源配置、操作,都可以按照上⾯
⽅法进⾏配置使⽤。
 
 
 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!