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裡配置 我寫了註