ShardingSphere入門實戰(1)-Sharding-JDBC使用


ShardingSphere是一套開源的分布式數據庫中間件解決方案組成的生態圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(計划中)這3款相互獨立的產品組成。 他們均提供標准化的數據分片、分布式事務和數據庫治理功能,可適用於如Java同構、異構語言、雲原生等各種多樣化的應用場景。具體介紹可以查看官網https://shardingsphere.apache.org/。本文主要介紹在Spring Boot工程中使用Sharding-JDBC,文中使用到的軟件版本:Java 1.8.0_191、sharding-jdbc-core 4.1.1、MySQL 5.7.26。

1、引入依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-test</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
</dependency>

<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
    <version>4.1.1</version>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.21</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.20</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13</version>
</dependency>

2、數據分片

2.1、對應配置

spring:
  shardingsphere:
    datasource:
      names: ds0,ds1 #數據源名稱,多數據源以逗號分隔
      ds0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://10.49.196.10:3306/itest
        username: admin
        password: Root_123!
      ds1:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://10.49.196.20:3306/itest
        username: admin
        password: Root_123!
    sharding:
      tables:
        t_user: #邏輯表名,在一個庫里分表:ds0.t_user_0,ds0.t_user_1
          actual-data-nodes: ds0.t_user_$->{0..1}
          table-strategy: #表分片策略
            inline: #行表達式分片策略
              sharding-column: user_id #分片的字段
              algorithm-expression: t_user_$->{user_id % 2} #分片的算法
        t_dept: #分庫,兩個庫里建系統的表:ds0.t_dept,ds1.t_dept
          actual-data-nodes: ds$->{0..1}.t_dept
          database-strategy: #數據庫分片策略
            inline: #行表達式分片策略
              sharding-column: dept_id #分片的字段
              algorithm-expression: ds$->{dept_id % 2} #分片的算法

    props:
      sql:
        show: true

2.2、對應程序

/**
 * 數據分片
 * t_user在同一個庫里分表(t_user_0,t_user_1)
 * t_dept分庫
 */
@Test
public void fragmentation() {
    Connection con = null;
    try {
        con = dataSource.getConnection();
        con.setAutoCommit(false);
        Statement st = con.createStatement();

        //插入ds0.t_user_0表
        st.executeUpdate("insert into t_user(user_id,user_name,age) values(10,'趙雲', 30)");
        //插入ds0.t_user_1表
        st.executeUpdate("insert into t_user(user_id,user_name,age) values(11,'張飛', 31)");

        //插入ds0.t_dept表
        st.executeUpdate("insert into t_dept(dept_id,dept_name) values(10,'dept10')");
        //插入ds1.t_dept表
        st.executeUpdate("insert into t_dept(dept_id,dept_name) values(11,'dept11')");

        ResultSet rs = st.executeQuery("select user_id,user_name from t_user where user_id in(10,11)");
        while (rs.next()) {
            logger.info("user_id={},user_name={}", rs.getString("user_id"), rs.getString("user_name"));
        }

        rs = st.executeQuery("select dept_id,dept_name from t_dept where dept_id in(10,11)");
        while (rs.next()) {
            logger.info("dept_id={},dept_name={}", rs.getString("dept_id"), rs.getString("dept_name"));
        }

        con.commit();
    } catch (Exception e) {
        JdbcUtil.rollback(con);
        e.printStackTrace();
    } finally {
        JdbcUtil.close(con);
    }
}

3、讀寫分離

3.1、對應配置

spring:
  shardingsphere:
    datasource:
      names: master,slave0
      master:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://10.49.196.10:3306/itest
        username: admin
        password: Root_123!
      slave0:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://10.49.196.20:3306/itest
        username: admin
        password: Root_123!
    masterslave:
      name: ms
      master-data-source-name: master
      slave-data-source-names: slave0
    props:
      sql:
        show: true

3.2、對應程序

/**
 * 讀寫分離,主庫寫,從庫讀
 * 同一線程且同一數據庫連接內,如有寫入操作,以后的讀操作均從主庫讀取,用於保證數據一致性
 */
