2019-11-01 22:26 全me村的希望 阅读() 评论() 编辑 收藏

  上个文章介绍了spring boot在使用Mybatis持久化技术的时候如何使用多数据源,今天再补充一个使用spring data jpa实现多数据源的使用情况,JPA是一套数据库持久化规范,或者称之为一套接口,可以类比于Java中的接口,既然有接口就有实现,Hibernate就是其中的一个实现。
  本例为查询两个数据库test1和test2中的用户信息,可以共用一个实体类,当然如果有需要也可以操作不同的实体类。

  1.项目的整体结构如下:

  2.pom文件说明

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-data-jpa</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-starter-web</artifactId>
  9. </dependency>
  10. <dependency>
  11. <groupId>com.alibaba</groupId>
  12. <artifactId>druid-spring-boot-starter</artifactId>
  13. <version>1.1.10</version>
  14. </dependency>
  15. <dependency>
  16. <groupId>mysql</groupId>
  17. <artifactId>mysql-connector-java</artifactId>
  18. <scope>runtime</scope>
  19. <version>5.1.27</version>
  20. </dependency>
  21. <dependency>
  22. <groupId>org.springframework.boot</groupId>
  23. <artifactId>spring-boot-starter-test</artifactId>
  24. <scope>test</scope>
  25. <exclusions>
  26. <exclusion>
  27. <groupId>org.junit.vintage</groupId>
  28. <artifactId>junit-vintage-engine</artifactId>
  29. </exclusion>
  30. </exclusions>
  31. </dependency>
  32. </dependencies>

  pom文件中主要是需要锁定数据库驱动的版本,因为要使用多数据源,所以需要导入druid,因为后面要使用DruidDataSourceBuilder来初始化数据源。而spring-boot默认使用的HikariCP是不支持的。

  3.项目配置文件

  1. spring.datasource.one.type=com.alibaba.druid.pool.DruidDataSource
  2. spring.datasource.one.url=jdbc:mysql://localhost:3306/test1
  3. spring.datasource.one.username=root
  4. spring.datasource.one.password=123456
  5. spring.datasource.two.type=com.alibaba.druid.pool.DruidDataSource
  6. spring.datasource.two.url=jdbc:mysql://localhost:3306/test2
  7. spring.datasource.two.username=root
  8. spring.datasource.two.password=123456
  9. spring.jpa.properties.hibernate.ddl-auto=update //每次启动项目如果发现实体类类更新则对应着更新表结构
  10. spring.jpa.properties.show-sql=true //在控制台打印sql语句
  11. spring.jpa.properties.database=mysql
  12. spring.jpa.properties.database-platform=mysql
  13. spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect

  注意两个数据库的配置信息的前缀不一样,后面将根据配置信息的前缀对数据源进行初始化,还有就是关于JPA的属性配置都需要在spring.jpa后面增加properties关键字,为什么这样做呢?是因为后面配置JPA的时候
