这篇文章主要介绍了springboot集成spring data jpa及读写分离的相关知识,需要的朋友可以参考下
相关代码: github oscchina
jpa是什么
jpa(java persistence api)是sun官方提出的java持久化规范,它为java开发人员提供了一种对象/关联映射工具 来管理java应用中的关系数据.它包括以下几方面的内容:
1.orm映射 支持xml和注解方式建立实体与表之间的映射.
2.java持久化api 定义了一些常用的crud接口,我们只需直接调用,而不需要考虑底层jdbc和sql的细节.
3.jpql查询语言 这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序的sql语句紧密耦合.
在工作中,我们都会用到orm技术,比如hibernate,jooq等,根据需求的不同,我们会采用不同的orm框架,当我们需要 更换orm框架来满足我们的需求时,由于不同orm框架的实现,使用方式的区别以及各自为营,我们往往需要对代码进行重构.jpa的 出现就是为了解决这个问题,jpa充分吸收了现有一些orm框架的优点,具有易于使用,伸缩性强等优点,为orm技术提供了一套标准的 接口用来整合不同的orm框架.
hibernate对jpa的实现
jpa本身并不做具体的实现,而只是定义了一些接口规范,让其它orm来具体的实现这些接口,就目前来说,对jpa规范实现最好的就是 hibernate了.这里提一下mybatis,mybatis并没有实现jpa规范,它本身也不能算做一个真正的orm框架.
spring data jpa是什么
spring data jpa只是spring data框架的一个模块,可以极大的简化jpa的使用,spring data jpa强大的地方还在于能够简化我们 对持久层业务逻辑的开发,通过规范持久层方法的名称,通过名称来判断需要实现什么业务逻辑,我们机会可以在不写一句sql,不做任何dao层 逻辑的情况下完成我们绝大部分的开发,当然,对于一些复杂的,性能要求高的查询,spring data jpa一样支持我们使用原生的sql.
在这里我们不过多的去介绍jpa以及spring data jpa,主要还是与springboot集成的一些细节以及示例.
引入依赖
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-data-jpa</artifactid>
</dependency>
我们引入这个依赖后,发现也引入了hibernate的包,这是现在一种默认的做法,hibernate已经被作为jpa规范的最好实现了,这里就不介绍druid数据源的 配置了,大家可以看另外一篇xxxx.
配置我们的数据源以及jpa(hibernate)
#配置模板
#https://docs.spring.io/spring-boot/docs/1.4.0.release/reference/html/common-application-properties.html
#数据源
spring.datasource.druid.write.url=jdbc:mysql://localhost:3306/jpa
spring.datasource.druid.write.username=root
spring.datasource.druid.write.password=1
spring.datasource.druid.write.driver-class-name=com.mysql.jdbc.driver
spring.datasource.druid.read.url=jdbc:mysql://localhost:3306/jpa
spring.datasource.druid.read.username=root
spring.datasource.druid.read.password=1
spring.datasource.druid.read.driver-class-name=com.mysql.jdbc.driver
#jpa (jpabaseconfiguration, hibernatejpaautoconfiguration)
spring.jpa.database-platform=org.hibernate.dialect.mysql5dialect
spring.jpa.database=mysql
spring.jpa.generate-ddl=true
#就是hibernate.hbm2ddl.auto,具体说明可以看readme
spring.jpa.hibernate.ddl-auto=update
#通过方法名解析sql的策略,具体说明可以看readme,这里就不配置了
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.defaultcomponentsafenamingstrategy
spring.jpa.show-sql=true
#spring.jpa.properties.*
#spring.jpa.properties.hibernate.hbm2ddl.auto=update
#spring.jpa.properties.hibernate.show_sql=true
#spring.jpa.properties.hibernate.use-new-id-generator-mappings=true
druid数据源注入
@configuration
public class druiddatasourceconfig {
/**
* datasource 配置
* @return
*/
@configurationproperties(prefix = "spring.datasource.druid.read")
@bean(name = "readdruiddatasource")
public datasource readdruiddatasource() {
return new druiddatasource();
}
/**
* datasource 配置
* @return
*/
@configurationproperties(prefix = "spring.datasource.druid.write")
@bean(name = "writedruiddatasource")
@primary
public datasource writedruiddatasource() {
return new druiddatasource();
}
}
entitymanagerfactory实例注入
entitymanagerfactory类似于hibernate的sessionfactory,mybatis的sqlsessionfactory 总之,在执行操作之前,我们总要获取一个entitymanager,这就类似于hibernate的session, mybatis的sqlsession. 注入entitymanagerfactory有两种方式,一种是直接注入entitymanagerfactory,另一种是通过 localcontainerentitymanagerfactorybean来间接注入.虽说这两种方法都是基于 localcontainerentitymanagerfactorybean的,但是在配置上还是有一些区别.
1.直接注入entitymanagerfactory
配置:通过spring.jpa.properties.*来配置hibernate的属性
spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.use-new-id-generator-mappings=true
@configuration
@enablejparepositories(value = "com.lc.springboot.jpa.repository",
entitymanagerfactoryref = "writeentitymanagerfactory",
transactionmanagerref="writetransactionmanager")
public class writedatasourceconfig {
@autowired
jpaproperties jpaproperties;
@autowired
@qualifier("writedruiddatasource")
private datasource writedruiddatasource;
/**
* entitymanagerfactory类似于hibernate的sessionfactory,mybatis的sqlsessionfactory
* 总之,在执行操作之前,我们总要获取一个entitymanager,这就类似于hibernate的session,
* mybatis的sqlsession.
* @return
*/
@bean(name = "writeentitymanagerfactory")
@primary
public entitymanagerfactory writeentitymanagerfactory() {
hibernatejpavendoradapter vendoradapter = new hibernatejpavendoradapter();
localcontainerentitymanagerfactorybean factory = new localcontainerentitymanagerfactorybean();
factory.setjpavendoradapter(vendoradapter);
factory.setpackagestoscan("com.lc.springboot.jpa.entity");
factory.setdatasource(writedruiddatasource);//数据源
factory.setjpapropertymap(jpaproperties.getproperties());
factory.afterpropertiesset();//在完成了其它所有相关的配置加载以及属性设置后,才初始化
return factory.getobject();
}
/**
* 配置事物管理器
* @return
*/
@bean(name = "writetransactionmanager")
@primary
public platformtransactionmanager writetransactionmanager() {
jpatransactionmanager jpatransactionmanager = new jpatransactionmanager();
jpatransactionmanager.setentitymanagerfactory(this.writeentitymanagerfactory());
return jpatransactionmanager;
}
}
2.先注入localcontainerentitymanagerfactorybean,再获取entitymanagerfactory
配置:
spring.jpa.database-platform=org.hibernate.dialect.mysql5dialect
spring.jpa.database=mysql
spring.jpa.generate-ddl=true
#就是hibernate.hbm2ddl.auto,具体说明可以看readme
spring.jpa.hibernate.ddl-auto=update
#通过方法名解析sql的策略,具体说明可以看readme,这里就不配置了
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.defaultcomponentsafenamingstrategy
spring.jpa.show-sql=true
@configuration
@enablejparepositories(value = "com.lc.springboot.jpa.repository",
entitymanagerfactoryref = "writeentitymanagerfactory",
transactionmanagerref = "writetransactionmanager")
public class writedatasourceconfig1 {
@autowired
jpaproperties jpaproperties;
@autowired
@qualifier("writedruiddatasource")
private datasource writedruiddatasource;
/**
* 我们通过localcontainerentitymanagerfactorybean来获取entitymanagerfactory实例
* @return
*/
@bean(name = "writeentitymanagerfactorybean")
@primary
public localcontainerentitymanagerfactorybean writeentitymanagerfactorybean(entitymanagerfactorybuilder builder) {
return builder
.datasource(writedruiddatasource)
.properties(jpaproperties.getproperties())
.packages("com.lc.springboot.jpa.entity") //设置实体类所在位置
.persistenceunit("writepersistenceunit")
.build();
//.getobject();//不要在这里直接获取entitymanagerfactory
}
/**
* entitymanagerfactory类似于hibernate的sessionfactory,mybatis的sqlsessionfactory
* 总之,在执行操作之前,我们总要获取一个entitymanager,这就类似于hibernate的session,
* mybatis的sqlsession.
* @param builder
* @return
*/
@bean(name = "writeentitymanagerfactory")
@primary
public entitymanagerfactory writeentitymanagerfactory(entitymanagerfactorybuilder builder) {
return this.writeentitymanagerfactorybean(builder).getobject();
}
/**
* 配置事物管理器
* @return
*/
@bean(name = "writetransactionmanager")
@primary
public platformtransactionmanager writetransactionmanager(entitymanagerfactorybuilder builder) {
return new jpatransactionmanager(writeentitymanagerfactory(builder));
}
}
对于这个配置
@bean(name = "writeentitymanagerfactorybean")
@primary
public localcontainerentitymanagerfactorybean writeentitymanagerfactorybean(entitymanagerfactorybuilder builder) {
return builder
.datasource(writedruiddatasource)
.properties(jpaproperties.getproperties())
.packages("com.lc.springboot.jpa.entity") //设置实体类所在位置
.persistenceunit("writepersistenceunit")
.build();
//.getobject();//不要在这里直接获取entitymanagerfactory
}
getobject()方法可以获取到entitymanagerfactory的实例,看似跟第一种没有什么区别,但是我们不能直接用 getobject(),不然会获取不到,报空指针异常.
读写分离配置
自定义注入abstractroutingdatasource
@configuration
public class datasourceconfig {
private final static string write_datasource_key = "writedruiddatasource";
private final static string read_datasource_key = "readdruiddatasource";
/**
* 注入abstractroutingdatasource
* @param readdruiddatasource
* @param writedruiddatasource
* @return
* @throws exception
*/
@bean
public abstractroutingdatasource routingdatasource(
@qualifier(read_datasource_key) datasource readdruiddatasource,
@qualifier(write_datasource_key) datasource writedruiddatasource
) throws exception {
dynamicdatasource datasource = new dynamicdatasource();
map<object, object> targetdatasources = new hashmap();
targetdatasources.put(write_datasource_key, writedruiddatasource);
targetdatasources.put(read_datasource_key, readdruiddatasource);
datasource.settargetdatasources(targetdatasources);
datasource.setdefaulttargetdatasource(writedruiddatasource);
return datasource;
}
}
自定义注解
@target({elementtype.method, elementtype.type})
@retention(retentionpolicy.runtime)
@documented
public @interface targetdatasource {
string datasource() default "";//数据源
}
使用threadlocal使数据源与线程绑定
public class dynamicdatasourceholder {
//使用threadlocal把数据源与当前线程绑定
private static final threadlocal<string> datasources = new threadlocal<string>();
public static void setdatasource(string datasourcename) {
datasources.set(datasourcename);
}
public static string getdatasource() {
return (string) datasources.get();
}
public static void cleardatasource() {
datasources.remove();
}
}
public class dynamicdatasource extends abstractroutingdatasource {
@override
protected object determinecurrentlookupkey() {
//可以做一个简单的负载均衡策略
string lookupkey = dynamicdatasourceholder.getdatasource();
system.out.println("------------lookupkey---------"+lookupkey);
return lookupkey;
}
}
定义切面
@aspect
@component
public class dynamicdatasourceaspect {
@around("execution(public * com.lc.springboot.jpa.service..*.*(..))")
public object around(proceedingjoinpoint pjp) throws throwable {
methodsignature methodsignature = (methodsignature) pjp.getsignature();
method targetmethod = methodsignature.getmethod();
if (targetmethod.isannotationpresent(targetdatasource.class)) {
string targetdatasource = targetmethod.getannotation(targetdatasource.class).datasource();
system.out.println("----------数据源是:" + targetdatasource + "------");
dynamicdatasourceholder.setdatasource(targetdatasource);
}
object result = pjp.proceed();//执行方法
dynamicdatasourceholder.cleardatasource();
return result;
}
}
以上就是springboot实现spring data jpa集成的实例详解的详细内容。