天天看點

Sharding-JDBC(二)- Sharding-JDBC介紹一、Sharding-JDBC介紹二、Sharding-JDBC快速入門

文章目錄

  • 一、Sharding-JDBC介紹
    • 1. Sharding-JDBC介紹
    • 2. Sharding-JDBC與JDBC性能對比
  • 二、Sharding-JDBC快速入門
    • 1. 需求說明
    • 2. 環境搭建
      • 2.1 環境說明
      • 2.2 建立資料庫
      • 2.3 引入maven依賴
    • 3. 編寫程式
      • 3.1 分片規則配置
      • 3.2.資料操作
      • 3.3.測試
    • 4. 流程分析
    • 5. 其他內建方式
      • 5.1 Spring Boot properties配置
      • 5.2 Spring Boot Yaml 配置
      • 5.3 Java 配置
      • 5.4 Spring命名空間配置

一、Sharding-JDBC介紹

1. Sharding-JDBC介紹

Sharding-JDBC是當當網研發的開源分布式資料庫中間件,從 3.0 開始Sharding-JDBC被包含在 Sharding-Sphere 中,之後該項目進入Apache孵化器,4.0版本之後的版本為Apache版本。
ShardingSphere是一套開源的分布式資料庫中間件解決方案組成的生态圈,它由Sharding-JDBC、Sharding- Proxy和Sharding-Sidecar(計劃中)這3款互相獨立的産品組成。 他們均提供标準化的資料分片、分布式事務和資料庫治理功能,可适用于如Java同構、異構語言、容器、雲原生等各種多樣化的應用場景。

官方位址:https://shardingsphere.apache.org/document/current/cn/overview/

目前隻需關注Sharding-JDBC,它定位為輕量級Java架構,在Java的JDBC層提供的額外服務。 它使用用戶端直連資料庫,以jar包形式提供服務,無需額外部署和依賴,可了解為增強版的JDBC驅動,完全相容JDBC和各種ORM架構。

Sharding-JDBC的核心功能為資料分片和讀寫分離,通過Sharding-JDBC,應用可以透明的使用jdbc通路已經分庫分表、讀寫分離的多個資料源,而不用關心資料源的數量以及資料如何分布。

  • 适用于任何基于Java的ORM架構,如: Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
  • 基于任何第三方的資料庫連接配接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
  • 支援任意實作JDBC規範的資料庫。目前支援MySQL,Oracle,SQLServer和PostgreSQL。
Sharding-JDBC(二)- Sharding-JDBC介紹一、Sharding-JDBC介紹二、Sharding-JDBC快速入門
上圖展示了Sharding-Jdbc的工作方式,使用Sharding-Jdbc前需要人工對資料庫進行分庫分表,在應用程式中加入Sharding-Jdbc的Jar包,應用程式通過Sharding-Jdbc操作分庫分表後的資料庫和資料表,由于Sharding-Jdbc是對Jdbc驅動的增強,使用Sharding-Jdbc就像使用Jdbc驅動一樣,在應用程式中是無需指定具體要操作的分庫和分表的。

2. Sharding-JDBC與JDBC性能對比

①性能損耗測試:伺服器資源充足、并發數相同,比較JDBC和Sharding-JDBC性能損耗,Sharding-JDBC相對JDBC損耗不超過7%。

Sharding-JDBC(二)- Sharding-JDBC介紹一、Sharding-JDBC介紹二、Sharding-JDBC快速入門

②性能對比測試:伺服器資源使用到極限,相同的場景JDBC與Sharding-JDBC的吞吐量相當。

③性能對比測試:伺服器資源使用到極限,Sharding-JDBC采用分庫分表後,Sharding-JDBC吞吐量較JDBC不分表有接近2倍的提升。

Sharding-JDBC(二)- Sharding-JDBC介紹一、Sharding-JDBC介紹二、Sharding-JDBC快速入門

二、Sharding-JDBC快速入門

1. 需求說明

本章節使用Sharding-JDBC完成對訂單表的水準分表,通過快速入門程式的開發,快速體驗Sharding-JDBC的使用方法。

人工建立兩張表,t_order_1和t_order_2,這兩張表是訂單表拆分後的表,通過Sharding-Jdbc向訂單表插入資料,按照一定的分片規則,主鍵為偶數的進入t_order_1,另一部分資料進入t_order_2,通過Sharding-Jdbc查詢資料,根據SQL語句的内容從t_order_1或t_order_2查詢資料。

2. 環境搭建

2.1 環境說明

  • 作業系統:Win10
  • 資料庫:MySQL-5.7.25
  • JDK:64位 jdk1.8.0_201
  • 應用架構:spring-boot-2.1.3.RELEASE,Mybatis3.5.0
  • Sharding-JDBC:sharding-jdbc-spring-boot-starter-4.0.0-RC1