不仅需要数据源还需要JpaProperties对象,看一下JpaProperties类:

  1. @ConfigurationProperties(prefix = "spring.jpa")
  2. public class JpaProperties {
  3. /**
  4. * Additional native properties to set on the JPA provider.
  5. */
  6. private Map<String, String> properties = new HashMap<>();

  我们自己定义的属性存到名为properties的HashMap中,再加上类的前缀为spring.jpa。所以想要spring boot自己读取需要按照其规则注入即为spring.jpa.properties。

  4.用户类

  1. @Entity(name = "users")
  2. public class User {
  3. @Id
  4. @GeneratedValue(strategy = GenerationType.IDENTITY)
  5. private Integer id;
  6. private String name;
  7. private String address;
  8. 省略get set 方法................
  9. }

  用户类比较简单,只有几个基本的属性。@Entity注解的name的值对应数据库的表名。

  5.配置数据源

  1. @Configuration
  2. public class DataSourceConfig {
  3. @Bean
  4. @ConfigurationProperties(prefix = "spring.datasource.one")
  5. @Primary
  6. DataSource dsOne() {
  7. return DruidDataSourceBuilder.create().build();
  8. }
  9. //primary注解表示某个类存在多个实例时优先使用当前bean
  10. @Bean
  11. @ConfigurationProperties(prefix = "spring.datasource.two")
  12. DataSource dsTwo() {
  13. return DruidDataSourceBuilder.create().build();
  14. }
  15. }

  既然是多数据源那么肯定需要自己配置多个数据源的情况,注意这里需要增加@Primary注解,其含义就是表示某个类存在多个实例时优先使用当前实例,如果不加项目会报错,多个bean只能加一个,意思是dsTwo同样返回的DataSource,但是dsOne加了,其他的就不能再加了。

  6.JPA配置

  (1)第一个JPA的配置

  1. @Configuration
  2. @EnableJpaRepositories(basePackages = "com.hopec.jpa2.repository1",transactionManagerRef = "platformTransactionManager1",entityManagerFactoryRef = "localContainerEntityManagerFactoryBean1")
  3. public class JpaConfigOne {
  4. @Autowired
  5. @Qualifier(value = "dsOne")
  6. DataSource dsOne;
  7. @Autowired
  8. JpaProperties jpaProperties;
  9. @Bean
  10. @Primary //相应的需要添加上此注解
  11. LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean1(EntityManagerFactoryBuilder factoryBuilder){
  12. return factoryBuilder.dataSource(dsOne) //设置数据源
  13. .properties(jpaProperties.getProperties()) //获取配置信息
  14. .packages("com.hopec.jpa2.model") //设置扫描的实体类的包
  15. .persistenceUnit("name1") //持久化单元的名称 不同的对象的名字不同就可以
  16. .build();
  17. }
  18. @Bean
  19. PlatformTransactionManager platformTransactionManager1(EntityManagerFactoryBuilder factoryBuilder){
  20. LocalContainerEntityManagerFactoryBean bean = localContainerEntityManagerFactoryBean1(factoryBuilder);
  21. return new JpaTransactionManager(bean.getObject());
  22. }
  23. }

  (2)第二个JPA的配置

  1. @Configuration
  2. @EnableJpaRepositories(basePackages = "com.hopec.jpa2.repository2",transactionManagerRef = "platformTransactionManager2",entityManagerFactoryRef = "localContainerEntityManagerFactoryBean2")
  3. public class JpaConfigTwo {
  4. @Autowired
  5. @Qualifier(value = "dsTwo")
  6. DataSource dsTwo;
  7. @Autowired
  8. JpaProperties jpaProperties;
  9. @Bean
  10. LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean2(EntityManagerFactoryBuilder factoryBuilder){
  11. return factoryBuilder.dataSource(dsTwo) //设置数据源
  12. .properties(jpaProperties.getProperties()) //获取配置信息
  13. .packages("com.hopec.jpa2.model") //设置扫描的实体类的包
  14. .persistenceUnit("name2") //持久化单元的名称 不同的对象的名字不同就可以
  15. .build();
  16. }
  17. @Bean
  18. PlatformTransactionManager platformTransactionManager2(EntityManagerFactoryBuilder factoryBuilder){
  19. LocalContainerEntityManagerFactoryBean bean = localContainerEntityManagerFactoryBean2(factoryBuilder);
  20. return new JpaTransactionManager(bean.getObject());
  21. }
  22. }

  以上两个JPA的配置主要是注意包名路径的对应一定要保持一致。

  7.持久层
  (1)第一个持久层

  1. public interface UserRepository1 extends JpaRepository<User,Integer>{
  2. @Query(value = "select * from users where id=(select max(id) from users)",nativeQuery = true)
  3. User findMaxIdUser();
  4. //自定义的属性如何进行匹配
  5. @Query(value = "insert into users(name,address) values(?1,?2)",nativeQuery = true)
  6. @Modifying
  7. @Transactional
  8. Integer addUser1(String name,String author);
  9. @Query(value = "insert into users(name,address) values(:name,:address)",nativeQuery = true)
  10. @Modifying
  11. @Transactional
  12. Integer addUser2(@Param("name") String name, @Param("address") String address);
  13. //自定义的对象与sql语句进行匹配
  14. @Query(value = "insert into users(name,address) values(:#{#user.name},:#{#user.address})",nativeQuery = true)
  15. @Modifying
  16. @Transactional
  17. Integer addUser3(@Param("user") User user);

  这里其实不需要写这么复杂的,单纯查询所有用户信息,JpaRepository里面已经实现了,这里自定义查询和保存用户方法是为了多学习一点如何在JPA中自定义查询方法以及参数对应,也就是将自定义的方法中的普通参数或者对象与@Query中原生SQL的属性对应起来。

  (2)第二个持久层

  1. public interface UserRepository2 extends JpaRepository<User,Integer>{
  2. }

  实际上在本例中是这样的,不需要第一个那么复杂,第一个只是作为扩展的参考。

  8.测试

  1. @Test
  2. public void test1(){
  3. List<User> users = userRepository1.findAll();
  4. System.out.println(users);
  5. List<User> users1 = userRepository2.findAll();
  6. System.out.println(users1);
  7. }
  8. @Test
  9. public void test2(){
  10. User user = new User();
  11. user.setName("123");
  12. user.setAddress("石家庄");
  13. Integer r = userRepository1.addUser3(user);
  14. System.out.println(r);
  15. }

  测试结果:

 

    最后大功告成!

版权声明:本文为hopeofthevillage原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/hopeofthevillage/p/11779955.html