springboot2.0.4整合springdatajpa和druid,双数据源

光焱      2022-04-10     107

关键词:

最近Team开始尝试使用Spring Boot + Spring Data JPA作为数据层的解决方案,在网上逛了几圈之后发现大家并不待见JPA,理由是(1)MyBatis简单直观够用,(2)以Hibernate为底层的Spring Data JPA复杂且性能一般。

但是当我们来到Spring Boot的世界后发现,相较于Spring Data JPA,MyBatis对Spring Boot的支持有限,Spring Data JPA与Spring Boot结合可以让dao变得非常简单,比如(1)JPA自带分页对象,无需设置插件;(2)一个空接口搞定所有基本CRUD。

本着虚心学习的态度,我决定将Spring Boot、Spring Data JPA和Druid三者整合在一起,并分别对SQL Server和MySQL进行支持,希望本文能够帮助到需要相关技术的同学。

1. 程序和版本

Spring Boot 2.0.4

mssql-jdbc 6.2.2.jre8

mysql-connector-java 5.1.46

druid-spring-boot-starter 1.1.10

2. properties配置文件

我们把主程序配置文件application.properties和数据库配置文件分开,这样可使application.properties不至于臃肿。

(1) application.properties

1 server.port=9006
2 spring.application.name=spring-data-jpa
3 
4 #Serialize JPA entity to Json string.
5 spring.jackson.serialization.fail-on-empty-beans=false

第5行的作用是避免com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer,该配置只对MSSQL数据源有效。

