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

Wan*_*ker 4 mysql architecture design-patterns jpa spring-data

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

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

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

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

man*_*ish 13

使用MySQL时,Java开发人员通常使用Connector/J作为JDBC驱动程序.开发人员通常使用Connector/J com.mysql.jdbc.Driver类,其URL 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.这允许应用程序连接到多个服务器之一,具体取决于在任何给定时间点哪个服务器可用.

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

@Service
@Transactional(readOnly = true)
public class SomeServiceImpl implements SomeService {
   public SomeDataType readSomething(...) { ... }

   @Transactional(readOnly = false)
   public void writeSomething(...) { ... }
}
Run Code Online (Sandbox Code Playgroud)

使用这样的代码,无论何时readSomething调用该方法,Spring事务管理代码都将获取JDBC Connection并对其进行调用setReadOnly(true),因为@Transactional(readOnly = true)默认情况下会对服务方法进行注释.这将使来自该readSomething方法的所有数据库查询转到其中一个非主MySQL主机,以循环方式进行负载平衡.同样,每当writeSomething调用时,Spring都会调用setReadOnly(false)底层JDBC Connection,强制数据库查询转到主服务器.

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