本文主要解决基于spring data jpa读写分离。
思想:在dataSource做路由,根据事务判断使用主从数据源。
背景:spring+spring data jpa(hibernate jpa)
首先是jpa配置,时间有限在原基础上该的,既有java配置也有xml配置,见谅。
先声明EntityManager
<!-- Jpa Entity Manager 配置 --> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="showSql" value="false" /> <property name="generateDdl" value="true" /> <property name="database" value="MYSQL" /> </bean> </property> <property name="packagesToScan" value="com.lee"/> <property name="jpaProperties"> <props> <!-- 命名规则 My_NAME->MyName --> <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop> </props> </property> </bean> <!-- 动态dataSource --> <bean id="dataSource" class="com.lee.spring.core.jpa.rws.RwDataSource"> <property name="targetDataSources"> <map key-type="java.lang.String"> <!-- write --> <entry key="master" value-ref="masterDataSource"/> <!-- read --> <entry key="slave" value-ref="slaveDataSource"/> </map> </property> <property name="defaultTargetDataSource" ref="masterDataSource"/> </bean> <!-- 主(写)数据源 --> <bean id="masterDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${jdbc.master.driver}" /> <property name="jdbcUrl" value="${jdbc.master.url}" /> <property name="user" value="${jdbc.master.username}" /> <property name="password" value="${jdbc.master.password}" /> <property name="maxPoolSize" value="30" /> <property name="minPoolSize" value="10" /> <property name="initialPoolSize" value="1" /> <property name="maxIdleTime" value="0" /> <property name="acquireIncrement" value="3" /> <property name="acquireRetryAttempts" value="30" /> <property name="checkoutTimeout" value="0" /> <property name="idleConnectionTestPeriod" value="60" /> </bean> <!-- 从(读)数据源 --> <bean id="slaveDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${jdbc.slave.driver}" /> <property name="jdbcUrl" value="${jdbc.slave.url}" /> <property name="user" value="${jdbc.slave.username}" /> <property name="password" value="${jdbc.slave.password}" /> <property name="maxPoolSize" value="30" /> <property name="minPoolSize" value="10" /> <property name="initialPoolSize" value="1" /> <property name="maxIdleTime" value="0" /> <property name="acquireIncrement" value="3" /> <property name="acquireRetryAttempts" value="30" /> <property name="checkoutTimeout" value="0" /> <property name="idleConnectionTestPeriod" value="60" /> </bean>
用java声明的jpa设置
import javax.annotation.Resource; import javax.persistence.EntityManagerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.transaction.annotation.EnableTransactionManagement; import com.lee.spring.core.jpa.rws.MyJpaTransactionManager; /** * spring-jpa设置 * @author lee * */ @Configuration @PropertySource("classpath:/application.properties") @EnableTransactionManagement @EnableJpaRepositories(basePackages = {"com.lee.**.dao"}) public class SpringDaoConfig { private static final Logger logger = LoggerFactory.getLogger(SpringDaoConfig.class); @Resource(name="entityManagerFactory") private EntityManagerFactory entityManagerFactory; /** * 描述 : 负责解析资源文件 * 这个类必须有,而且必须声明为static,否则不能正常解析 * @return */ @Bean public static PropertySourcesPlaceholderConfigurer placehodlerConfigurer() { logger.info("PropertySourcesPlaceholderConfigurer"); return new PropertySourcesPlaceholderConfigurer(); } @Bean(name="entityManagerFactory") public EntityManagerFactory entityManagerFactory() { return entityManagerFactory; } @Bean(name="transactionManager") public MyJpaTransactionManager transactionManager() { MyJpaTransactionManager transactionManager = new MyJpaTransactionManager(); transactionManager.setEntityManagerFactory(entityManagerFactory); return transactionManager; } }
由上可以看出跟平常不同的有两点
- 自定义动态连接池RwDataSource
- 自定义事务管理器MyJpaTransactionManager
其中MyJpaTransactionManager主要作用在于判断事务类别。因为我是使用注解@Transactional来声明事务,所以该类做了如下调整
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.support.DefaultTransactionStatus; @SuppressWarnings("serial") public class MyJpaTransactionManager extends JpaTransactionManager{ private static final Logger logger = LoggerFactory.getLogger(MyJpaTransactionManager.class); @Override protected void doBegin(Object transaction, TransactionDefinition definition) { if(definition.isReadOnly()){ RwDataSourceHolder.localSlave(); }else{ RwDataSourceHolder.localMaster(); } logger.info("jpa-transaction:begin-----now dataSource is ["+RwDataSourceHolder.getDataSouce()+"]"); super.doBegin(transaction, definition); } @Override protected void doCommit(DefaultTransactionStatus status) { logger.info("jpa-transaction:commit-----now dataSource is ["+RwDataSourceHolder.getDataSouce()+"]"); super.doCommit(status); } }
上面涉及到definition.isReadOnly()来判断我的注解声明,依此来决定使用哪个dataSource。
public class RwDataSourceHolder { public static final String MASTER = "master"; //主(写)连接池 public static final String SLAVE = "slave"; //从(读)连接池 public static final ThreadLocal<String> holder = new ThreadLocal<String>(); public static void localMaster() { holder.set(MASTER); } public static void localSlave() { holder.set(SLAVE); } public static String getDataSouce() { return holder.get(); } }
最后是RwDataSource,这个完全基于spring提供的AbstractRoutingDataSource
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class RwDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return RwDataSourceHolder.getDataSouce(); } }
相关推荐
SpringBoot2.x 继承 AbstractRoutingDataSource 动态数据源切换实现 JPA读写分离。 使用MyCat代理MySQL8数据库,添加root账户(读写)和user账户(只读)模拟读写简单分离。
主要介绍了SpringBoot集成Spring Data JPA及读写分离的相关知识,需要的朋友可以参考下
最近项目要支持读写分离, 网上找了很多,但都是不太完整,我自己整理了下供大家参考。 我的项目使用的框架: springMvc+spring+hibernate+springJPA+maven, 数据库连接池用阿里的druid。
Spring AOP + SpringMVC +Mybatis做动态数据源,实现读写分离Spring AOP + SpringMVC +Mybatis做动态数据源,实现读写分离Spring AOP + SpringMVC +Mybatis做动态数据源,实现读写分离
1:多租户系统集成 2:集成shardingjdbc分库分表 3:集成shardingjdbc读写分离 4:集成人大金仓数据库 5:重写了JPA-saveandflush方法 6:修复了JPA更新数据为null的问题 7:解压后导入idea,创建数据库即可运行测试
mysql主从复制,读写分离 3技术要点 后端: spring-boot、spring-session、spring-security等全家桶 dubbo + zookeeper分布式rpc服务 redis缓存 mysql数据库 flowable工作流 mybatis、jdbcTemplate、spring jpa持久...
mysql主从复制,读写分离 3技术要点 后端: spring-boot、spring-session、spring-security等全家桶 dubbo + zookeeper分布式rpc服务 redis缓存 mysql数据库 flowable工作流 mybatis、jdbcTemplate、spring jpa持久...
jpa的依赖 (spring-boot-starter-data-jpa) 3.1.2.4 JavaBean对象 3.1.2.5 application.properties配置文件 3.1.2.6 配置类 3.1.2.7 测试类 3.1.3问题与解答 问题: 解答与分析: 案例实操 3.2 作用于Class类及其...
那么这种模式查询的时候性能会变的非常差,这个时候就涉及到了 CQRS ,简单的理解就是读写分离,通过事件触发,将最新状态保存到读库,查询全都走读库,理论上代码层,数据库层,都可以做到分离,当然也可以不分离,...
支持数据库读写分离,Feign增加服务直接的安全调用。v01版本是基础学习,主分支基于目前线上功能拆出来的功能模块,实现开箱即用。 ## 项目结构 ``` lua super-boot ├── client-config -- 项目配置文件信息...
SPRINGBOOT天猫整站,基于 前后端分离思想, 由于该商城高并发的特点,后端框架便使用了方便维护的 SpringM VC、SpringBoot框架,而前端框架则选择了主流的BootStrap、Vue.js,JQuery三大前端框架,页面使用...
8-20 实现读写分离 8-21 测试与并发 8-22 事件溯源模式与Axon框架总结 第9章 TCC模式和微服务架构的设计模式 本章介绍TCC模式,也对微服务系统的几种设计模式,以及这些模式下分布式事务的实现模式进行了介绍。 9-1...
简介:计划:version-1.0.0 先基于...2.0.1 抛开一切框架直接使用(NB-Durex[Nothing But Durex])version-3.0.0 支持分布式事务version-3.0.1 接入Sharding-JDBCversion-3.0.2 简化读写分离version-3.0.3 简化分表&分库
集成mybatis,druid数据库连接池(是否可以动态修改连接数),多数据源(读写分离,主从数据库同步的延迟), 分页:https://github.com/pagehelper/Mybatis-PageHelper(完成) 集成jpa(完成,集成了mybatis工具包后基本...
ef-orm A Simple OR-Mapping framework on multiple databases. ... EF-ORM是一个轻量,便捷的Java ORM框架。并且具备若干企业级的... SQL分析,性能统计,分库分表,Oracle RAC支持,读写分离支持 标签:eform
适用于任何基于JDBC的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。 支持任意实现JDBC规范的数据库,...
1. 目录 1. 2. 目录 .........................................................................................................................................................1 JVM ........................