工具篇-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注解
随机推荐
- MarkDown语法总结
MarkDown常用语法讲解,写博客使用. 一丶标题的设置. 标题设置使用#来区分一级标题,几个#代表几级标题. 图片如下. 二丶添加代码块,以及标记代码. 1.添加代码块使用语法三个 '设置 2.添 ...
- RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.2-> “Tab”标签新增可“最大化”显示功能
最大化工作区的功能是非常必要的,特别是当模块功能比较多时,把工作区最大的展现出来就变得很重要,RDIFramework.NET V3.2版本对工作区新增了最大功能,最大化工作区后如下图所示: 具体使 ...
- http无状态
说http无状态,客户端请求,建立一个链接,请求完毕既会关掉连接,避免占用通道,对处理业务逻辑没有记忆功能
- https 加密、http2.0、keep-alive
原文地址:https://ainyi.com/44 HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议 ...
- 程序员50题(JS版本)(一)
程序1:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? for(var i=1,sum=0;i<=4;i++){ for(var j=1;j<=4;j++){ ...
- WingMoney APP逆向,实现自动话费充值
主要难点,获取JWT内加密的token. 因为是打算使用写成c# winform版本的.所以折腾了很久.刚开始直接改写成c#版本始终有问题.最后决定先上eclipse,先使用java把数据读取出来. ...
- 【Webpack 杂谈】帮助文档翻译:Webpack的模块
页面出自Webpack官方文档(撰写时,是v4.1.1) 其实Webpack本身有中文文档,不知道是谁去撰写的,但是自己翻译一遍感觉更好理解. https://webpack.js.org/conce ...
- OpenUDID 和 IDFA 比较
iOS标识符 现今来比较下,不同情况下两种标识符的变化情况.以下试验,每种标识符均分为存于Keychain和未存于Keychain的两种情况做比较. 广告标识符(IDFA-identifierForI ...
- 集成Android人脸识别demo分享
本应用来源于虹软人工智能开放平台,人脸识别技术工程如何使用? 1.下载代码 git clone https://github.com/andyxm/ArcFaceDemo.git 2.下载虹软人脸识别 ...
- RN开发中的报错以及告警
报错一: Attempted to transition from state `RESPONDER_INACTIVE_PRESS_IN` to `RESPONDER_ACTIVE_LONG_PRES ...