2.2 建立資料庫

建立訂單庫order_db

CREATE DATABASE

order_db

CHARACTER SET ‘utf8’ COLLATE ‘utf8_general_ci’;

在order_db中建立t_order_1、t_order_2表

DROP TABLE IF EXISTS

t_order_1

;

CREATE TABLE

t_order_1

(

order_id

bigint(20) NOT NULL COMMENT ‘訂單id’,

price

decimal(10, 2) NOT NULL COMMENT ‘訂單價格’,

user_id

bigint(20) NOT NULL COMMENT ‘下單使用者id’,

status

varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ‘訂單狀态’,

PRIMARY KEY (

order_id

) USING BTREE

) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

DROP TABLE IF EXISTS

t_order_2

;

CREATE TABLE

t_order_2

(

order_id

bigint(20) NOT NULL COMMENT ‘訂單id’,

price

decimal(10, 2) NOT NULL COMMENT ‘訂單價格’,

user_id

bigint(20) NOT NULL COMMENT ‘下單使用者id’,

status

varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT ‘訂單狀态’,

PRIMARY KEY (

order_id

) USING BTREE

) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

2.3 引入maven依賴

引入 sharding-jdbc和SpringBoot整合的Jar包:

<dependency> 
	<groupId>org.apache.shardingsphere</groupId> 
	<artifactId>sharding‐jdbc‐spring‐boot‐starter</artifactId> 
	<version>4.0.0‐RC1</version> 
</dependency>
           

3. 編寫程式

3.1 分片規則配置

分片規則配置是sharding-jdbc進行對分庫分表操作的重要依據,配置内容包括:資料源、主鍵生成政策、分片政策等。

在application.properties中配置:

server.port=56081

#工程名
spring.application.name = sharding-jdbc-simple-demo

#通路路徑
server.servlet.context-path = /sharding-jdbc-simple-demo
spring.http.encoding.enabled = true
spring.http.encoding.charset = UTF-8
spring.http.encoding.force = true

#覆寫重複的bean定義
spring.main.allow-bean-definition-overriding = true

#mybatis駝峰命名
mybatis.configuration.map-underscore-to-camel-case = true

#sharding-jdbc分片規則配置
#資料源,自定義名稱m1
spring.shardingsphere.datasource.names = m1

spring.shardingsphere.datasource.m1.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m1.url = jdbc:mysql://localhost:3306/order_db?useUnicode=true
spring.shardingsphere.datasource.m1.username = root
spring.shardingsphere.datasource.m1.password = root

# 指定t_order表的資料分布情況,配置資料節點,邏輯表t_order對應的節點是:m1.t_order_1,m1.t_order_2
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes = m1.t_order_$->{1..2}

# 指定t_order表的主鍵生成政策為SNOWFLAKE,主鍵為order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE

# 指定t_order表的分片政策,分片政策包括分片鍵和分片算法
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column = order_id
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression = t_order_$->{order_id % 2 + 1}

# 打開sql輸出日志
spring.shardingsphere.props.sql.show = true

swagger.enable = true

logging.level.root = info
logging.level.org.springframework.web = info
logging.level.com.itheima.dbsharding  = debug
logging.level.druid.sql = debug
           

1.首先定義資料源m1,并對m1進行實際的參數配置。

2.指定t_order表的資料分布情況,分布在m1.t_order_1,m1.t_order_2

3.指定t_order表的主鍵生成政策為SNOWFLAKE,SNOWFLAKE是一種分布式自增算法,保證id全局唯一

4.定義t_order分片政策,order_id為偶數的資料落在t_order_1,為奇數的落在t_order_2,分表政策的表達式為 t_order_$->{order_id % 2 + 1}

3.2.資料操作

@Mapper
@Component
public interface OrderDao {

    /**
     * 插入訂單
     */
    @Insert("insert into t_order(price,user_id,status)values(#{price},#{userId},#{status})")
    int insertOrder(@Param("price")BigDecimal price,@Param("userId")Long userId,@Param("status")String status);

    /**
     * 根據id清單查詢訂單
     */
    @Select("<script>" +
            "select" +
            " * " +
            " from t_order t " +
            " where t.order_id in " +
            " <foreach collection='orderIds' open='(' separator=',' close=')' item='id'>" +
            " #{id} " +
            " </foreach>" +
            "</script>")
    List<Map> selectOrderbyIds(@Param("orderIds") List<Long> orderIds);
}
           

3.3.測試

①編寫單元測試:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {ShardingJdbcSimpleBootstrap.class})
public class OrderDaoTest {

    @Autowired
    OrderDao orderDao;

