在Spring / J2EE Apps中隔离只读和读写

时间:2015-06-19 12:48:41

标签: mysql jpa design-patterns architecture spring-data

我们在项目中使用Spring,Spring-Data和JPA。

对于生产服务器,我们希望设置数据库集群,以便将所有读取查询定向到一个服务器,并将所有写入查询定向到另一个服务器。

这显然需要对DAO的构建方式进行一些更改。

有人知道如何实现这一点,如果到目前为止,使用Spring-Data / JPA遵循烹饪书风格的DAO创作,其中DAO实现负责读取和写入?需要对架构进行哪些更改才能隔离这两种类型的呼叫?

2 个答案:

答案 0 :(得分:13)

使用MySQL时,Java开发人员通常使用Connector/J作为JDBC驱动程序。开发人员通常使用Connector / J com.mysql.jdbc.Driver类,使用诸如jdbc:mysql://host[:port]/database之类的URL连接到MySQL数据库。

Connector / J提供了另一个名为ReplicationDriver的驱动程序,它允许应用程序在多个MySQL主机之间进行负载平衡。使用ReplicationDriver时,JDBC URL将更改为jdbc:mysql:replication://master-host[:master-port][,slave-1-host[:slave-1-port]][,slave-2-host[:slave-2-port]]/database。这允许应用程序连接到多个服务器之一,具体取决于在任何给定时间点可用的服务器。

使用ReplicationDriver时,如果JDBC连接设置为read-only,则驱动程序会将URL中声明的第一个主机视为read-write主机,将所有其他主机视为{{1}主机。开发人员可以通过按如下方式构建代码来在Spring应用程序中利用这一点:

read-only

使用这样的代码,每当调用方法@Service @Transactional(readOnly = true) public class SomeServiceImpl implements SomeService { public SomeDataType readSomething(...) { ... } @Transactional(readOnly = false) public void writeSomething(...) { ... } } 时,Spring事务管理代码将获取JDBC readSomething并在其上调用Connection,因为服务方法使用{注释{1}}默认情况下。这将使来自setReadOnly(true)方法的所有数据库查询转到其中一个非主MySQL主机,以循环方式进行负载平衡。类似地,每当调用@Transactional(readOnly = true)时,Spring将在底层JDBC readSomething上调用writeSomething,强制数据库查询转到主服务器。

此策略允许应用程序将所有只读流量定向到一组MySQL服务器,并将所有读写流量定向到不同的服务器,而无需更改应用程序的逻辑体系结构或开发人员不必担心不同数据库主机和角色。

答案 1 :(得分:2)

嗯,你所说的实际上叫做CQRS(http://martinfowler.com/bliki/CQRS.html)。 在尝试实施之前,我建议阅读一些概念指南。

关于你的问题,首先,我建议将DAL的服务划分为Finder类和Repository类,这些类将由更高级的业务导向服务使用。

Finders将适合只读访问,只暴露getBy ...()方法和返回自定义结果对象(如报表)的查找,并且它们的底层实现是针对只读数据库而定制的。

另一方面,

存储库将适合只写/ getById()方法,并且它们的底层实现是针对只写数据库而定制的。

唯一剩下的就是这些数据库之间的同步。 这可以通过以下技术解决方案非常简单地实现:数据库复制,在对只写数据库进行更改后,对只读数据库的更新推迟(最终一致性)。