- pom依赖
org.springframework.boot
spring-boot-starter-data-jpa
mysql
mysql-connector-java
runtime
- spring boot 多数据源配置
#数据源配置 mysql8 使用com.mysql.cj.jdbc.Driver驱动,PS:serverTimezone=GMT需要加上,不然服务器时间不能同步
spring.datasource.test.driver-class-name=com.mysql.cj.jdbc.Driver
#新版本mysql,必须带上时区说明serverTimezone=GMT
#GMT会少了8小时,所以这里用GMT+8,转义后:GMT%2b8
spring.datasource.test.jdbc-url=jdbc\:mysql\://localhost\:3306/test?serverTimezone\=GMT%2b8&autoReconnect\=true&useUnicode\=true&characterEncoding\=UTF-8&useSSL\=true
spring.datasource.test.username=root
spring.datasource.test.password=
spring.datasource.test.max-idle=10
spring.datasource.test.max-wait=10000
spring.datasource.test.min-idle=5
spring.datasource.test.initial-size=5
#本地 订单数据源配置
spring.datasource.order.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.order.jdbc-url=jdbc\:mysql\://localhost\:3306/order?serverTimezone\=GMT%2b8&autoReconnect\=true&useUnicode\=true&characterEncoding\=UTF-8&useSSL\=true
spring.datasource.order.username=root
spring.datasource.order.password=
spring.datasource.order.max-idle=10
spring.datasource.order.max-wait=10000
spring.datasource.order.min-idle=5
spring.datasource.order.initial-size=5
#1.251 业务数据源配置
spring.datasource.report.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.report.jdbc-url=jdbc\:mysql\://192.168.1.251\:3306/gnota?serverTimezone\=GMT%2b8&autoReconnect\=true&useUnicode\=true&characterEncoding\=UTF-8&useSSL\=true
spring.datasource.report.username=root
spring.datasource.report.password=
spring.datasource.report.max-idle=10
spring.datasource.report.max-wait=10000
spring.datasource.report.min-idle=5
spring.datasource.report.initial-size=5
- spring boot jpa 配置
#SQL输出
spring.jpa.show-sql=true
#spring.jpa.properties.hibernate.hbm2ddl.auto说明
#create:Hibernate每次删除上次生成,然后根据实体重新生成表,哪怕实体没有变化也照样执行。
#create-drop:Hibernate每次根据实体生成表,sessionFactory关闭,表自动删除。
#update:比较常用,先建好数据库,Hibernate第一次根据实体自动建表,后面根据实体说明结构自动更新表结构,表一直存在。PS:发布服务器后,服务器启动不会立马执行,得到app调用
#validate:Hibernate每次验证创建数据库表结构,只会和数据库中的表进比较,不会创建新表,但是会插入新值。
spring.jpa.properties.hibernate.hbm2ddl.auto=update
#新版mysql方言MySQL5InnoDBDialect
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
#format SQL进⾏输出
spring.jpa.properties.hibernate.format_sql=true
#jpa多数据源配置后调用autoware dao接口可能会报相同bean名冲突
#2种方法可以解决,打开spring.main.allow-bean-definition-overriding或在springboot启动类添加注解
#@ComponentScan(nameGenerator = AnnotationBeanNameGenerator.class)
#如果junit测试,在类头部也要加上该注解
#这里用注解解决相同名bean冲突,所以注释了allow-bean-definition-overriding
#相同bean名覆盖注册 SpringBoot 2.1之前,这个配置默认就是true,而在2.1做了更改。
#spring.main.allow-bean-definition-overriding=true
- 针对不同数据源配置生成对应的DataSource的Configuration
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
/**
* 数据集源配置,此示例配置了3个数据源
*1,spring.datasource.test
*2,spring.datasource.order
*3,spring.datasource.report
* 通过配置文件中的前缀,区分数据源
* @author kyoxue
* @date 2019年10月28日
*/
@Configuration
public class DemoDBConfiguration {
/** 定义数据源 */
//默认数据源
@Primary
//bean名称
@Bean(name="orderDB")
//为数据源取别名区分
@Qualifier("orderDB")
//指定配置数据源前缀
@ConfigurationProperties("spring.datasource.order")
public DataSource orderDB() {
return DataSourceBuilder.create().build();
}
//bean名称
@Bean(name="reportDB")
//为数据源取别名区分
@Qualifier("reportDB")
//指定配置数据源前缀
@ConfigurationProperties("spring.datasource.report")
public DataSource reportDB() {
return DataSourceBuilder.create().build();
}
//bean名称
@Bean(name="testDB")
//为数据源取别名区分
@Qualifier("testDB")
//指定配置数据源前缀
@ConfigurationProperties("spring.datasource.test")
public DataSource testDB() {
return DataSourceBuilder.create().build();
}
}
- 使用对应的DataSource生成JPA对应的配置
主要工作内容:
1.通过DataSource的bean实例,实体对象的包路径来产生对应该数据源的jpa环境
2.生成JPA的对应api接口EntityManager
3.生成对应数据源的事务PlatformTransactionManager
有一定注意:EntityManagerFactoryBuilder此处的包路径为org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder
而非org.hibernate.jpa.boot.spi.EntityManagerFactoryBuilder
orderDB对应的JPA配置
package com.example.demo;
import java.util.Map;
import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
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;
/**
* 针对localhost:3306/order数据源的JPA配置
* ps:多数据源,JPA配置类至少有一个,其下所有方法添加primary注解
* 本示例primary写在test数据源配置中
* @author kyoxue
* @date 2019年10月30日
*/
//标识此为spring bean 配置类,启动时加载
@Configuration
//启用事务支持
@EnableTransactionManagement
@EnableJpaRepositories(
//JPA数据访问环境
entityManagerFactoryRef="localContainerEntityManagerFactoryBeanOrder",
//JPA事务
transactionManagerRef="transactionManagerOrder",
//dao接口包扫描
basePackages={"com.example.demo.dao.order"})
public class DemoJPAOrderConfiguration {
//引入orderDB数据源,别名orderDB与DemoDBConfiguration中@Qualifier("orderDB")一致
//注意:@Qualifier不可少,否则导致不能准确区分数据源
@Autowired
@Qualifier("orderDB")
private DataSource orderDB;
@Autowired
private JpaProperties jpaProperties;
@Resource
private HibernateProperties hibernateProperties;
private Map getVendorProperties() {
return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
}
/**
* 创建JPA数据访问环境
* @param entityManagerFactoryBuilder
* @return
*/
@Bean(name="localContainerEntityManagerFactoryBeanOrder")
public LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBeanOrder(org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder entityManagerFactoryBuilderOrder) {
return entityManagerFactoryBuilderOrder
//数据源
.dataSource(orderDB)
//JPA配置信息
.properties(getVendorProperties())
//实体类的包路径
.packages("com.example.demo.entity.order")
//JPA数据环境名称定义
.persistenceUnit("persistenceUnitOrder")
.build();
}
/**
* 操控数据库的对应API
* EntityManager是JPA中⽤于增、删、改、查的接⼝
* ,它的作⽤相当于⼀座桥梁
* ,连接内存中的Java对象 和数据库的数据存储。
* 使⽤EntityManager中的相关接⼝对数据库实体进⾏操作的时候
* ,EntityManager会跟踪实体对象的状态
* ,并决定在特定时刻将对实体的操作映射到数据库操作上⾯
* @param entityManagerFactoryBuilderOrder
* @return
*/
@Bean(name="entityManagerOrder")
public EntityManager entityManagerOrder(org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder entityManagerFactoryBuilderOrder){
return localContainerEntityManagerFactoryBeanOrder(entityManagerFactoryBuilderOrder).getObject().createEntityManager();
}
/**
* 给数据源添加JPA事务
* @param entityManagerFactoryBuilderOrder
* @return
*/
@Bean(name="transactionManagerOrder")
PlatformTransactionManager transactionManagerOrder(EntityManagerFactoryBuilder entityManagerFactoryBuilderOrder){
return new JpaTransactionManager(localContainerEntityManagerFactoryBeanOrder(entityManagerFactoryBuilderOrder).getObject());
}
}
reportDB对应的JPA配置
package com.example.demo;
import java.util.Map;
import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
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;
/**
* 针对192.168.1.251:3306/gnota数据源的JPA配置
* ps:多数据源,JPA配置类至少有一个,其下所有方法添加primary注解
* 本示例primary写在test数据源配置中
* @author kyoxue
* @date 2019年10月30日
*/
//标识此为spring bean 配置类,启动时加载
@Configuration
//启用事务支持
@EnableTransactionManagement
@EnableJpaRepositories(
//JPA数据访问环境
entityManagerFactoryRef="localContainerEntityManagerFactoryBeanReport",
//JPA事务
transactionManagerRef="transactionManagerReport",
//dao接口包扫描
basePackages={"com.example.demo.dao.report"})
public class DemoJPAReportConfiguration {
//引入reportDB数据源,属性名reportDB与DemoDBConfiguration中@Qualifier("reportDB")一致
@Autowired
@Qualifier("reportDB")
private DataSource reportDB;
@Autowired
private JpaProperties jpaProperties;
@Resource
private HibernateProperties hibernateProperties;
private Map getVendorProperties() {
return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
}
/**
* 创建JPA数据访问环境
* @param entityManagerFactoryBuilder
* @return
*/
@Bean(name="localContainerEntityManagerFactoryBeanReport")
public LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBeanReport(org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder entityManagerFactoryBuilderReport) {
return entityManagerFactoryBuilderReport
//数据源
.dataSource(reportDB)
//JPA配置信息
.properties(getVendorProperties())
//实体类的包路径
.packages("com.example.demo.entity.report")
//JPA数据环境名称定义
.persistenceUnit("persistenceUnitReport")
.build();
}
/**
* 操控数据库的对应API
* EntityManager是JPA中⽤于增、删、改、查的接⼝
* ,它的作⽤相当于⼀座桥梁
* ,连接内存中的Java对象 和数据库的数据存储。
* 使⽤EntityManager中的相关接⼝对数据库实体进⾏操作的时候
* ,EntityManager会跟踪实体对象的状态
* ,并决定在特定时刻将对实体的操作映射到数据库操作上⾯
* @param entityManagerFactoryBuilderReport
* @return
*/
@Bean(name="entityManagerReport")
public EntityManager entityManagerReport(org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder entityManagerFactoryBuilderReport){
return localContainerEntityManagerFactoryBeanReport(entityManagerFactoryBuilderReport).getObject().createEntityManager();
}
/**
* 给数据源添加JPA事务
* @param entityManagerFactoryBuilderReport
* @return
*/
@Bean(name="transactionManagerReport")
PlatformTransactionManager transactionManagerReport(EntityManagerFactoryBuilder entityManagerFactoryBuilderReport){
return new JpaTransactionManager(localContainerEntityManagerFactoryBeanReport(entityManagerFactoryBuilderReport).getObject());
}
}
testDB对应的JPA配置,注意一点:testDB这个JPA配置类每个bean方法都加了@Primary注解,可以任意一个配置类加@Primary注解,其余不用,但至少有一个配置类是这样的
package com.example.demo;
import java.util.Map;
import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
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;
/**
* 针对localhost:3306/test数据源的JPA配置
* ps:多数据源,JPA配置类至少有一个,其下所有方法添加primary注解
* @author kyoxue
* @date 2019年10月30日
*/
//标识此为spring bean 配置类,启动时加载
@Configuration
//启用事务支持
@EnableTransactionManagement
@EnableJpaRepositories(
//JPA数据访问环境
entityManagerFactoryRef="localContainerEntityManagerFactoryBeanTest",
//JPA事务
transactionManagerRef="transactionManagerTest",
//dao接口包扫描
basePackages={"com.example.demo.dao.test"})
public class DemoJPATestConfiguration {
//引入testDB数据源,属性名testDB与DemoDBConfiguration中@Qualifier("testDB")一致
@Autowired
@Qualifier("testDB")
private DataSource testDB;
@Autowired
private JpaProperties jpaProperties;
@Resource
private HibernateProperties hibernateProperties;
private Map getVendorProperties() {
return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
}
/**
* 创建JPA数据访问环境
* @param entityManagerFactoryBuilder
* @return
*/
@Bean(name="localContainerEntityManagerFactoryBeanTest")
@Primary
public LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBeanTest(org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder entityManagerFactoryBuilderTest) {
return entityManagerFactoryBuilderTest
//数据源
.dataSource(testDB)
//JPA配置信息
.properties(getVendorProperties())
//实体类的包路径
.packages("com.example.demo.entity.test")
//JPA数据环境名称定义
.persistenceUnit("persistenceUnitTest")
.build();
}
/**
* 操控数据库的对应API
* EntityManager是JPA中⽤于增、删、改、查的接⼝
* ,它的作⽤相当于⼀座桥梁
* ,连接内存中的Java对象 和数据库的数据存储。
* 使⽤EntityManager中的相关接⼝对数据库实体进⾏操作的时候
* ,EntityManager会跟踪实体对象的状态
* ,并决定在特定时刻将对实体的操作映射到数据库操作上⾯
* @param entityManagerFactoryBuilderTest
* @return
*/
@Bean(name="entityManagerTest")
@Primary
public EntityManager entityManagerTest(org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder entityManagerFactoryBuilderTest){
return localContainerEntityManagerFactoryBeanTest(entityManagerFactoryBuilderTest).getObject().createEntityManager();
}
/**
* 给数据源添加JPA事务
* @param entityManagerFactoryBuilderTest
* @return
*/
@Bean(name="transactionManagerTest")
@Primary
PlatformTransactionManager transactionManagerTest(EntityManagerFactoryBuilder entityManagerFactoryBuilderTest){
return new JpaTransactionManager(localContainerEntityManagerFactoryBeanTest(entityManagerFactoryBuilderTest).getObject());
}
}
- 对应配置中包位置建立dao接口已经实体类
-
testDB
image.png
image.png -
orderDB
image.png
image.png -
reportDB
image.png
image.png
- 对dao以及entity代码如下
/**
* 继承JpaRepository<实体名称,实体主键类型>,使用其内置大量常用API
* @author kyoxue
* @date 2019年10月31日
*/
@Qualifier("testJPA")
public interface TestJPADao extends JpaRepository {
}
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity(name="jpa_test")
public class EntityTestJPA {
@Id
@GeneratedValue
private Long id;
@Column
private String testName;
//setter...getter...
}
@Qualifier("orderJPA")
public interface OrderJPADao extends JpaRepository {
}
@Entity(name="jpa_order")
public class EntityOrder {
@Id
//主键生成策略GenerationType包括AUTO、INDENTITY、SEQUENCE和TABLE
//generator主键生成器名称
@GeneratedValue(strategy=GenerationType.AUTO,generator="order_generator")
private Long id;
@Column
private Date time;
@Column
private String orderNo;
//setter...getter...
}
@Qualifier("reportJPA")
public interface ReportJPADao extends JpaRepository {
}
@Entity(name = "jpa_report")
public class EntityReport {
@Id
@GeneratedValue
private Integer id;
@Column
private String reportName;
//setter...getter...
}
- junit测试多数据源操作
@RunWith(SpringRunner.class)
//因为项目用到了websocket,这里引入随机端口
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
//相同bean名冲突解决,springboot解决bean命名冲突可以加入这个注解,也可以在配置文件加入spring.main.allow-bean-definition-overriding=true
@ComponentScan(nameGenerator = AnnotationBeanNameGenerator.class)
public class applicationTest {
@Resource
private TestJPADao testJPA;
@Resource
private OrderJPADao orderJPA;
@Resource
private ReportJPADao reportJPA;
@Test
public void testEntityTestJPA()throws Exception{
EntityTestJPA vo = new EntityTestJPA();
vo.setTestName("ttt1");
testJPA.save(vo);
}
@Test
public void testEntityOrderJPA()throws Exception{
EntityOrder vo = new EntityOrder();
vo.setOrderNo("aaaa");
vo.setTime(new Date());
orderJPA.save(vo);
}
@Test
public void testEntityReportJPA()throws Exception{
EntityReport vo = new EntityReport();
vo.setReportName("tttttt");
reportJPA.save(vo);
}
}
- 查看数据库是否正确操作
-
testDB
image.png -
orderDB
image.png -
reportDB
image.png
- 至此,多数据源测试完毕。