[新增功能](master): JPA多数据源

dev-protocol-shardingtask 目前支持了JPA的多数据源方案1

待补充:JPA的多数据源2 及 ShardingJDBC的多数据源
master
土豆兄弟 3 years ago
parent d72f2ce8b4
commit 1f5c08df34

@ -15,6 +15,8 @@
- 智能网关设计 - 智能网关设计
dev-protocol-devops dev-protocol-devops
- DevOps 相关的最佳实现 - DevOps 相关的最佳实现
dev-protocol-shardingtask
- 配置多数据源和分表分库实现
### 1.1 基本命令(dev-protocol-log) ### 1.1 基本命令(dev-protocol-log)
- Kafka - Kafka

@ -1,6 +1,6 @@
package com.baiye.controller; package com.baiye.controller;
import com.baiye.entity.Notebook; import com.baiye.dao.entity.Notebook;
import com.baiye.repository.NotebookRepository; import com.baiye.repository.NotebookRepository;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;

@ -1,4 +1,4 @@
package com.baiye.entity; package com.baiye.dao.entity;
import javax.persistence.Column; import javax.persistence.Column;

@ -1,7 +1,7 @@
package com.baiye.repository; package com.baiye.repository;
import com.baiye.entity.Notebook; import com.baiye.dao.entity.Notebook;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;

@ -0,0 +1,10 @@
## 场景描述
场景:
假设订单库使用了分表分库
订单相关的SKU使用的是别的库
技术框架:
SpringBoot + ShardingSphere + JPA / dynamic-datasource
## 实现功能
多数据源动态切换整合分表分库实现

