这篇文章主要介绍了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集成的实例详解的详细内容。更多信息请关注PHP中文网其他相关文章!

本文讨论了使用Maven和Gradle进行Java项目管理,构建自动化和依赖性解决方案,以比较其方法和优化策略。

本文使用Maven和Gradle之类的工具讨论了具有适当的版本控制和依赖关系管理的自定义Java库(JAR文件)的创建和使用。

本文讨论了使用咖啡因和Guava缓存在Java中实施多层缓存以提高应用程序性能。它涵盖设置,集成和绩效优势,以及配置和驱逐政策管理最佳PRA

本文讨论了使用JPA进行对象相关映射,并具有高级功能,例如缓存和懒惰加载。它涵盖了设置,实体映射和优化性能的最佳实践,同时突出潜在的陷阱。[159个字符]

Java的类上载涉及使用带有引导,扩展程序和应用程序类负载器的分层系统加载,链接和初始化类。父代授权模型确保首先加载核心类别,从而影响自定义类LOA


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

WebStorm Mac版
好用的JavaScript开发工具

SecLists
SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

Dreamweaver Mac版
视觉化网页开发工具

安全考试浏览器
Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。