`
QING____
  • 浏览: 2251591 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Spring + JPA实现数据库读写分离

    博客分类:
  • JAVA
 
阅读更多

    SQL的读写分离方案,是一种通用的设计,通常可以较好的提升数据库集群的整体负载能力,当一个mysql实例无法支撑客户端的读写负载时,我们首先会想到对数据库进行“读写分离”

    1)在数据库的架构层面,我们使用M-S架构模式,即一主多从,Master主要用于处理write、transaction等核心操作,这些操作必须发生在master上,否则将会导致数据一致性问题。对于slaves,通常用于分流read操作,对于那些对数据实时性要求不高、批量读取、SLOW SQL等操作,我们应该将它们分配到slaves中。

 

    2)能进行读写分离的前提,一个非常重要的指标,就是“集群的R:W比较高”,即较多的read、较少的write,如果读写比很低,读写分离所产生的收益,将是比较微弱的。

 

    3)从架构的视角考虑,Master与slave在整个timeline中,所需要处理的物理write操作是相同的,即在master上发生一个write操作,此操作也必将在slaves上发生(可能时间线不一致,但是最终一定会发生,这取决于binlog和mysql IO线程的处理效率)。因此,粗略来讲,slaves所面对的writes负载与master一致。这也限定我们,“读写比较低”的应用场景下,读写分离收益较低的原因。

 

    4)slaves机器的物理性能,应该与master保持一致,甚至可以更好,毕竟,大量的reads操作需要等待slaves去处理,这些load是master所不会面对的。

 

    本文展示了如何在Spring环境中使用JPA实现dataSource的读写分离(本文没有使用JTA事务),这个东西看起来简单,其实实现起来比较蹩脚,与JDBC有很大区别。

    1)使用Spring中的AbstractRoutingDataSource,辅助程序在运行时选择合适的dataSource。

    2)可以使用@Master、@Slave注释来强制dao方法调用必须使用master或者slave的数据库源。

    3)本例提供的ReadWriteDataSourceRouter可以根据当前Transaction的readOnly特性,将SQL调用按需分发给master或者slaves;可以指定多个slaves,可以简单的负载均衡。

 

1、persistence.xml

    如果我们不适用JTA事务的话,这个文件可以为空即可。

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
             xmlns="http://java.sun.com/xml/ns/persistence" 
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
             http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <!--
    <persistence-unit name="trial" transaction-type="RESOURCE_LOCAL">
    </persistence-unit>
    -->
</persistence>

 

2、ReadWriteDataSourceRouter.java

**
 * Created by liuguanqing on 16/5/10.
 * 全量读写分离
 */
public class ReadWriteDataSourceRouter extends AbstractRoutingDataSource {

    private Integer slaves;//slaves的个数

    private Random random = new Random();
    //如果基于JDK 7+,可以使用ThreadLocalRandom

    public void setSlaves(Integer slaves) {
        this.slaves = slaves;
    }

    @Override
    protected Object determineCurrentLookupKey() {
        boolean isReadOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
        if(!isReadOnly) {
            return "WRITE";
        }
        //如果是只读,可以从任意一个slave中执行
        return "READ_" + random.nextInt(slaves);
        //如果基于JDK 7+
        //ThreadLocalRandom random = ThreadLocalRandom.current();
    }
}

 

    java类中使用了一些约定的字符串,比如“WRITE”对应的为masterDataSource,所有的slaves对应的key必须为“READ_” + 数字。(参见下文配置)

 

3、spring-datasource.xml配置摘要:

<bean id="masterDataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://192.168.1.100:3306/test?useUnicode=true&amp;characterEncoding=UTF-8&amp;autoReconnect=false"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>
    <property name="maxActive" value="128"></property>
    <property name="maxIdle" value="6"></property>
    <property name="minIdle" value="2"></property>
    <property name="maxWait" value="30000"></property>
    <property name="defaultAutoCommit" value="true"></property>
</bean>

<bean id="slaveDataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://192.168.1.101:3306/test?useUnicode=true&amp;characterEncoding=UTF-8&amp;autoReconnect=false"></property>
    <property name="username" value="root"></property>
    <property name="password" value="root"></property>
    <property name="maxActive" value="128"></property>
    <property name="maxIdle" value="6"></property>
    <property name="minIdle" value="2"></property>
    <property name="maxWait" value="30000"></property>
    <property name="defaultAutoCommit" value="true"></property>
</bean>

<bean id="rwDataSource" class="com.test.demo.dataSource.TypedReadWriteDataSourceRouter">
    <property name="slaves" value="2"/><!-- 允许read操作的节点个数 -->
    <property name="targetDataSources">
        <map key-type="java.lang.String">
            <entry key="WRITE" value-ref="masterDataSource"/>
            <entry key="READ_0" value-ref="slaveDataSource" />
            <entry key="READ_1" value-ref="masterDataSource" /><!-- 允许部分read到slave上 -->
        </map>
    </property>
    <property name="defaultTargetDataSource" ref="slaveDataSource"/><!-- or master -->
</bean>

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceXmlLocation" value="classpath:persistence.xml" />
    <property name="dataSource" ref="rwDataSource" />
    <!-- model的package-->
    <property name="packagesToScan" value="com.test.demo.model"/>
    <property name="jpaVendorAdapter">
    	<!-- JPA的实现,有多种,请根据实际情况选择 -->
        <bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
            <property name="showSql" value="false"/>
            <property name="generateDdl" value="false"/>
            <property name="database" value="MYSQL"/>
            <property name="databasePlatform" value="org.eclipse.persistence.platform.database.MySQLPlatform" />
        </bean>
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="eclipselink.weaving">false</prop>
            <prop key="eclipselink.cache.shared.default">false</prop>
            <prop key="eclipselink.read-only">true</prop>
        </props>
    </property>
</bean>


<!-- 声明一个Spring提供的JPA事务管理器,传入的参数是Spring中的实体管理器工厂 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<context:annotation-config/>
<tx:annotation-driven transaction-manager="transactionManager" />

 

4、TesUser.java(model样例) 

@Entity
@Table(name="test_user",schema = "vipkid")
public class TestUser {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @Column(name = "name")
    private String name;

    @Column(name = "password")
    private String password;

    // 创建时间
    @Temporal(TemporalType.DATE)
    @Column(name = "created")
    private Date created;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

 

5、TestUserRepository.java(DAO层)

@Repository
public class TestUserRepository  {

    @PersistenceContext
    private EntityManager entityManager;


    @Transactional(readOnly = true)
    //To slave
    public TestUser getFromSlave(int id) {
        String sql = "select T from TestUser T where T.id = :id";
        TypedQuery<TestUser> query = entityManager.createQuery(sql,TestUser.class);
        query.setParameter("id",id);
        return query.getSingleResult();
    }

    @Transactional(readOnly = false)
    //To master
    public TestUser getFromMaster(int id) {
        String sql = "select T from TestUser T where T.id = :id";
        TypedQuery<TestUser> query = entityManager.createQuery(sql,TestUser.class);
        query.setParameter("id",id);
        return query.getSingleResult();
    }
}

 

分享到:
评论

相关推荐

    使用springboot + JPA / MyBatis 实现多数据源动态切换

    在现代企业级应用开发中,数据源的动态切换是一个重要的需求,特别是在分布式系统中,可能需要连接多个数据库来实现读写分离、数据分区等策略。本教程将详细讲解如何使用Spring Boot结合JPA或MyBatis框架实现多数据...

    SpringBoot集成Spring Data JPA及读写分离

    SpringBoot集成Spring Data JPA及读写分离是现代Java Web应用程序中常见的技术组合,用于高效地管理和处理数据库操作。Spring Boot简化了应用的初始化和配置,而Spring Data JPA则进一步降低了使用Java Persistence ...

    数据库读写分离(aop方式完整实现)

    最近项目要支持读写分离, 网上找了很多,但都是不太完整,我自己整理了下供大家参考。 我的项目使用的框架: springMvc+spring+hibernate+springJPA+maven, 数据库连接池用阿里的druid。

    Mysql主从集群搭建方法,以及基于spring boot注解式数据库读写分离代码示例.zip

    Spring Boot是流行的Java开发框架,提供了便捷的方式来配置和使用数据库,包括实现数据库读写分离。 1. **MySQL主从复制原理**: 主从复制的核心是binlog(二进制日志),主节点的所有更改操作都会记录在binlog中...

    springboot+shardingjdbc+hikari+jpa+KingbaseES V8R6

    1:多租户系统集成 2:集成shardingjdbc分库分表 3:集成shardingjdbc读写分离 4:集成人大金仓数据库 5:重写了JPA-saveandflush方法 6:修复了JPA更新数据为null的问题 7:解压后导入idea,创建数据库即可运行测试

    Spring MVC + JPA + MQ + redis +activemq 集成项目实例

    在Spring MVC项目中,JPA通过Hibernate等实现者与数据库交互,简化了SQL代码,提高了开发效率。开发者可以通过注解或者XML配置来定义实体类和数据表之间的映射,实现CRUD(创建、读取、更新、删除)操作。 **消息...

    SpringBoot2.x 继承 AbstractRoutingDataSource 动态数据源切换实现 JPA读写分离

    SpringBoot2.x 继承 AbstractRoutingDataSource 动态数据源切换实现 JPA读写分离。 使用MyCat代理MySQL8数据库,添加root账户(读写)和user账户(只读)模拟读写简单分离。

    Spring Boot使用spring-data-jpa配置Mysql多数据源

    在Spring Boot应用中,使用`spring-data-jpa`来配置MySQL多数据源是一项常见的需求,尤其是在构建大型分布式系统时,为了实现数据隔离、负载均衡或读写分离等目的。本教程将详细介绍如何在Spring Boot项目中配置多个...

    springboot 实现mysql读写分离

    在IT行业中,数据库读写分离是一种常见的优化策略,特别是在高并发和大数据量的场景下,以提高系统的性能和可用性。本教程将详细介绍如何利用SpringBoot框架实现MySQL的读写分离,以及涉及到的相关技术。 首先,...

    整合Spring Data JPA1

    - **多数据源支持**:可以方便地配置和管理多个数据源,实现数据隔离和读写分离。 **2. Spring Boot 整合 Spring Data JPA** - **环境搭建**:在 Maven 项目中添加相关依赖,包括 `spring-boot-starter-data-jpa`...

    Springboot2+JPA|MyBatis+Sharding-JDBC示例

    Sharding-JDBC提供了分片、读写分离、分布式事务等功能,使得在大数据量场景下,应用性能得以显著提升。在Spring Boot应用中,Sharding-JDBC作为一个数据库驱动的替代品,通过简单的配置即可实现数据分片策略,提高...

    spring3.1+hibernate4+struts2 项目例子(注解方式)

    这个项目例子旨在帮助开发者理解如何在实际开发中整合这三个框架,实现MVC模式的高效应用。 **Spring 3.1:** Spring是一个全面的企业级应用开发框架,它提供了依赖注入(DI)和面向切面编程(AOP)等核心功能。在...

    基于Springboot结合aop实现读写分离实例工程系统-源码

    这个项目为学习和实践数据库读写分离提供了一个很好的起点,开发者可以从中学习到如何在Spring Boot环境下,利用AOP进行业务逻辑的拦截和定制,从而实现高效的数据库访问策略。同时,对于想要提升系统性能和扩展性的...

    Spring Boot+Jpa多数据源配置的完整步骤

    在实际项目中,我们经常会遇到需要使用多个数据源的情况,例如在分布式数据库中读写分离、集成多种数据库等等。多数据源配置可以满足这些需求,提高系统的灵活性和扩展性。 application.yml文件配置 在Spring Boot...

    spring的自动获取数据源,实现读写分离

    在Spring框架中,数据源的自动获取和读写分离是两个关键的概念,它们对于构建高效、可扩展的数据库应用至关重要。下面将详细讲解这两个概念及其实施方法。 首先,"spring的自动获取数据源"通常指的是Spring框架中的...

    spring-boot-mybatis多数据源读写分离实例

    本实例将探讨如何利用Spring Boot和MyBatis框架实现多数据源的读写分离。以下是关于这个主题的详细讲解。 1. **Spring Boot**:Spring Boot是由Pivotal团队提供的全新框架,旨在简化Spring应用的初始搭建以及开发...

    springMVC读写分离

    在IT行业中,数据库的读写分离是一种常见的优化策略,它能有效地提高系统性能,尤其是在高并发环境下。SpringMVC作为Java Web开发中的一个强大框架,能够很好地支持这种架构设计。以下将详细介绍如何在SpringMVC项目...

    springboot 学习mybatis+mysql读写分离(一写多读)+事务.zip

    在IT行业中,数据库的读写分离是提升系统性能和可扩展性的重要技术手段,尤其是在高并发的场景下。本教程将带你深入理解如何在SpringBoot项目中结合Mybatis和MySQL实现读写分离,并且探讨事务管理。以下是相关知识点...

    在线云盘系统源码,基于SpringBoot+Vue的前后端分离项目.zip

    SpringBoot的自动配置特性使得开发者可以快速集成各种微服务组件,如数据访问层的JPA、MyBatis等,以及安全控制层的Spring Security。 Vue.js是一个流行的前端JavaScript框架,以其简单易用、高性能和组件化设计而...

    springboot+redis实现查询附近商铺功能.zip

    Spring Boot基于Spring MVC框架,实现了模型-视图-控制器架构,使得业务逻辑、数据处理和视图渲染分离。项目中可能有对应的Controller处理HTTP请求,Service层处理业务逻辑,Repository层与数据库或Redis交互。 8....

Global site tag (gtag.js) - Google Analytics