@ -0,0 +1,20 @@
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for order
-- ----------------------------
DROP TABLE IF EXISTS `order`;
CREATE TABLE `order`
(
`id` bigint(20) NOT NULL COMMENT 'id',
`order_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`order_price` decimal(10, 2) NOT NULL,
`order_time` datetime(0) NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB
CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci
ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;

@ -0,0 +1,65 @@
<?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">
<parent>
<artifactId>dev-protocol</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dev-protocol-shardingtask</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- 目前不使用这个来切换数据源 -->
<!-- <dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.apache.shardingsphere</groupId>-->
<!-- <artifactId>sharding-jdbc-spring-boot-starter</artifactId>-->
<!-- <version>4.1.1</version>-->
<!-- </dependency>-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,39 @@
package com.baiye;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.Iterator;
/**
* appication
*
* @author q
* @date 2021/11/29
*/
@SpringBootApplication
public class DevProtocolsShardingTaskApplication {
public static void main(String[] args) {
// todo 这里先拿到上下文一会检查下配置
ConfigurableApplicationContext context = new SpringApplicationBuilder(DevProtocolsShardingTaskApplication.class)
.run(args);
// 检查Beans加载
checkAllBeansWithName(context);
}
private static void checkAllBeansWithName(ConfigurableApplicationContext context) {
Iterator<String> beanNamesIterator = context.getBeanFactory().getBeanNamesIterator();
int i = 0;
while (beanNamesIterator.hasNext()) {
System.out.println("bean number is : " + (i++) + "name is : " + beanNamesIterator.next());
}
}
}

@ -0,0 +1,95 @@
package com.baiye.configuration;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.util.StringUtils;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
/**
* source1
*
*
*
* @author q
* @date 2021/11/29
*/
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
basePackages = {"com.baiye.dao.db1"},//数据源1的repository的包路径
entityManagerFactoryRef = "db1EntityManagerFactory",//改变数据源1的EntityManagerFactory的默认值改为db1EntityManagerFactory
transactionManagerRef = "db1TransactionManager"//改变数据源1的transactionManager的默认值改为db1TransactionManager
)
public class DataSource1Config {
/**
* 1dataSource
*
* @see ConfigurationProperties 1dbspring.datasource1
*/
@Primary
@Bean(name = "db1DataSourceProperties")
@ConfigurationProperties("spring.datasource1")
public DataSourceProperties dataSourceProperties() {
return new DataSourceProperties();
}
/**
* HikariDataSource1
*
* @see ConfigurationProperties 1hikarikey
* @param db1DataSourceProperties
* @return
*/
@Primary
@Bean(name = "db1DataSource")
@ConfigurationProperties(prefix = "spring.datasource.hikari.db1")
public HikariDataSource dataSource(@Qualifier("db1DataSourceProperties") DataSourceProperties db1DataSourceProperties) {
HikariDataSource dataSource = db1DataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
if (StringUtils.hasText(db1DataSourceProperties.getName())) {
dataSource.setPoolName(db1DataSourceProperties.getName());
}
return dataSource;
}
/**
* 1entityManagerFactorydb1EntityManagerFactory
* @param builder
* @param db1DataSource entityManagerdb1DataSource
* @return
*/
@Primary
@Bean(name = "db1EntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder, @Qualifier("db1DataSource") DataSource db1DataSource) {
return builder.dataSource(db1DataSource)
//数据1的实体所在的路径
.packages("com.baiye.dao.db1")
// persistenceUnit的名字采用db1
.persistenceUnit("db1")
.build();
}
/**
* 1db1TransactionManagerdb1EntityManagerFactory
* @param db1EntityManagerFactory
* @return
*/
@Primary
@Bean(name = "db1TransactionManager")
public PlatformTransactionManager transactionManager(@Qualifier("db1EntityManagerFactory") EntityManagerFactory db1EntityManagerFactory) {
return new JpaTransactionManager(db1EntityManagerFactory);
}
}

@ -0,0 +1,93 @@
package com.baiye.configuration;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.util.StringUtils;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
/**
* source2
*
* @author q
* @date 2021/11/29
*/
@Configuration
@EnableTransactionManagement//开启事务
//利用EnableJpaRepositories配置哪些包下面的Repositories采用哪个 EntityManagerFactory 和哪个 transactionManager
@EnableJpaRepositories(
basePackages = {"com.baiye.dao.db2"},//数据源2的repository的包路径
entityManagerFactoryRef = "db2EntityManagerFactory",//改变数据源2的EntityManagerFactory的默认值改为db2EntityManagerFactory
transactionManagerRef = "db2TransactionManager"//改变数据源2的transactionManager的默认值改为db2TransactionManager
)
public class DataSource2Config {
/**
* 2dataSource
*
* 2dbspring.datasource2
* @return
*/
@Bean(name = "db2DataSourceProperties")
@ConfigurationProperties("spring.datasource2")
public DataSourceProperties dataSourceProperties() {
return new DataSourceProperties();
}
/**
* HikariDataSource2
*
* 2hikarikey
*
* @param db2DataSourceProperties
* @return
*/
@Bean(name = "db2DataSource")
@ConfigurationProperties(prefix = "spring.datasource.hikari.db2")
public HikariDataSource dataSource(@Qualifier("db2DataSourceProperties") DataSourceProperties db2DataSourceProperties) {
HikariDataSource dataSource = db2DataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
if (StringUtils.hasText(db2DataSourceProperties.getName())) {
dataSource.setPoolName(db2DataSourceProperties.getName());
}
return dataSource;
}
/**
* 2entityManagerFactorydb2EntityManagerFactory
*
* @param builder
* @param db2DataSource entityManagerdb2DataSource
* @return
*/
@Bean(name = "db2EntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder, @Qualifier("db2DataSource") DataSource db2DataSource) {
return builder.dataSource(db2DataSource)
//数据2的实体所在的路径
.packages("com.baiye.dao.db2")
// persistenceUnit的名字采用db2
.persistenceUnit("db2")
.build();
}
/**
* 2db2TransactionManagerdb2EntityManagerFactory
*
* @param db2EntityManagerFactory
* @return
*/
@Bean(name = "db2TransactionManager")
public PlatformTransactionManager transactionManager(@Qualifier("db2EntityManagerFactory") EntityManagerFactory db2EntityManagerFactory) {
return new JpaTransactionManager(db2EntityManagerFactory);
}
}

@ -0,0 +1,35 @@
package com.baiye.controller;
import com.baiye.dao.db1.Order;
import com.baiye.dao.db1.OrderRepository;
import com.baiye.dao.db2.Sku;
import com.baiye.dao.db2.SkuRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OrderController {
@Autowired
private OrderRepository orderRepository;
@Autowired
private SkuRepository skuRepository;
/**
*
*
* @param order
* @return {@link Order}
*/
@PostMapping("/user")
public Order saveOrder(@RequestBody Order order) {
return orderRepository.save(order);
}
@PostMapping("/user/info")
public Sku saveUserInfo(@RequestBody Sku sku) {
return skuRepository.save(sku);
}
}

@ -0,0 +1,42 @@
package com.baiye.dao.db1;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.Date;
/**
* -1
*
* @author q
* @date 2021/11/29
*/
@Entity
@Table(name = "order")
public class Order {
/**
* id
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
*
*/
@Column(name = "order_name")
private String orderName;
/**
*
*/
@Column(name = "order_price")
private BigDecimal orderPrice;
/**
*
*/
@Column(name = "order_time")
private Date orderTime;
}

@ -0,0 +1,14 @@
package com.baiye.dao.db1;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
/**
*
*
* @author q
* @date 2021/11/29
*/
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
}

@ -0,0 +1,42 @@
package com.baiye.dao.db2;
import javax.persistence.*;
/**
* sku -2
*
* @author q
* @date 2021/11/29
*/
@Entity
@Table(name = "sku")
public class Sku {
/**
* id
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
/**
*
*/
private String name;
/**
*
*/
private String level;
/**
*
*/
private String color;
/**
*
*/
private String size;
}

@ -0,0 +1,14 @@
package com.baiye.dao.db2;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
/**
* sku
*
* @author q
* @date 2021/11/29
*/
@Repository
public interface SkuRepository extends JpaRepository<Sku, Long> {
}

@ -0,0 +1,7 @@
# 加载不同的配置文件,进行配置文件分离
spring:
profiles:
include:
- jpa
# - shardingSphere
# - dynamicDatasource

@ -0,0 +1,10 @@
# 基本配置
server:
port: 8088
spring:
application:
name: dev-protocol-shardingtask
# 加载不同环境
profiles:
active: dev

@ -0,0 +1,28 @@
spring:
###########datasource1 采用Mysql数据库
datasource1:
url: jdbc:mysql://localhost:3306/test2?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&rewriteBatchedStatements=true
username: root
password: root
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
##数据源1的连接池的名字
db1:
pool-name: jpa-hikari-pool-db1
## 最长生命周期15分钟
maxLifetime: 900000
maximumPoolSize: 8
###########datasource2 采用h2内存数据库
datasource2:
url: jdbc:h2:~/test
username: sa
password: sa
datasource:
driver-class-name: org.h2.Driver
hikari:
##数据源2的连接池的名字
db2:
pool-name: jpa-hikari-pool-db2
maxLifetime: 500000
maximumPoolSize: 6

@ -14,6 +14,7 @@
<module>dev-protocol-common</module> <module>dev-protocol-common</module>
<module>dev-protocol-gateway</module> <module>dev-protocol-gateway</module>
<module>dev-protocol-devops</module> <module>dev-protocol-devops</module>
<module>dev-protocol-shardingtask</module>
</modules> </modules>
<properties> <properties>

Loading…
Cancel
Save