    @Test
    public void testInsertOrder() {
        for (int i = 1; i < 20; i++) {
            orderDao.insertOrder(new BigDecimal(i), 1L, "SUCCESS");
        }
    }

    @Test
    public void testSelectOrderbyIds() {
        List<Long> ids = new ArrayList<>();
        ids.add(373897739357913088L);
        ids.add(373897037306920961L);

        List<Map> maps = orderDao.selectOrderbyIds(ids);
        System.out.println(maps);
    }
}
           

②執行testInsertOrder:

Sharding-JDBC(二)- Sharding-JDBC介紹一、Sharding-JDBC介紹二、Sharding-JDBC快速入門
Sharding-JDBC(二)- Sharding-JDBC介紹一、Sharding-JDBC介紹二、Sharding-JDBC快速入門
Sharding-JDBC(二)- Sharding-JDBC介紹一、Sharding-JDBC介紹二、Sharding-JDBC快速入門
通過日志可以發現order_id為奇數的被插入到t_order_2表,為偶數的被插入到t_order_1表,達到預期目标。

③執行testSelectOrderbyIds:

Sharding-JDBC(二)- Sharding-JDBC介紹一、Sharding-JDBC介紹二、Sharding-JDBC快速入門
通過日志可以發現,根據傳入order_id的奇偶不同,sharding-jdbc分别去不同的表檢索資料,達到預期目标。

4. 流程分析

通過日志分析,Sharding-JDBC在拿到使用者要執行的sql之後幹了哪些事兒:

(1)解析sql,擷取分片鍵值,在本例中是order_id

(2)Sharding-JDBC通過規則配置 t_order_$->{order_id % 2 + 1},知道了當order_id為偶數時,應該往 t_order_1表插資料,為奇數時,往t_order_2插資料。

(3)于是Sharding-JDBC根據order_id的值改寫sql語句,改寫後的SQL語句是真實所要執行的SQL語句。

(4)執行改寫後的真實sql語句

(5)将所有真正執行sql的結果進行彙總合并,傳回。

5. 其他內建方式

Sharding-JDBC不僅可以與spring boot良好內建,它還支援其他配置方式,共支援以下四種內建方式。

5.1 Spring Boot properties配置

#sharding-jdbc分片規則配置
#資料源,自定義名稱m1
spring.shardingsphere.datasource.names = m1

spring.shardingsphere.datasource.m1.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.m1.url = jdbc:mysql://localhost:3306/order_db?useUnicode=true
spring.shardingsphere.datasource.m1.username = root
spring.shardingsphere.datasource.m1.password = root

# 指定t_order表的資料分布情況,配置資料節點,邏輯表t_order對應的節點是:m1.t_order_1,m1.t_order_2
spring.shardingsphere.sharding.tables.t_order.actual-data-nodes = m1.t_order_$->{1..2}

# 指定t_order表的主鍵生成政策為SNOWFLAKE,主鍵為order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.t_order.key-generator.type=SNOWFLAKE

# 指定t_order表的分片政策,分片政策包括分片鍵和分片算法
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.sharding-column = order_id
spring.shardingsphere.sharding.tables.t_order.table-strategy.inline.algorithm-expression = t_order_$->{order_id % 2 + 1}
           

5.2 Spring Boot Yaml 配置

定義application.yml,内容如下:

server:
  port: 56081
  servlet:
    context-path: /sharding-jdbc-simple-demo
spring:
  application:
    name: sharding-jdbc-simple-demo
  http:
    encoding:
      enabled: true
      charset: utf-8
      force: true
  main:
    allow-bean-definition-overriding: true
  shardingsphere:
    datasource:
      names: m1
      m1:
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3306/order_db?useUnicode=true
        username: root
        password: root
    sharding:
      tables:
        t_order:
          actualDataNodes: m1.t_order_$->{1..2}
          tableStrategy:
            inline:
              shardingColumn: order_id
              algorithmExpression: t_order_$->{order_id % 2 + 1}
          keyGenerator:
            type: SNOWFLAKE
            column: order_id
    props:
      sql:
        show: true
mybatis:
  configuration:
    map-underscore-to-camel-case: true
swagger:
  enable: true
logging:
  level:
    root: info
    org.springframework.web: info
    com.itheima.dbsharding: debug
    druid.sql: debug
           

5.3 Java 配置

添加配置類:

@Configuration
public class ShardingJdbcConfig {

    // 配置分片規則
    // 定義資料源
    Map<String, DataSource> createDataSourceMap() {
        DruidDataSource dataSource1 = new DruidDataSource();
        dataSource1.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource1.setUrl("jdbc:mysql://localhost:3306/order_db?useUnicode=true");
        dataSource1.setUsername("root");
        dataSource1.setPassword("root");
        Map<String, DataSource> result = new HashMap<>();
        result.put("m1", dataSource1);
        return result;
    }
    // 定義主鍵生成政策
    private static KeyGeneratorConfiguration getKeyGeneratorConfiguration() {
        KeyGeneratorConfiguration result = new KeyGeneratorConfiguration("SNOWFLAKE","order_id");
        return result;
    }

