工具篇-Spring boot JPA多数据源
写这篇博文是因为这个东西坑太多,首先说明下边实现的多数据源不是动态切换的,应该算是静态的。另外,如果对Spring JPA不熟悉的话,可以参见:SpringBoot 中 JPA 的使用
坑一、pom文件
pom中spring boot以及mysql connector的版本一定要注意。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
<relativePath/>
</parent> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<springboot.version>1.5.8.RELEASE</springboot.version>
<java.version>1.8</java.version>
<spring.boot.mainclass>xxxx.data.xxxx.Application</spring.boot.mainclass>
</properties> <dependencies>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-aop</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-beans</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-context</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-core</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-expression</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>jackson-annotations</artifactId>
<groupId>com.fasterxml.jackson.core</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${springboot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${springboot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>${springboot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${springboot.version}</version>
<scope>test</scope>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.36</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>1.5.8.RELEASE</version>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${springboot.version}</version>
<configuration>
<!--<fork>true</fork>
<mainClass>${spring.boot.mainclass}</mainClass>-->
<layout>ZIP</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
坑二、config文件
有DataSourceConfig、PrimaryConfig、SecondaryConfig三个配置文件,路径大概是这样的:


首先DataSourceConfig:
/**
* Multi datasource profile.
* @date 2019/04/26 10:58
*/ @Configuration
public class DataSourceConfig {
@Bean(name = "primaryDataSource")
@Qualifier("primaryDataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
} @Bean(name = "secondaryDataSource")
@Qualifier("secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
}
PrimaryConfig:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef="entityManagerFactoryPrimary",
transactionManagerRef="transactionManagerPrimary",
basePackages = {"xxxx.data.xxxx.dao.primary.*"})
public class PrimaryConfig { @Autowired
@Qualifier("primaryDataSource")
private DataSource primaryDataSource; @Autowired(required = false)
private JpaProperties jpaProperties; /**
* EntityManager profile.
*/
@Primary
@Bean(name = "entityManagerPrimary")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactoryPrimary(builder).getObject().createEntityManager();
} /**
* EntityManagerFactory profile.
*/
@Primary
@Bean(name = "entityManagerFactoryPrimary")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryPrimary(EntityManagerFactoryBuilder builder) {
return builder.dataSource(primaryDataSource)
.properties(getVendorProperties(primaryDataSource))
.packages("xxxx.data.xxxx.entity.primary.*")
.persistenceUnit("primaryPersistenceUnit")
.build();
} /**
* Jpa profile.
*/
private Map<String, String> getVendorProperties(DataSource dataSource) {
return jpaProperties.getHibernateProperties(dataSource);
} /**
* Transaction profile.
*/
@Primary
@Bean(name = "transactionManagerPrimary")
public PlatformTransactionManager transactionManagerPrimary(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactoryPrimary(builder).getObject());
}
}
SecondaryConfig:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef="entityManagerFactorySecondary",
transactionManagerRef="transactionManagerSecondary",
basePackages = {"xxxx.data.xxxx.dao.secondary.*"})
public class SecondaryConfig {
@Autowired
@Qualifier("secondaryDataSource")
private DataSource secondaryDataSource; @Autowired(required = false)
private JpaProperties jpaProperties; /**
* EntityManager profile.
*/
@Bean(name = "entityManagerSecondary")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactorySecondary(builder).getObject().createEntityManager();
} /**
* EntityManagerFactory profile.
*/
@Bean(name = "entityManagerFactorySecondary")
public LocalContainerEntityManagerFactoryBean entityManagerFactorySecondary (EntityManagerFactoryBuilder builder) {
return builder
.dataSource(secondaryDataSource)
.properties(getVendorProperties(secondaryDataSource))
.packages("xxxx.data.xxxx.entity.secondary.*")
.persistenceUnit("secondaryPersistenceUnit")
.build();
} /**
* Jpa profile.
*/
private Map<String, String> getVendorProperties(DataSource dataSource) {
return jpaProperties.getHibernateProperties(dataSource);
} /**
* Transaction profile.
*/
@Bean(name = "transactionManagerSecondary")
public PlatformTransactionManager transactionManagerSecondary(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactorySecondary(builder).getObject());
} }
上边这些配不好,就会报一些烂七八糟的错误:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'operationLogAspect': Unsatisfied dependency expressed through field 'jobOperationLogDao'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'xxxxxxDao': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class xxxxxx
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) ~[spring-beans-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) [spring-boot-1.5.8.RELEASE.jar:1.5.8.RELEASE]
at yidian.data.bear.Application.main(Application.java:18) [classes/:na]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'xxxxxxxDao': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class ......
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.
... 19 common frames omitted
Caused by: java.lang.IllegalArgumentException: Not a managed type: class
当然,如果你使用Springboot2.x的话,getHibernateProperties方法会报错的,对于这种情况,可以参考:https://blog.csdn.net/MrCoderStack/article/details/88658069,附上上边链接中的一张图片。

