說明:Sharding-jdbc是常見的分庫分表工具,本文介紹Sharding-jdbc的基礎使用。
分庫分表
首先,介紹一下分庫分表:
(1)分庫
水平分庫:以字段為依據,按照一定策略(hash、range),將一個庫中的數據拆分到多個庫中;
垂直分庫:以表為依據,按照業務歸屬不同,將不同的表拆分到不同的庫中;
(2)分表
水平分表:按照策略,將記錄路由到不同的表上,常見的策略有范圍、hash、字段值;
垂直分表:根據業務相關性,拆分表字段,將一張表拆分為多張表;
水平分就是橫著一刀,垂直分就是豎著一刀。
垂直分庫、垂直分表,我認為是設計時考慮的,像微服務架構,根據業務場景拆分多個小的服務,每個服務都可以有自己的數據庫,是垂直分庫。
而垂直分表,某張表的字段過長,可以考慮將表字段按照業務相關性拆分成多張表,另外,當表中有text類型的字段時,為了避免影響其他字段索引率,也需要獨立出來一張表,用主鍵對應(阿里巴巴《Java開發手冊》),是垂直分表的體現。
(3)需要考慮的問題
分庫:
-
跨庫事務;
-
跨庫的JOIN;
分表:
-
多張表如何保證主鍵不重復;
-
多張表的count、order by、group by 及 聚合函數問題;
Sharding-jdbc使用
這里介紹使用Sharding-jdbc實現水平分表
(1)創建數據庫表
先創建兩張數據庫表
# 創建數據庫
create schema order_db collate utf8mb3_general_ci;# 創建表
use order_db;CREATE TABLE `t_order_1`
(`order_id` bigint NOT NULL COMMENT '訂單id',`price` decimal(10, 2) NOT NULL COMMENT '訂單價格',`user_id` bigint NOT NULL COMMENT '下單用戶id',`status` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '訂單狀態',PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDBDEFAULT CHARSET = utf8mb3ROW_FORMAT = DYNAMIC;CREATE TABLE `t_order_2`
(`order_id` bigint NOT NULL COMMENT '訂單id',`price` decimal(10, 2) NOT NULL COMMENT '訂單價格',`user_id` bigint NOT NULL COMMENT '下單用戶id',`status` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '訂單狀態',PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDBDEFAULT CHARSET = utf8mb3ROW_FORMAT = DYNAMIC;
(2)創建項目
創建一個Spring Boot項目,pom如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.hezy</groupId><artifactId>sharding-jdbc-demo</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!-- shardingJDBC核心依賴 --><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId><version>5.2.1</version><exclusions><exclusion><artifactId>snakeyaml</artifactId><groupId>org.yaml</groupId></exclusion><exclusion><artifactId>cosid-core</artifactId><groupId>me.ahoo.cosid</groupId></exclusion></exclusions></dependency><!-- 版本沖突 --><dependency><groupId>org.yaml</groupId><artifactId>snakeyaml</artifactId><version>1.33</version></dependency><dependency><groupId>me.ahoo.cosid</groupId><artifactId>cosid-core</artifactId><version>1.19.3</version></dependency><!--XA 分布式事務 --><dependency><groupId>org.apache.shardingsphere</groupId><artifactId>shardingsphere-transaction-xa-core</artifactId><version>5.2.1</version><exclusions><exclusion><artifactId>transactions-jdbc</artifactId><groupId>com.atomikos</groupId></exclusion><exclusion><artifactId>transactions-jta</artifactId><groupId>com.atomikos</groupId></exclusion></exclusions></dependency><!-- SpringBoot依賴 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><exclusions><exclusion><artifactId>snakeyaml</artifactId><groupId>org.yaml</groupId></exclusion></exclusions></dependency><!--測試類依賴--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><!--durid數據庫連接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.20</version></dependency><!-- mysql連接驅動 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!-- mybatisplus依賴 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3.3</version></dependency></dependencies>
</project>
(3)編寫代碼
創建pojo對象,注意表名是t_order
,沒有加后綴
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;
import java.math.BigDecimal;@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("t_order")
public class Order implements Serializable {@TableIdprivate Long orderId;private BigDecimal price;private Long userId;private String status;
}
創建Service和Mapper
(OrderService)
import com.baomidou.mybatisplus.extension.service.IService;
import com.hezy.pojo.Order;public interface OrderService extends IService<Order> {
}
(OrderServiceImpl)
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hezy.mapper.OrderMapper;
import com.hezy.pojo.Order;
import com.hezy.service.OrderService;
import org.springframework.stereotype.Service;@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
}
(OrderMapper)
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hezy.pojo.Order;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface OrderMapper extends BaseMapper<Order> {
}
啟動類
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class App {public static void main(String[] args) {SpringApplication.run(App.class, args);}
}
(4)配置文件
配置文件中,定義了數據庫配置及水平分表的策略,采用取模(%2)的方式
spring:main:# 允許Bean重復定義覆蓋allow-bean-definition-overriding: trueshardingsphere:datasource:# 數據源名稱,多個數據源時使用逗號(,)分割names: m1m1:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/order_db?serverTimezone=Asia/Shanghai&characterEncoding=utf8username: rootpassword: 123456sharding:tables:t_order:# 配置數據節點,m1.t_order_1,m1.t_order_2,使用上面names的配置名稱actual-data-nodes: m1.t_order_$->{1..2}key-generator:# 配置主鍵,及主鍵生成算法column: order_id# 雪花算法type: SNOWFLAKEtable-strategy:inline:# 配置分片鍵sharding-column: order_id# 配置分片策略( order_id % 2 + 1 的值就是數據實際要進入的數據表 )# 利用“取模”計算的方式進行分片,將分片鍵除以分片表的個數,得到的模就是該數據要進入的數據表# 示例中,共有2張分片表,則此處求取分片鍵的值與分片表的模數,表示為 order_id % 2,又因為分片表的初始值以 1 開始,則再加上1algorithm-expression: t_order_$->{order_id % 2 + 1}
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl# 配置數據庫字段與實體類映射方式,是否是小駝峰命名法map-underscore-to-camel-case: trueglobal-config:db-config:# 配置數據表前綴table-prefix: t_
(5)測試
寫一個測試類,如下:
import com.hezy.pojo.Order;
import com.hezy.service.OrderService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.math.BigDecimal;
import java.util.List;@SpringBootTest
public class OrderMapperTest {@Autowiredprivate OrderService orderService;@Testpublic void insertTest() {for (int i = 0; i < 10; i++) {Order order = new Order();order.setStatus("正常");order.setPrice(new BigDecimal(20));order.setUserId(1L);boolean save = orderService.save(order);System.out.println(save);}}@Testpublic void findAllTest() {List<Order> list = orderService.list();System.out.println(list);}
}
執行插入方法,插入完成
可見數據分散插入到對應的表中
試一下查詢,也是查出10條記錄,而不是單張表的5條記錄。
注意
如果是手寫SQL,不用Mybatis-Plus的API,那么寫SQL的時候注意不要帶上表名后綴
@Select("select * from t_order")List<Order> findALl();
不要寫成下面這樣,這樣就是查單張表的5條記錄了。
@Select("select * from t_order_1")List<Order> findALl();
參考
代碼:
-
https://gitee.com/learning_demo/sharding-jdbc
-
https://gitee.com/xscodeit/xushu_springboot_demos/tree/master/Sharding
博客:
- Sharding-JDBC分庫分表