    // 定義t_order表的分片政策
    TableRuleConfiguration getOrderTableRuleConfiguration() {
        TableRuleConfiguration result = new TableRuleConfiguration("t_order","m1.t_order_$->{1..2}");
        result.setTableShardingStrategyConfig(new InlineShardingStrategyConfiguration("order_id", "t_order_$->{order_id % 2 + 1}"));
        result.setKeyGeneratorConfig(getKeyGeneratorConfiguration());

        return result;
    }
    // 定義sharding-Jdbc資料源
    @Bean
    DataSource getShardingDataSource() throws SQLException {
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        shardingRuleConfig.getTableRuleConfigs().add(getOrderTableRuleConfiguration());
        //spring.shardingsphere.props.sql.show = true
        Properties properties = new Properties();
        properties.put("sql.show","true");
        return ShardingDataSourceFactory.createDataSource(createDataSourceMap(), shardingRuleConfig,properties);
    }

}
           
Sharding-JDBC(二)- Sharding-JDBC介紹一、Sharding-JDBC介紹二、Sharding-JDBC快速入門
Sharding-JDBC(二)- Sharding-JDBC介紹一、Sharding-JDBC介紹二、Sharding-JDBC快速入門
Sharding-JDBC(二)- Sharding-JDBC介紹一、Sharding-JDBC介紹二、Sharding-JDBC快速入門

注意:

Sharding-Jdbc與SpringBoot內建,會自動從配置檔案中讀“spring.shardingsphere”字首的配置

由于使用java配置類方式,沒有配置檔案,讀取不到就會報以上錯誤

此時需要在啟動類中加上@SpringBootApplication(exclude = SpringBootConfiguration.class)

import org.apache.shardingsphere.shardingjdbc.spring.boot.SpringBootConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(exclude = SpringBootConfiguration.class)
public class ShardingJdbcSimpleBootstrap {

    public static void main(String[] args) {
        SpringApplication.run(ShardingJdbcSimpleBootstrap.class, args);
    }

}
           

5.4 Spring命名空間配置

此方式使用xml方式配置,不推薦使用。

<?xml version="1.0" encoding="UTF‐8"?>
<?xml version="1.0" encoding="UTF‐8"?>
	xmlns:xsi="http://www.w3.org/2001/XMLSchema‐instance" 
	xmlns:p="http://www.springframework.org/schema/p" 
	xmlns:context="http://www.springframework.org/schema/context" 、
	xmlns:tx="http://www.springframework.org/schema/tx" 
	xmlns:sharding="http://shardingsphere.apache.org/schema/shardingsphere/sharding"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring‐beans.xsd 
	http://shardingsphere.apache.org/schema/shardingsphere/sharding
			http://shardingsphere.apache.org/schema/shardingsphere/sharding/sharding.xsd 
			http://www.springframework.org/schema/context 
			http://www.springframework.org/schema/context/spring‐context.xsd 
			http://www.springframework.org/schema/tx 
			http://www.springframework.org/schema/tx/spring‐tx.xsd">

<context:annotation‐config />

<!‐‐定義多個資料源‐‐> 
<bean id="m1" class="com.alibaba.druid.pool.DruidDataSource" destroy‐method="close"> 
	<property name="driverClassName" value="com.mysql.jdbc.Driver" /> 
	<property name="url" value="jdbc:mysql://localhost:3306/order_db_1?useUnicode=true" /> 
	<property name="username" value="root" /> 
	<property name="password" value="root" /> 
</bean>

<!‐‐定義分庫政策‐‐> 
<sharding:inline‐strategy id="tableShardingStrategy" sharding‐column="order_id" algorithm‐ expression="t_order_$‐>{order_id % 2 + 1}" /> 

<!‐‐定義主鍵生成政策‐‐> 
<sharding:key‐generator id="orderKeyGenerator" type="SNOWFLAKE" column="order_id" /> 

<!‐‐定義sharding‐Jdbc資料源‐‐> 
<sharding:data‐source id="shardingDataSource"> 
	<sharding:sharding‐rule data‐source‐names="m1"> 
		<sharding:table‐rules> 
			<sharding:table‐rule logic‐table="t_order" table‐strategy‐ ref="tableShardingStrategy" key‐generator‐ref="orderKeyGenerator" /> 
		</sharding:table‐rules> 
	</sharding:sharding‐rule> 
</sharding:data‐source> 

</beans>