坑三、数据库配置文件
application-test.properties中配置了两个数据源,注意.url不好使的话,换成.jdbc.url试试:
#########################################################
### Primary DataSource -- DataSource 1 configuration ###
#########################################################
spring.datasource.primary.url=jdbc:mysql://ip:3307/数据库名
spring.datasource.primary.username=用户名
spring.datasource.primary.password=密码
spring.datasource.primary.driver-class-name=com.mysql.jdbc.Driver #########################################################
### Secondary DataSource -- DataSource 2 configuration ##
#########################################################
spring.datasource.secondary.url=jdbc:mysql://ip:3309/数据库名
spring.datasource.secondary.username=用户名
spring.datasource.secondary.password=密码
spring.datasource.secondary.driver-class-name=com.mysql.jdbc.Driver #########################################################
### Java Persistence Api -- Spring jpa configuration ###
#########################################################
# Specify the DBMS
spring.jpa.database=mysql
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
# Hibernate ddl auto (create, create-drop, update, validate)
spring.jpa.hibernate.ddl-auto=validate
# Naming strategy
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
# stripped before adding them to the entity manager
#spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
坑四、Entity映射无自增Id数据库表
JPA entity映射数据库表时需要一个唯一Id,而有的数据库表没有id怎么办,但是如果存在联合主键的话你可以采取IdClass注解的方式,这样的好处是写dao层代码方便,首先把联合主键封装成一个类,如下所示:
public class ScPK implements Serializable {
@Column(name = "student_name")
private String studentName;
@Column(name = "course_name")
private String courseName;
private String score;
public String getStudentName() {
return studentName;
}
public void setStudentName(String studentName) {
this.studentName = studentName;
}
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public String getScore() {
return score;
}
public void setScore(String score) {
this.score = score;
}
}
然后是实体类:
@Entity
@Table(name = "test")
@IdClass(ScPK.class)
public class ScEntity {
@Id
@Column(name = "student_name")
private String studentName;
@Id
@Column(name = "course_name")
private String courseName; private String score; public String getStudentName() {
return studentName;
} public void setStudentName(String studentName) {
this.studentName = studentName;
} public String getCourseName() {
return courseName;
} public void setCourseName(String courseName) {
this.courseName = courseName;
} public String getScore() {
return score;
} public void setScore(String score) {
this.score = score;
}
}
也附上dao层代码吧,这里studentName、courseName与实体类中属性保持一致,与数据库表无关:
@Repository
public interface ScDao extends JpaRepository<ScEntity, Long> { @Query("select l from ScEntity l where l.studentName = :studentName and l.courseName = :courseName")
ScEntity findAllByStudentNameAndCourseName(@Param("studentName") String studentName, @Param("courseName") String courseName);
}
坑五、SpringBoot项目改多数据源后debug启动不起来
我就纳闷怎么改了多数据源,debug启动服务就起不来了,用postman也访问不了。有位大哥or大姐(https://www.cnblogs.com/fightingting/p/9683811.html)说自己几个月一直启动很慢,我是直接起不来了偶偶,幸亏ta提醒:idea左下角出现一行小字,Method breakpoints may dramatically slow down debugging,启动Springboot项目之前把断点去掉就解决了。
坑刘、Hibernate整合SpringBoot配置多数据源后8小时无操作数据库连接失效
问题:应用8小时不访问数据库,数据库连接自动失效访问失败,报错如下:

解决办法:在上面的properties中增加如下配置:
spring.datasource.primary.test-while-idle=true
spring.datasource.secondary.test-while-idle=true
工具篇-Spring boot JPA多数据源的更多相关文章
- spring boot jpa 多数据源配置
在实际项目中往往会使用2个数据源,这个时候就需要做额外的配置了.下面的配置在2.0.1.RELEASE 测试通过 1.配置文件 配置两个数据源 spring.datasource.url=jdbc:m ...
- Spring Boot(五):Spring Boot Jpa 的使用
在上篇文章Spring Boot(二):Web 综合开发中简单介绍了一下 Spring Boot Jpa 的基础性使用,这篇文章将更加全面的介绍 Spring Boot Jpa 常见用法以及注意事项. ...
- (转)Spring Boot(五):Spring Boot Jpa 的使用
http://www.ityouknow.com/springboot/2016/08/20/spring-boot-jpa.html 在上篇文章Spring Boot(二):Web 综合开发中简单介 ...
- Spring Boot Jpa 的使用
Spring Boot Jpa 介绍 首先了解 Jpa 是什么? Jpa (Java Persistence API) 是 Sun 官方提出的 Java 持久化规范.它为 Java 开发人员提供了一种 ...
- Spring Boot + JPA(hibernate 5) 开发时,数据库表名大小写问题
(转载)Spring Boot + JPA(hibernate 5) 开发时,数据库表名大小写问题 这几天在用spring boot开发项目, 在开发的过程中遇到一个问题hibernate在执 ...
- Springboot spring data jpa 多数据源的配置01
Springboot spring data jpa 多数据源的配置 (说明:这只是引入了多个数据源,他们各自管理各自的事务,并没有实现统一的事务控制) 例: user数据库 global 数据库 ...
- Spring Boot JPA 连接数据库
本文将介绍怎样在Spring Boot project中加入JPA作为持久化方式. 改动 pom.xml 依赖 与上一篇介绍的 jdbc 不同的是 spring-boot-starter-jdbc 改 ...
- Spring Boot与多数据源那点事儿~
持续原创输出,点击上方蓝字关注我 目录 前言 写这篇文章的目的 什么是多数据源? 何时用到多数据源? 整合单一的数据源 整合Mybatis 多数据源如何整合? 什么是动态数据源? 数据源切换如何保证线 ...
- spring boot jpa 使用update 报错解决办法
在spring boot jpa 中自定义sql,执行update操作报错解决办法: 在@Query(...)上添加 @Modifying@Transactional注解
随机推荐
- SpringBoot技术栈搭建个人博客【项目准备】
前言:很早之前就想要写一个自己的博客了,趁着现在学校安排的实习有很多的空档,决定把它给做出来,也顺便完成实习的任务(搞一个项目出来...) 需求分析 总体目标:设计一套自适应/简洁/美观/易于文章管理 ...
- DocX开源WORD操作组件的学习系列四
DocX学习系列 DocX开源WORD操作组件的学习系列一 : http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_sharp_001_docx1.htm ...
- 使用yum安装不知道到底安装在什么文件夹
find /* >yum001 #记录之前的文件夹 find /* >yum002 #记录安装完成后的文件夹 diff yum001 yum002 >yum000 ...
- 写在最前面 - 《看懂每一行代码 - kubernetes》
我要写什么 <看懂每一行代码 - kubernetes>会包含k8s整个项目的源码解析,考虑到门槛问题,在开始分析k8s之前我会通过一些更低难度的golang开源项目讲解来帮助大家提升go ...
- Java提高班(二)深入理解线程池ThreadPool
本文你将获得以下信息: 线程池源码解读 线程池执行流程分析 带返回值的线程池实现 延迟线程池实现 为了方便读者理解,本文会由浅入深,先从线程池的使用开始再延伸到源码解读和源码分析等高级内容,读者可根据 ...
- Perl线程队列:Thread::Queue
(Thread::Queue)队列数据结构(FIFO)是线程安全的,它保证了某些线程从一端写入数据,另一些线程从另一端读取数据.只要队列已经满了,写入操作就自动被阻塞直到有空间支持写操作,只要队列空了 ...
- Springboot 系列(二)Spring Boot 配置文件
注意:本 Spring Boot 系列文章基于 Spring Boot 版本 v2.1.1.RELEASE 进行学习分析,版本不同可能会有细微差别. 前言 不管是通过官方提供的方式获取 Spring ...
- 第57章 GrantValidationResult - Identity Server 4 中文文档(v1.0.0)
该GrantValidationResult类模型补助确认为扩展授权和资源所有者密码授权的结果. 最常见的用法是使用身份验证(成功用例): context.Result = new GrantVali ...
- 第24章 退出 - Identity Server 4 中文文档(v1.0.0)
注销IdentityServer就像删除身份验证cookie一样简单,但是为了完成联合注销,我们必须考虑将用户从客户端应用程序(甚至可能是上游身份提供者)中签名. 24.1 删除认证 要删除身份验证c ...
- tar -P参数含义
-p(小写) :保留备份数据的原本权限与属性,常用于备份(-c) 重要的配置文件-P(大写) :保留绝对路径,亦即允许备份数据中含有根目录存在之意: 在加上绝对路径出现的那个警告讯息“tar: Rem ...