@Test
public void readWrite() {
    Connection con = null;
    try {
        con = dataSource.getConnection();
        Statement st = con.createStatement();

        //從slave0讀數據
        ResultSet rs = st.executeQuery("select * from t_student");
        while (rs.next()) {
            System.out.println(rs.getString("id") + "|" + rs.getString("name"));
        }

        //寫入master
        st.executeUpdate("insert into t_student(id,name) values(100,'測試')");

        //從master讀數據
        rs = st.executeQuery("select * from t_student");
        while (rs.next()) {
            System.out.println(rs.getString(1) + "|" + rs.getString(2));
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JdbcUtil.close(con);
    }
}

/**
 * 讀寫分離,強制主庫路由
 */
@Test
public void hintMasterRouteOnly() {
    Connection con = null;
    try {
        con = dataSource.getConnection();
        Statement st = con.createStatement();
        HintManager hintManager = HintManager.getInstance();
        //主庫路由
        hintManager.setMasterRouteOnly();

        //從master讀數據
        ResultSet rs = st.executeQuery("select * from a_orm");
        while (rs.next()) {
            logger.info(rs.getString(1) + "|" + rs.getString(2));
        }
        hintManager.close();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JdbcUtil.close(con);
    }
}

4、完整代碼

package com.inspur.demo.shardingsphere;

import com.inspur.demo.shardingsphere.util.JdbcUtil;
import org.apache.shardingsphere.api.hint.HintManager;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

/**
 * ShardingJdbc使用樣例
 */
@RunWith(SpringRunner.class)
@SpringBootTest
public class ShardingJdbcCase {
    private static Logger logger = LoggerFactory.getLogger(ShardingJdbcCase.class);

    @Resource
    private DataSource dataSource;

    /**
     * 數據分片
     * t_user在同一個庫里分表(t_user_0,t_user_1)
     * t_dept分庫
     */
    @Test
    public void fragmentation() {
        Connection con = null;
        try {
            con = dataSource.getConnection();
            con.setAutoCommit(false);
            Statement st = con.createStatement();

            //插入ds0.t_user_0表
            st.executeUpdate("insert into t_user(user_id,user_name,age) values(10,'趙雲', 30)");
            //插入ds0.t_user_1表
            st.executeUpdate("insert into t_user(user_id,user_name,age) values(11,'張飛', 31)");

            //插入ds0.t_dept表
            st.executeUpdate("insert into t_dept(dept_id,dept_name) values(10,'dept10')");
            //插入ds1.t_dept表
            st.executeUpdate("insert into t_dept(dept_id,dept_name) values(11,'dept11')");

            ResultSet rs = st.executeQuery("select user_id,user_name from t_user where user_id in(10,11)");
            while (rs.next()) {
                logger.info("user_id={},user_name={}", rs.getString("user_id"), rs.getString("user_name"));
            }

            rs = st.executeQuery("select dept_id,dept_name from t_dept where dept_id in(10,11)");
            while (rs.next()) {
                logger.info("dept_id={},dept_name={}", rs.getString("dept_id"), rs.getString("dept_name"));
            }

            con.commit();
        } catch (Exception e) {
            JdbcUtil.rollback(con);
            e.printStackTrace();
        } finally {
            JdbcUtil.close(con);
        }
    }


    /**
     * 讀寫分離,主庫寫,從庫讀
     * 同一線程且同一數據庫連接內,如有寫入操作,以后的讀操作均從主庫讀取,用於保證數據一致性
     */
    @Test
    public void readWrite() {
        Connection con = null;
        try {
            con = dataSource.getConnection();
            Statement st = con.createStatement();

            //從slave0讀數據
            ResultSet rs = st.executeQuery("select * from t_student");
            while (rs.next()) {
                System.out.println(rs.getString("id") + "|" + rs.getString("name"));
            }

            //寫入master
            st.executeUpdate("insert into t_student(id,name) values(100,'測試')");

            //從master讀數據
            rs = st.executeQuery("select * from t_student");
            while (rs.next()) {
                System.out.println(rs.getString(1) + "|" + rs.getString(2));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtil.close(con);
        }
    }

    /**
     * 讀寫分離,強制主庫路由
     */
    @Test
    public void hintMasterRouteOnly() {
        Connection con = null;
        try {
            con = dataSource.getConnection();
            Statement st = con.createStatement();
            HintManager hintManager = HintManager.getInstance();
            //主庫路由
            hintManager.setMasterRouteOnly();

            //從master讀數據
            ResultSet rs = st.executeQuery("select * from a_orm");
            while (rs.next()) {
                logger.info(rs.getString(1) + "|" + rs.getString(2));
            }
            hintManager.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtil.close(con);
        }
    }

}

 


免責聲明!

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



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