阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

MySQL使用ReplicationDriver驱动实现读写分离

165次阅读
没有评论

共计 3090 个字符,预计需要花费 8 分钟才能阅读完成。

数据库的主从复制环境已经配好,该要解决系统如何实现读写分离功能了。MySQL 的 jdbc 驱动提供了一种实现 ReplicationDriver。

1 数据库地址的两种写法

参考:https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-url-format.html

因为后续配置可能会用到,先介绍一下 mysql url 中主机地址的两种写法。

最简单的写法就是 host:port,如 192.168.5.128:3306,如果端口是缺省的 3306,也可以不写,直接使用 192.168.5.128。

更复杂的写法是指定属性,格式为 address=(host=host_or_ip)(port=port)(key1=value1)(key2=value2)…(keyN=valueN),如 address=(host=192.168.5.128)(port=3306)(type=master)。

2 数据池配置

参考:https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-master-slave-replication-connection.html

driverClassName: com.mysql.jdbc.ReplicationDriver

url 字符串格式:

jdbc:mysql:replication://[master host][:port],[slave host 1][:port][,[slave host 2][:port]]…[/[database]][?propertyName1=propertyValue1[&propertyName2=propertyValue2]…]

数据库地址的写法有两种,上面是第一种简单的写法,ReplicationDriver 默认将第一个数据库服务器作为 Master 库,后续其他数据库服务器作为从数据库。

如果数据库主从设置了多台数据库作为 Master,则 url 格式为:

jdbc:mysql:replication://address=(type=master)(host=master1host),address=(type=master)(host=master2host),address=(type=slave)(host=slave1host)/database[?propertyName1=propertyValue1[&propertyName2=propertyValue2]…]

3 ReplicationDriver 的调用方法

Mysql 驱动使用究竟使用 master 还是 slave 数据库,取决于 Connection.getReadOnly() 的值。如果值为 false,则将命令发送到 master 数据库,如果值为 true,则将命令发送到 slave 数据库。当有多台 slave 数据库时,使用轮询调度(round-robin)算法选择某一台 slave 数据库。

所以,为了让 mysql 驱动能够准确的将命令发送到 master 或 slave,代码需要在获取到数据连接后,执行命令 Connection.setReadOnly(true) 或 Connection.setReadOnly(false)。

以下是 mysql 官方提供的示例代码

import Java.sql.Connection;

import java.sql.ResultSet;

import java.util.Properties;

import com.mysql.jdbc.ReplicationDriver;

public class ReplicationDriverDemo {

  public static void main(String[] args) throws Exception {

    ReplicationDriver driver = new ReplicationDriver();

    Properties props = new Properties();

    // 从库上允许自动重连

    props.put(“autoReconnect”, “true”);

    // 多台从库使用负载均衡

    props.put(“roundRobinLoadBalance”, “true”);

    props.put(“user”, “foo”);

    props.put(“password”, “password”);

    Connection conn = driver.connect(“jdbc:mysql:replication://master,slave1,slave2 /test”, props);

    // 在主库上读写,设置 read-only 为 “false”

    conn.setReadOnly(false);

    conn.setAutoCommit(false);

    conn.createStatement().executeUpdate(“UPDATE some_table ….”);

    conn.commit();

    // 现在在从库上执行查询,驱动会自动选择一台从库执行查询

    conn.setReadOnly(true);

    ResultSet rs = conn.createStatement().executeQuery(“SELECT a,b FROM alt_table”);

    …….

  }

}
 

 

4 Spring TX 实现读写分离

项目使用 Spring Transaction 管理事务,注解 Transactional 已经帮我们做了封装,注解属性 readOnly,缺省为 false。

/**

 * {@code true} if the transaction is read-only.

 * Defaults to {@code false}.

 * <p>This just serves as a hint for the actual transaction subsystem;

 * it will <i>not necessarily</i> cause failure of write access attempts.

 * A transaction manager which cannot interpret the read-only hint will

 * <i>not</i> throw an exception when asked for a read-only transaction.

 * @see org.springframework.transaction.interceptor.TransactionAttribute#isReadOnly()

 */

boolean readOnly() default false;
 

简单用法

@Transactional(readOnly = true)

public List<Enterprise> queryList(EnterpriseCriteria criteria) {

      return enterpriseDao.queryList(criteria);

}
 

在现有项目上拉了一个分支,使用 VMWare 上搭建的 MariaDB 主从库进行测试,确实能实现读写分离。

5 还需要了解的扩展知识

有空时应该进一步读一下代码,看看以下一些内容:
1.Transactional 的注解,是怎样逐渐调用到 Connection.setReadOnly() 的?
2. 多个 Transactional 注解的函数调用时,readOnly 参数是否会每次都调用?

 

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-22发表,共计3090字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中