上個文章介紹了spring boot在使用Mybatis持久化技術的時候如何使用多數據源,今天再補充一個使用spring data jpa實現多數據源的使用情況,JPA是一套數據庫持久化規范,或者稱之為一套接口,可以類比於Java中的接口,既然有接口就有實現,Hibernate就是其中的一個實現。
本例為查詢兩個數據庫test1和test2中的用戶信息,可以共用一個實體類,當然如果有需要也可以操作不同的實體類。
1.項目的整體結構如下:

2.pom文件說明
<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>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> <version>5.1.27</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
pom文件中主要是需要鎖定數據庫驅動的版本,因為要使用多數據源,所以需要導入druid,因為后面要使用DruidDataSourceBuilder來初始化數據源。而spring-boot默認使用的HikariCP是不支持的。
3.項目配置文件
spring.datasource.one.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.one.url=jdbc:mysql://localhost:3306/test1
spring.datasource.one.username=root
spring.datasource.one.password=123456
spring.datasource.two.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.two.url=jdbc:mysql://localhost:3306/test2
spring.datasource.two.username=root
spring.datasource.two.password=123456
spring.jpa.properties.hibernate.ddl-auto=update //每次啟動項目如果發現實體類類更新則對應着更新表結構
spring.jpa.properties.show-sql=true //在控制台打印sql語句
spring.jpa.properties.database=mysql
spring.jpa.properties.database-platform=mysql
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
注意兩個數據庫的配置信息的前綴不一樣,后面將根據配置信息的前綴對數據源進行初始化,還有就是關於JPA的屬性配置都需要在spring.jpa后面增加properties關鍵字,為什么這樣做呢?是因為后面配置JPA的時候
不僅需要數據源還需要JpaProperties對象,看一下JpaProperties類:
@ConfigurationProperties(prefix = "spring.jpa") public class JpaProperties { /** * Additional native properties to set on the JPA provider. */ private Map<String, String> properties = new HashMap<>();
我們自己定義的屬性存到名為properties的HashMap中,再加上類的前綴為spring.jpa。所以想要spring boot自己讀取需要按照其規則注入即為spring.jpa.properties。
4.用戶類
@Entity(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String name; private String address; 省略get set 方法................ }
用戶類比較簡單,只有幾個基本的屬性。@Entity注解的name的值對應數據庫的表名。
5.配置數據源
@Configuration public class DataSourceConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.one") @Primary DataSource dsOne() { return DruidDataSourceBuilder.create().build(); } //primary注解表示某個類存在多個實例時優先使用當前bean @Bean @ConfigurationProperties(prefix = "spring.datasource.two") DataSource dsTwo() { return DruidDataSourceBuilder.create().build(); } }
既然是多數據源那么肯定需要自己配置多個數據源的情況,注意這里需要增加@Primary注解,其含義就是表示某個類存在多個實例時優先使用當前實例,如果不加項目會報錯,多個bean只能加一個,意思是dsTwo同樣返回的DataSource,但是dsOne加了,其他的就不能再加了。
6.JPA配置
(1)第一個JPA的配置
@Configuration @EnableJpaRepositories(basePackages = "com.hopec.jpa2.repository1",transactionManagerRef = "platformTransactionManager1",entityManagerFactoryRef = "localContainerEntityManagerFactoryBean1") public class JpaConfigOne { @Autowired @Qualifier(value = "dsOne") DataSource dsOne; @Autowired JpaProperties jpaProperties; @Bean @Primary //相應的需要添加上此注解 LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean1(EntityManagerFactoryBuilder factoryBuilder){ return factoryBuilder.dataSource(dsOne) //設置數據源 .properties(jpaProperties.getProperties()) //獲取配置信息 .packages("com.hopec.jpa2.model") //設置掃描的實體類的包 .persistenceUnit("name1") //持久化單元的名稱 不同的對象的名字不同就可以 .build(); } @Bean PlatformTransactionManager platformTransactionManager1(EntityManagerFactoryBuilder factoryBuilder){ LocalContainerEntityManagerFactoryBean bean = localContainerEntityManagerFactoryBean1(factoryBuilder); return new JpaTransactionManager(bean.getObject()); } }
(2)第二個JPA的配置
@Configuration @EnableJpaRepositories(basePackages = "com.hopec.jpa2.repository2",transactionManagerRef = "platformTransactionManager2",entityManagerFactoryRef = "localContainerEntityManagerFactoryBean2") public class JpaConfigTwo { @Autowired @Qualifier(value = "dsTwo") DataSource dsTwo; @Autowired JpaProperties jpaProperties; @Bean LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean2(EntityManagerFactoryBuilder factoryBuilder){ return factoryBuilder.dataSource(dsTwo) //設置數據源 .properties(jpaProperties.getProperties()) //獲取配置信息 .packages("com.hopec.jpa2.model") //設置掃描的實體類的包 .persistenceUnit("name2") //持久化單元的名稱 不同的對象的名字不同就可以 .build(); } @Bean PlatformTransactionManager platformTransactionManager2(EntityManagerFactoryBuilder factoryBuilder){ LocalContainerEntityManagerFactoryBean bean = localContainerEntityManagerFactoryBean2(factoryBuilder); return new JpaTransactionManager(bean.getObject()); } }
以上兩個JPA的配置主要是注意包名路徑的對應一定要保持一致。
7.持久層
(1)第一個持久層
public interface UserRepository1 extends JpaRepository<User,Integer>{ @Query(value = "select * from users where id=(select max(id) from users)",nativeQuery = true) User findMaxIdUser(); //自定義的屬性如何進行匹配 @Query(value = "insert into users(name,address) values(?1,?2)",nativeQuery = true) @Modifying @Transactional Integer addUser1(String name,String author); @Query(value = "insert into users(name,address) values(:name,:address)",nativeQuery = true) @Modifying @Transactional Integer addUser2(@Param("name") String name, @Param("address") String address); //自定義的對象與sql語句進行匹配 @Query(value = "insert into users(name,address) values(:#{#user.name},:#{#user.address})",nativeQuery = true) @Modifying @Transactional Integer addUser3(@Param("user") User user);
這里其實不需要寫這么復雜的,單純查詢所有用戶信息,JpaRepository里面已經實現了,這里自定義查詢和保存用戶方法是為了多學習一點如何在JPA中自定義查詢方法以及參數對應,也就是將自定義的方法中的普通參數或者對象與@Query中原生SQL的屬性對應起來。
(2)第二個持久層
public interface UserRepository2 extends JpaRepository<User,Integer>{ }
實際上在本例中是這樣的,不需要第一個那么復雜,第一個只是作為擴展的參考。
8.測試
@Test public void test1(){ List<User> users = userRepository1.findAll(); System.out.println(users); List<User> users1 = userRepository2.findAll(); System.out.println(users1); } @Test public void test2(){ User user = new User(); user.setName("123"); user.setAddress("石家庄"); Integer r = userRepository1.addUser3(user); System.out.println(r); }
測試結果:

最后大功告成!
