对于生产服务器,我们希望设置数据库集群,以便将所有读取查询定向到一台服务器,将所有写入查询定向到另一台服务器。服务器。
这显然需要对DAO的构建方式进行一些更改。
如果到目前为止,有人一直在关注cook-,那么有人知道如何实现这一目标吗?使用Spring-Data / JPA的书籍风格的DAO创作,其中DAO实现既负责读写又负责?要将两种类型的调用分开,需要对体系结构进行什么样的更改?
#1 楼
使用MySQL时,Java开发人员通常使用Connector / J作为JDBC驱动程序。开发人员通常使用带有com.mysql.jdbc.Driver
之类的URL的Connector / J jdbc:mysql://host[:port]/database
类来连接到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
。这使应用程序可以连接到多台服务器之一,具体取决于在任何给定时间点上哪一台服务器可用。 URL中声明的第一个主机为ReplicationDriver
主机,所有其他主机为read-only
主机。开发人员可以在Spring应用程序中通过如下代码结构来利用此功能:@Service
@Transactional(readOnly = true)
public class SomeServiceImpl implements SomeService {
public SomeDataType readSomething(...) { ... }
@Transactional(readOnly = false)
public void writeSomething(...) { ... }
}
像这样的代码,每当调用
read-write
方法时,Spring事务管理该代码将获取JDBC read-only
并对其调用readSomething
,因为默认情况下,服务方法用Connection
注释。这将使来自setReadOnly(true)
方法的所有数据库查询都转到非主MySQL主机之一,并以循环方式进行负载平衡。同样,每当调用@Transactional(readOnly = true)
时,Spring都会在基础JDBC readSomething
上调用writeSomething
,从而迫使数据库查询转到主服务器。此策略允许应用程序将所有只读流量定向到一个。一组MySQL服务器以及所有到另一台服务器的读写流量,而无需更改应用程序的逻辑体系结构,或者开发人员不必担心不同的数据库主机和角色。
评论
我知道这是一篇较旧的文章,但是我正在将Spring(4.2.x)与休眠(5.1.x)与mysql复制驱动程序一起使用,但是即使使用@Transactional(readOnly = true),所有查询仍然还是要掌握。似乎未将基础连接设置为readOnly,是否有人遇到/解决了此问题?
–csyperski
17年5月23日在12:44
我最终将只是休眠特定API(即:SessionFactory)的代码重构为标准JPA(即:EntityManager),从而解决了我的问题。
–csyperski
17年9月29日在12:31
#2 楼
好吧,您所说的实际上是CQRS(http://martinfowler.com/bliki/CQRS.html)。建议您在尝试实施之前先阅读一些概念指南。
关于您的问题,为获得短暂的第一个胜利,我建议先将DAL的服务分为Finder类和Repository类,供更高级别的面向业务的服务使用。
查找器将适合只读访问,仅公开返回自定义结果对象(例如报表)的getBy ...()方法和查找,并且其底层实现经过定制以与只读数据库配合使用。
另一方面,存储库将适合只写/ getById()方法,并且其底层实现是针对只写数据库而设计的。
唯一的剩下的就是这些数据库之间的同步。
这可以通过技术解决方案非常简单地实现,例如:数据库复制,对只读数据库进行更改后推迟对只读数据库的更新(最终一致性)。 。
评论
您正在使用什么数据库?我正在使用MySQL 5.6
在这种情况下,ReplicationDriver对您有用吗?我以前尝试过,并且效果很好。 ReplicationDriver类与常规的MySQL Driver类类似,只是它允许您在JDBC URL中传递多个服务器主机。如果使用@Transactional(readOnly = true)注释代码中的只读方法,则ReplicationDriver将始终将JDBC URL中的第一个主机视为写主机,而将其他主机视为只读主机。
谢谢。这看起来很有希望。我们有一个多主设备设置,我们是否需要转到主从类型的设置才能工作
不,不是必需的。例如,我曾经用一个MySQL主服务器构建了一个示例应用程序,而每个应用程序服务器都运行了一个从属副本。所有这些都在同一机架中,因此复制不会经常失败。然后,我们使用了JDBC URL jdbc:mysql:replication://master.example.com,local.example.com,其中master.example.com解析为master,local.example.com解析为本地服务器。因此,尽管有许多从属服务器,但由于制作JDBC URL的方式,每个应用程序服务器仅会知道一个(自身)。