spring jpa mysql集群_Spring + JPA实现数据库读写分离

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事务的话,这个文件可以为空即可。

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">

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配置摘要:

false

false

true

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 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 query = entityManager.createQuery(sql,TestUser.class);

query.setParameter("id",id);

return query.getSingleResult();

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值