本文主要解决基于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及读写分离是现代Java Web应用程序中常见的技术组合,用于高效地管理和处理数据库操作。Spring Boot简化了应用的初始化和配置,而Spring Data JPA则进一步降低了使用Java Persistence ...
- **多数据源支持**:可以方便地配置和管理多个数据源,实现数据隔离和读写分离。 **2. Spring Boot 整合 Spring Data JPA** - **环境搭建**:在 Maven 项目中添加相关依赖,包括 `spring-boot-starter-data-jpa`...
在SpringBoot中实现MySQL的读写分离,我们需要依赖于Spring Data JPA或MyBatis等持久层框架,并结合配置中心(如Apache ZooKeeper或Consul)来动态管理读写数据库的地址。以下是具体步骤: 1. **设置主从复制**:在...
在Spring Boot应用中,使用`spring-data-jpa`来配置MySQL多数据源是一项常见的需求,尤其是在构建大型分布式系统时,为了实现数据隔离、负载均衡或读写分离等目的。本教程将详细介绍如何在Spring Boot项目中配置多个...
本实例将探讨如何利用Spring Boot和MyBatis框架实现多数据源的读写分离。以下是关于这个主题的详细讲解。 1. **Spring Boot**:Spring Boot是由Pivotal团队提供的全新框架,旨在简化Spring应用的初始搭建以及开发...
- 使用如MyBatis或JPA等持久层框架时,需要确保在执行SQL时,根据读写分离规则选择合适的数据源。例如,在MyBatis中,可以通过`@Transactional`注解和自定义拦截器实现。 6. **监控与故障转移** - 实现监控机制,...
最近项目要支持读写分离, 网上找了很多,但都是不太完整,我自己整理了下供大家参考。 我的项目使用的框架: springMvc+spring+hibernate+springJPA+maven, 数据库连接池用阿里的druid。
在Spring框架中,数据源的自动获取和读写分离是两个关键的概念,它们对于构建高效、可扩展的数据库应用至关重要。下面将详细讲解这两个概念及其实施方法。 首先,"spring的自动获取数据源"通常指的是Spring框架中的...
使用Spring Boot的`JdbcTemplate`或者`JPA`(Java Persistence API)进行数据库操作时,可以透明地处理读写分离。只需配置好数据源,框架会自动根据规则选择合适的数据源。 6. **监控和故障转移**: 为了保证高...
这个项目为学习和实践数据库读写分离提供了一个很好的起点,开发者可以从中学习到如何在Spring Boot环境下,利用AOP进行业务逻辑的拦截和定制,从而实现高效的数据库访问策略。同时,对于想要提升系统性能和扩展性的...
Spring AOP + SpringMVC +Mybatis做动态数据源,实现读写分离Spring AOP + SpringMVC +Mybatis做动态数据源,实现读写分离Spring AOP + SpringMVC +Mybatis做动态数据源,实现读写分离
在现代企业级应用开发中,数据管理是至关重要的部分,特别是在高并发、大数据量的场景下,为了提高系统的性能和稳定性,通常会采用读写分离和多数据源的策略。本篇文章将详细讲解如何在SpringBoot项目中结合...
总结起来,动态数据源和读写分离是通过自定义注解和Spring AOP来实现的,这种方法提高了代码的可维护性和灵活性,同时降低了数据库的压力。结合Spring Data,我们可以构建出高效、可扩展的数据库访问层,满足大规模...
在本项目实例中,我们探讨的是一个基于Spring MVC、JPA、消息队列MQ以及缓存技术redis和ActiveMQ的集成应用。这个实例涵盖了多种关键的技术栈,旨在提供一个全面的解决方案,帮助开发者构建高效、可扩展的后端系统。...
在IT行业中,数据库的读写分离是提升系统性能和可扩展性的重要技术手段,尤其是在高并发的场景下。本教程将带你深入理解如何在SpringBoot项目中结合Mybatis和MySQL实现读写分离,并且探讨事务管理。以下是相关知识点...
1:多租户系统集成 2:集成shardingjdbc分库分表 3:集成shardingjdbc读写分离 4:集成人大金仓数据库 5:重写了JPA-saveandflush方法 6:修复了JPA更新数据为null的问题 7:解压后导入idea,创建数据库即可运行测试
在IT行业中,数据库管理是关键任务之一,尤其是在大型系统中,如何有效地进行读写分离和分库分表显得尤为重要。本教程将通过介绍如何使用Sharding-JDBC在SpringBoot框架下实现这一目标,来帮助你优化数据库性能和...
标题中的“Use the spring to separate read and write”指的是在Java开发中,利用Spring框架来实现数据库的读写分离。在大型应用中,为了提高数据库的性能和可用性,通常会采用主从复制的方式,将读操作和写操作...
在现代企业级应用开发中,数据源的动态切换是一个重要的需求,特别是在分布式系统中,可能需要连接多个数据库来实现读写分离、数据分区等策略。本教程将详细讲解如何使用Spring Boot结合JPA或MyBatis框架实现多数据...