工具篇-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注解
随机推荐
- ubuntu 修改网卡名称 更改设备网卡名称 修改eno16777736为eth0 ubuntu 15.10网卡名称为eno16777736
ubuntu linux 进入root用户,管理员模式 编辑这个文件需要管理员模式 在GRUB_CMD_LINUX后面增加图中所示 看到这个地方了没,有提示信息的,想要改变这个文件,记得运行 upda ...
- YYModel底层解析- Runtime
这段时间一直在忙新的需求,没有时间来整理代码,发表自己技术博客,今天我们来看一下YYModel的底层解析以及如何使用,希望对大家有所帮助! 一 概述 概括 YYModel是一个轻量级的JSON模型转换 ...
- 常用API。
object类: 1.equals方法: public boolean equals (Object obj) , 指示其他某个对象是否与此对象“相等” 源码:public boolean equal ...
- 【转载】ASP.NET MVC重写URL制作伪静态网页,URL地址以.html结尾
在搜索引擎优化领域,静态网页对于SEO的优化有着很大的好处,因此很多人就想把自己的网站的一些网页做成伪静态.我们现在在网络上发现很多博客网站.论坛网站.CMS内容管理系统等都有使用伪静态这一种情况,伪 ...
- vb.net MakeWParam
Private Function MakeWParam(loWord As Integer, hiWord As Integer) As Integer ) End Function
- xddpay.com 个人支付接口接入流程
作为一个独立开发者产品需要支付接口是挺麻烦的,支付宝微信都不对个人开放,注册公司维护成本太高,市面上各种收款工具要么手续费太高,要么到账很慢,体验很不好. 看到 「小叮当支付」 这个收款工具,挺有意思 ...
- 从零开始学安全(三十六)●利用python 爆破form表单
import sys import requests from requests.auth import HTTPBasicAuth def Brute_Force_Web(postData): re ...
- Java开发笔记(三)Java帝国的特种官吏
上一篇文章介绍了Java工程的帝国区划,末尾给出了一段Java代码例子,这个代码虽然勉强能看懂,但是有些细节令人不甚了了.比如说“// 参观朱雀台”为何能够直接跟在当前行后面?“System.out. ...
- bitset中_Find_first()与_Find_next()函数
bitset中_Find_first()与_Find_next()函数 很有趣但是没怎么有用的两个函数. _Find_fisrt就是找到从低位到高位第一个1的位置 #include<bits/s ...
- 十分钟(小时)学习pandas
十分钟学习pandas 一.导语 这篇文章从pandas官网翻译:链接,而且也有很多网友翻译过,而我为什么没去看他们的,而是去官网自己艰难翻译呢? 毕竟这是一个学习的过程,别人写的不如自己写的记忆深刻 ...