文章目录
前言
本文讨论Connector/J 的Replication模块。该模块整合Loadbalance模式而形成新的模式。看官若想了解Loadbalance模式,可参阅《Mysql Connector/J 源码分析(LoadBalance)》。
在本文,我们会观察整个模块的大概逻辑结构。然后在代码层面分析对于异常的控制,这里会有两个“区分”:1)区分构造连接过程和使用连接过程;2)区分通讯异常和数据异常。最后分析此模式的实用性。
本次分析的版本为5.1.46。若通过maven下载,可添加以下依赖:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
名词定义
- Mysql:Mysql数据库管理软件
- Mysql服务器:安装了Mysql数据库管理软件的服务器
- Source服务器:负责写数据的Mysql服务器
- Replica服务器:负责读数据的Mysql服务器
- 底层连接:普通的ConnectionImpl
- LB写代理:与Source服务器对接的Loadbalance动态代理
- LB读代理:与Replica服务器对接的Loadbalance动态代理
- 动态代理:通过动态代理的方式构造的连接
- 调用方:使用动态连接连接一方
一、Replication的使用场景
Replication的使用场景与数据库的部署模式相关,当下很流行的读写分离,将读数据请求引向一部分服务器,将写数据请求引向另一部分的服务器。由于负责写的服务器会将更新的数据同步到负责读的服务器,这样就能够减轻服务的负担并且提高了请求的影响时间。
Connector/J 的Replication模块引入了这种思路,它会建立两组连接,一组负责读操作(即:LB读代理),一组负责写为主操作(即:LB写代理)。在使用过程中,通过调用动态代理连接的setReadOnly方法,控制发送SQL命令时的走向。
二、Replication的逻辑结构
Replication模块同样利用动态代理技术,并且基于LoadBalance模式实现,他们的结构如下:
Replication动态代理有三个重要的属性:
- masterConnection,保存LB写代理
- slavesConnection,保存LB读代理
- currentConnection,指向当前在用LB代理
当调用者调用Replication动态代理的setReadOnly(true)方法时,currentConnection指向LB读代理,接下来只能进行读操作;当调用者调用Replication动态代理的setReadOnly(false)方法时,currentConnection指向LB写代理,接下来可以进行写操作(也可以读操作)。
有些调皮的看官会提问,能否调用Replication动态代理的setReadOnly(true),然后进行数据更新操作呢?
答案是不行的。当调用动态代理的setReadOnly(true)时,底层连接会发送set session transaction read only 到Mysql,对于Mysql来说,这个会话只进行数据读取操作,其他操作都将拒绝。所以如果后续在应用端再发送更新数据的操作就会收到Mysql返回的错误码,从而产生数据异常。
同理,当调用动态代理的setReadOnly(false)时,底层连接会发送set session transaction read write 到Mysql,对于Mysql来说,这个会话可进行数据读取和更新操作。所以如果后续在应用端再发送更新数据的操作不会收到Mysql返回的错误码。
三、异常处理机制
3.1 构造阶段
在我们的例子里,url以jdbc:mysql:replication作为前缀,当我们使用DriverManager#getConnection命令获取连接的时候,跟踪调用链会一直来到NonRegisteringDriver#connect方法。而该方法分析参数url后,知道这是使用replication模块,因此就会进入NonRegisteringDriver#connectReplicationConnection方法。该方法将调用ReplicationConnectionProxy#createProxyInstance方法获取连接。