spring boot 整合JPA多數據源


  上個文章介紹了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);
    }

  測試結果:

 

    最后大功告成!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM