Mysql使用ReplicationDriver驅動實現讀寫分離


數據庫的主從復制環境已經配好,該要解決系統如何實現讀寫分離功能了。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參數是否會每次都調用?

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM