1. 程式人生 > >spring-boot和JPA多資料來源整合

spring-boot和JPA多資料來源整合

今天弄一下spring-boot和jpa的多資料來源整合

Jpa(Java Persistence API)Java持久化API,它是一套ORM規範

只是一套規範

Spring Boot中使用的Jpa實際上是Spring Data Jpa,Spring Data是Spring家族的一個子專案,用於簡化SQL和NoSQL的訪問,在Spring Data中,只要你的方法名稱符合規範,它就知道你想幹嘛,不需要自己再去寫SQL。

接下來我們簡單來弄下,直接

在idea裡建立spring-boot工程,勾選web裡的web和sql裡的JPA和mysql依賴

 

然後在依賴裡,寫一下mysql的版本,一般五點幾就行了,再新增Druid依賴

依賴如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.liy</groupId>
    <artifactId>jpa</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>jpa</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <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>
            <version>5.1.27</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

 

然後寫配置資訊

application.properties

spring.datasource.one.username=root
spring.datasource.one.password=root
spring.datasource.one.url=jdbc:mysql:///again
spring.datasource.one.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.one.type=com.alibaba.druid.pool.DruidDataSource

spring.datasource.two.username=root
spring.datasource.two.password=root
spring.datasource.two.url=jdbc:mysql:///demo
spring.datasource.two.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.two.type=com.alibaba.druid.pool.DruidDataSource




#資料庫平臺
spring.jpa.properties.database-platform=mysql
#如果再次執行,檢查表是否要更新
spring.jpa.properties.hibernate.ddl-auto=update
#sql資訊列印
spring.jpa.properties.show-sql=true
#定義資料庫的方言
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect

spring.jpa.properties.database=mysql

寫個bean類。寫好bean類就可以執行下工程,它會自動在資料庫裡生成相對應的表

package com.liy.bean;

import javax.persistence.*;

//生成資料庫表的關鍵註解,後面的name是表名
@Entity(name = "book")
public class Book { 
    //必須寫個id
    @Id
   //也必須設定為主鍵,以及自增長
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
  
    //給他起別名,  設定約束什麼的也是@Column註解裡去設定
    @Column(name = "bookname")
    private String username;

    private String auther;


    public Book() {
        super();
    }

    public Book(String username, String auther) {
        this.username = username;
        this.auther = auther;
    }



    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
    }

    @Override
    public String toString() {
        return "Book{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", auther='" + auther + '\'' +
                '}';
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAuther() {
        return auther;
    }

    public void setAuther(String auther) {
        this.auther = auther;
    }
}

 

 

然後寫個區分兩個資料的DataSource配置類

DataSourceConfig

@Configuration
public class DataSourceConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.one")
    @Primary
    DataSource dsOne(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.two")
    DataSource dsTwo(){
        return DruidDataSourceBuilder.create().build();
    }
}

 

然後寫兩個jpa的配置類,分別對應兩個資料來源

JpaConfig


@Configuration
@EnableJpaRepositories(basePackages = "com.liy.dao1",
        entityManagerFactoryRef = "localContainerEntityManagerFactoryBeanOne",
        transactionManagerRef = "platformTransactionManagerOne")
public class JpaConfig {

    @Autowired
    @Qualifier(value = "dsOne")
    DataSource dsOne;

    @Autowired
    JpaProperties jr;

    @Bean
    @Primary
    LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBeanOne(EntityManagerFactoryBuilder builder){
        return builder.dataSource(dsOne)
                .properties(jr.getProperties())
                .packages("com.liy.bean")
                .persistenceUnit("pu1")
                .build();

    }

    @Bean
    @Primary
    PlatformTransactionManager platformTransactionManagerOne(EntityManagerFactoryBuilder builder){
        LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = localContainerEntityManagerFactoryBeanOne(builder);
        return new JpaTransactionManager(localContainerEntityManagerFactoryBean.getObject());
    }
}

 

JpaConfig1 ,其中程式碼基本一樣,要在一個配置類中的兩個方法都加上@Primary註解   ,我都加在上面那個了

@Configuration
@EnableJpaRepositories(basePackages = "com.liy.dao2",
        entityManagerFactoryRef = "localContainerEntityManagerFactoryBeanTwo",
        transactionManagerRef = "platformTransactionManagerTwo")
public class JpaConfig1 {