(2) db.properties

 1 #Data source 1
 2 db1.sqlserver.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
 3 db1.sqlserver.url=${DB1_URL:jdbc:sqlserver://127.0.0.1:1433;DatabaseName=MyTestDb1}
 4 db1.sqlserver.username=${DB1_UID:tester}
 5 db1.sqlserver.password=${DB1_PWD:tester}
 
6
db1.sqlserver.initial-size=1 7 db1.sqlserver.min-idle=1 8 db1.sqlserver.max-active=20 9 db1.sqlserver.max-wait=60000 10 db1.sqlserver.time-between-eviction-runs-millis=60000 11 db1.sqlserver.min-evictable-idle-time-millis=300000 12 db1.sqlserver.validation-query=select 1 13 db1.sqlserver.test-on-borrow=true 14 db1.sqlserver.test-While-Idle=true 15 db1.sqlserver.test-on-return=false 16 db1.sqlserver.pool-prepared-statements=false 17 db1.sqlserver.max-pool-prepared-statement-per-connection-size=20 18 19 db1.sqlserver.filter.stat.enabled=true 20 db1.sqlserver.filter.stat.db-type=mssql 21 db1.sqlserver.filter.stat.log-slow-sql=true 22 db1.sqlserver.filter.stat.slow-sql-millis=2000 23 24 db1.sqlserver.jpa.hibernate.dialect=org.hibernate.dialect.SQLServerDialect 25 db1.sqlserver.jpa.hibernate.show_sql=true 26 db1.sqlserver.jpa.hibernate.format_sql=true 27 28 #Data source 2 29 db2.mysql.driver-class-name=com.mysql.jdbc.Driver 30 db2.mysql.url=${DB2_URL:jdbc:mysql://127.0.0.1:3306/Test}?useUnicode=true&useSSL=false 31 db2.mysql.username=${DB2_UID:tester} 32 db2.mysql.password=${DB2_PWD:tester} 33 db2.mysql.initial-size=1 34 db2.mysql.min-idle=1 35 db2.mysql.max-active=20 36 db2.mysql.max-wait=60000 37 db2.mysql.time-between-eviction-runs-millis=60000 38 db2.mysql.min-evictable-idle-time-millis=300000 39 db2.mysql.validation-query=select 1 40 db2.mysql.test-on-borrow=true 41 db2.mysql.test-While-Idle=true 42 db2.mysql.test-on-return=false 43 db2.mysql.pool-prepared-statements=false 44 db2.mysql.max-pool-prepared-statement-per-connection-size=20 45 46 db2.mysql.filter.stat.enabled=true 47 db2.mysql.filter.stat.db-type=mysql 48 db2.mysql.filter.stat.log-slow-sql=true 49 db2.mysql.filter.stat.slow-sql-millis=2000 50 51 db2.mysql.jpa.hibernate.dialect=org.hibernate.dialect.MySQLDialect 52 db2.mysql.jpa.hibernate.show_sql=true 53 db2.mysql.jpa.hibernate.format_sql=true 54 db2.mysql.jpa.hibernate.enable_lazy_load_no_trans=true

该配置文件可分为三部分:一是JPA的数据源基本信息配置(行5之前);二是JPA的数据库连接池配置(行6-行17);三是Druid连接池的特殊配置(行19-行22);四是自定义配置(行24-行26)。

需要注意行54的配置,加这一行是为了解决由Hibernate懒加载引起的异常org.hibernate.LazyInitializationException: could not initialize proxy [devutility.test.database.springdatajpa.dao.mysql.entity.Customer#100000123] - no Session

但是让enable_lazy_load_no_trans=true会带来一定的性能问题,具体参考https://vladmihalcea.com/the-hibernate-enable_lazy_load_no_trans-anti-pattern/

此外,解决org.hibernate.LazyInitializationException异常还有另外一种方法,在每个Entity类型上添加@Proxy(lazy = false)注解,经测试有效。

3. Java Config

为便于管理,每个数据源一个配置类,此处只列出一个数据源:

 1 import java.util.Properties;
 2 
 3 import javax.sql.DataSource;
 4 
 5 import org.springframework.boot.context.properties.ConfigurationProperties;
 6 import org.springframework.context.annotation.Bean;
 7 import org.springframework.context.annotation.Configuration;
 8 import org.springframework.context.annotation.Primary;
 9 import org.springframework.context.annotation.PropertySource;
10 import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
11 import org.springframework.orm.jpa.JpaTransactionManager;
12 import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
13 import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
14 import org.springframework.transaction.PlatformTransactionManager;
15 
16 import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
17 
18 import devutility.internal.util.PropertiesUtils;
19 
20 @Configuration
21 @PropertySource("classpath:db.properties")
22 @EnableJpaRepositories(basePackages = "devutility.test.database.springdatajpa.dao.mssql", entityManagerFactoryRef = "entityManagerFactory1", transactionManagerRef = "transactionManager1")
23 public class DataSource1Configuration {
24     @Primary
25     @Bean
26     @ConfigurationProperties("db1.sqlserver")
27     public DataSource dataSource1() {
28         return DruidDataSourceBuilder.create().build();
29     }
30 
31     @Bean
32     @ConfigurationProperties("db1.sqlserver.jpa")
33     public Properties jpaProperties1() {
34         return new Properties();
35     }
36 
37     @Primary
38     @Bean
39     public LocalContainerEntityManagerFactoryBean entityManagerFactory1() {
40         LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
41         localContainerEntityManagerFactoryBean.setDataSource(dataSource1());
42         localContainerEntityManagerFactoryBean.setPackagesToScan(new String[] { "devutility.test.database.springdatajpa.dao.mssql.entity" });
43         localContainerEntityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
44         localContainerEntityManagerFactoryBean.setJpaPropertyMap(PropertiesUtils.toMap(jpaProperties1()));
45         return localContainerEntityManagerFactoryBean;
46     }
47 
48     @Bean
49     public PlatformTransactionManager transactionManager1() {
50         JpaTransactionManager transactionManager = new JpaTransactionManager();
51         transactionManager.setEntityManagerFactory(entityManagerFactory1().getObject());
52         return transactionManager;
53     }
54 }

4. Druid控制台页面配置

Druid的详细配置见Druid官网

如果你不想对Druid控制台的访问加以限制可以忽略此节,如果你希望通过用户名和密码访问Druid控制台,有如下两种配置方式:

(1)Java Config

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;

@Configuration
public class DruidConfiguration {
    @Bean
    public ServletRegistrationBean<StatViewServlet> druidStatViewServlet() {
        ServletRegistrationBean<StatViewServlet> servletRegistrationBean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
        servletRegistrationBean.addInitParameter("loginUsername", "admin");
        servletRegistrationBean.addInitParameter("loginPassword", "admin");
        servletRegistrationBean.addInitParameter("resetEnable", "false");
        return servletRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean<WebStatFilter> druidStatFilter() {
        FilterRegistrationBean<WebStatFilter> filterRegistrationBean = new FilterRegistrationBean<>(new WebStatFilter());
        filterRegistrationBean.setName("DruidWebStatFilter");
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return filterRegistrationBean;
    }
}

(2). 在application.properties文件中添加

#Configuration for druid
spring.datasource.druid.stat-view-servlet.enabled=true
spring.datasource.druid.stat-view-servlet.url-pattern=/druid/*
spring.datasource.druid.stat-view-servlet.login-username=admin
spring.datasource.druid.stat-view-servlet.login-password=admin

Demo代码


springboot2.0.4整合mybatis出现异常property'sqlsessionfactory'or'sqlsessiontemplate'a

在使用Springboot2.0.4整合Mybatis的时候出现异常Property‘sqlSessionFactory‘or‘sqlSessionTemplate‘arerequired,然后各种找日志百度,网上给了一种解决方法:版本太高,使用手动注入sqlSessionFactory,然后用dao的实习类继承,因为我的项目没... 查看详情

005-springboot2.0.4-jdbc升级

一、概述  Springboot2默认数据库连接池选择了HikariCP为何选择HikariCP理由一、代码量理由二、口碑理由三、速度理由四、稳定性理由五、可靠性HikariCP为什么这么快优化并精简字节码更好的并发集合类实现使用FastList替代ArrayListHi... 查看详情

Spring Boot 2.1 和 Java 11 中的 Bean 生命周期

】SpringBoot2.1和Java11中的Bean生命周期【英文标题】:BeanlifecycleinSpringBoot2.1andJava11【发布时间】:2019-05-0114:36:01【问题描述】:我的项目正在从带有Java8的SpringBoot2.0.4迁移到带有Java11的SpringBoot2.1.0。当应用程序使用SpringBoot2.0.4和Java... 查看详情

SpringBoot 2.0.4 中同一实体的多个表示

】SpringBoot2.0.4中同一实体的多个表示【英文标题】:MultiplerepresentationsofthesameentityinSpringBoot2.0.4【发布时间】:2019-01-3121:54:36【问题描述】:我有一个基本的SpringBoot2.0.4.RELEASE应用程序。使用SpringInitializer、JPA、嵌入式Tomcat、Thymele... 查看详情

Spring Boot 2.0.4 + Thymeleaf 3.0.9:无法初始化类 HTMLTemplateParser

】SpringBoot2.0.4+Thymeleaf3.0.9:无法初始化类HTMLTemplateParser【英文标题】:SpringBoot2.0.4+Thymeleaf3.0.9:CouldnotinitializeclassHTMLTemplateParser【发布时间】:2019-01-2212:38:20【问题描述】:我正在尝试使用带有Maven和Thymeleaf的SpringBoot运行一个基本... 查看详情

[springboot]springbootspringdatajpa操作mysql8

...ate基础上封装的一款框架。  开发环境    ● SpringBoot2.0.4    ● SpringDataJPA2.0.4    ● MySQL 查看详情

[springboot]springbootspringdatajpa操作mysql8

...ate基础上封装的一款框架。  开发环境    ● SpringBoot2.0.4    ● SpringDataJPA2.0.4    ● MySQL 查看详情

springboot最佳实践springdatajpa操作mysql8

...SpringDataJPA是在Hibernate基础上封装的一款框架。开发环境SpringBoot2.0.4SpringDataJPA2.0.4MySQL8.0.12JDK8IDEA2018.2Windows10##二、集成步 查看详情

springcloud使用样例

...emo项目地址:https://github.com/hackyoMa/spring-cloud-demo组件基于SpringBoot2.0.4、SpringCloudFinchley.SR1的SpringCloudDemo其中含有下列组件的样例:Eureka(服务注册与发现)Feign(服务消费者)Zuul(路由网关)Turbine(断路器聚合监控)Zipkin(服务... 查看详情

springboot入门十,添加junit单元测试

SpringBoot使用junit非常简单,我们来看一下,首先说明,这里使用的是springboot2.0.4的版本一.pom.xml文件开启springboot测试包<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test& 查看详情

在springboot中使用热部署(devtools)

...,能自动执行编译并运行。 二、工具  IntelliJIDEA、SpringBoot2.0.4三、步骤  1、创建正常SpringBoot的Maven项目  2、在需要热部署的项目中(或者在全局父Ma 查看详情

Spring Exception Handler 返回部分响应 - 也许是错误?

...【发布时间】:2019-03-2022:35:37【问题描述】:我正在使用springboot2.0.4来构建一个REST接口。我正在使用ExceptionHandler来处理错误。问题:当序列化时引发异常时,杰克逊会抛出JsonMappingE 查看详情

spring框架包含哪些内容

参考技术Aspring框架是一个轻量级的java开发框架,为应用开发提供平台。spring主要框架包括7个模块springcore,springaop,springcontext,springweb,springwebmvc,springorm,springDa 查看详情

springboot最佳实践集成jsp与生产环境部署

...发,以及生产环境的详细部署方法。二、集成JSP开发环境SpringBoot2.0.4RELEASETomcat9.0.10IDEA(IntellijIDEA简称,下文统 查看详情

springboot:浅谈文件上传和访问的坑(multipartfile)(代码片段)

本次的项目环境为SpringBoot2.0.4,JDK8.0.服务器环境为CentOS7.0,Nginx的忘了版本.前言SpringBoot使用MultiPartFile接收来自表单的file文件,然后进行服务器的上传是一个项目最基本的需求,我以前的项目都是基于SpringMVC框架搭建的,所以在使用Spr... 查看详情

请教利用fegin进行远程访问设置hystrix熔断器不生效(代码片段)

本人的环境:1.基于springboot2.0.4的springcloud(Finchley.SR1)2.分为eureka,merber,order。order通过Fegin的方式调用merber的一个方法困惑:远程调用利用注解@HystrixCommand的方式熔断器可以起作用,但是利用这种方式就不行代码展示:pom.xml<?xmlvers... 查看详情

ssm框架整合—详细整合教程(spring+springmvc+mybatis)

SSM框架整合—详细整合教程(Spring+SpringMVC+MyBatis)✨博主介绍MyBatis和Spring整合1、整合原因2、整合条件3、整合入门4、整合MyBatis现有配置SpringMVC和Spring整合1、整合理论2、整合实战💫点击直接资料领取💫✨... 查看详情

ssm框架整合—详细整合教程(spring+springmvc+mybatis)(代码片段)

SSM框架整合—详细整合教程(Spring+SpringMVC+MyBatis)✨博主介绍MyBatis和Spring整合1、整合原因2、整合条件3、整合入门4、整合MyBatis现有配置SpringMVC和Spring整合1、整合理论2、整合实战💫点击直接资料领取💫✨... 查看详情