    @Autowired
    @Qualifier(value = "dsTwo")
    DataSource dsTwo;

    @Autowired
    JpaProperties jr;

    @Bean
    LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBeanTwo(EntityManagerFactoryBuilder builder){
        return builder.dataSource(dsTwo)
                .properties(jr.getProperties())
                .packages("com.liy.bean")
                .persistenceUnit("pu2")
                .build();

    }

    @Bean
    PlatformTransactionManager platformTransactionManagerTwo(EntityManagerFactoryBuilder builder){
        LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = localContainerEntityManagerFactoryBeanTwo(builder);
        return new JpaTransactionManager(localContainerEntityManagerFactoryBean.getObject());
    }
}

 

然後根據上面JpaConfig的掃描負責的包來寫兩個dao包

BookDao1

package com.liy.dao1;

import com.liy.bean.Book;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

public interface BookDao1 extends JpaRepository<Book,Integer> {

    //方法名可以靠拼接,相當於自定義sql
    public List<Book> findBookByIdGreaterThanAndAndUsernameContains(Integer id,String usernames);

    @Query(value = "select count(*) from book",nativeQuery = true)
    public long TotalCount();

    //如果sql語句不是查詢,那麼必須加@Modifying註解
    //另外在對資料庫進行DML(update,delete,insert)操作時,必須加上事物,也就是@Transactional
    //@Transactional記得不要導錯包
    //import org.springframework.transaction.annotation.Transactional;
    @Query(value = "update book set auther=:auther  where id=:id",nativeQuery = true)
    @Modifying
    @Transactional
    public int update(@Param("id") int id,@Param("auther") String auther);

    @Query(value = "update book set bookname=:bookname  where id=:id",nativeQuery = true)
    @Modifying
    public int update1(@Param("id") int id ,@Param("bookname") String bookname);


}

 

BookDao2

package com.liy.dao2;

import com.liy.bean.Book;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;

public interface BookDao2 extends JpaRepository<Book,Integer> {


    @Query(value = "update book set auther=:auther  where id=:id",nativeQuery = true)
    @Modifying
    @Transactional
    public int update1(@Param("id") int id,@Param("auther") String auther);



}

 

然後在spring-boot自帶的測試類裡進行測試

package com.liy;

import com.liy.bean.Book;
import com.liy.dao1.BookDao1;
import com.liy.dao2.BookDao2;
import com.liy.service.BookService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

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

    @Autowired
    BookDao1 db1;

    @Autowired
    BookDao2 db2;


    @Test
    public void updateMany(){
        db1.update(3,"liy1");
        db2.update1(3,"liy1");
    }

    @Test
    public void TestFind() {

        List<Book> a = db1.findBookByIdGreaterThanAndAndUsernameContains(1, "a");
        System.out.println(a);
        long l = db1.TotalCount();
        System.out.println(l);
        db1.update(3,"aaaa");
    }


    @Test
    public void contextLoads() {
        Book book = new Book("老夫子", "afaf");
        db1.save(book);
    }

    @Test
    public void update(){
        Book book = new Book("老夫子", "老夫");
        book.setId(1);
        db1.saveAndFlush(book);
    }

    @Test
    public void find(){

        List<Book> all = db1.findAll(Sort.by(new Sort.Order(Sort.Direction.DESC, "id")));
        System.out.println(all);
    }

    @Test
    public void findPage(){
        PageRequest data = PageRequest.of(0, 2);
        System.out.println(data);
        Page<Book> page = db1.findAll(data);

        System.out.println(page.getNumberOfElements());//當前記錄數
        System.out.println(page.getNumber());//
        System.out.println(page.getSize());//每頁應該查到的記錄數
        System.out.println(page.isLast());//是否是最後一頁
        System.out.println(page.isFirst());//是否是第一頁
        System.out.println(page.getTotalPages());//總頁數
        System.out.println(page.getTotalElements());//總記錄數
        System.out.println(page.getContent());//當前頁的資料

    }
}

 

資料庫裡

在兩個資料庫裡用兩個表

第一個表是在spring-boot工程了寫了個bean類,自動生成的

我為了方便,直接把上面的複製了,表結構,資料都複製,然後下面的修改下就可以了

 

顯示運行了兩條sql語句,然後再看下資料庫裡資料是否改變即可

這個列印sql語句的在application.properties裡配置   我寫了註