ps:
概念:水平分表是在同一個數據庫內,把同一個表的數據按一定規則拆到多個表中
一、準備環境:
1.單數據庫下,分表:
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;
二、pom.xml:(導入相應jar包)
ps:
這裏用的springboot版本是2.2.2.RELEASE;
這裏sharding-jdbc-spring-boot-starter我用4.0.0-RC2整合,控制檯會報錯:
Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.20</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0-RC1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
三、 application.yml:(重要)
#服務端口
server:
port: 56081
#服務名
spring:
application:
name: sharding-jdbc-examples
http:
encoding:
enabled: true
charset: utf-8
force: true
main:
allow-bean-definition-overriding: true
#shardingsphere相關配置
shardingsphere:
datasource:
names: m1 #配置庫的名字,隨意
m1: #配置目前m1庫的數據源信息
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.87.133:3306/order_db?useUnicode=true
username: root
password: 123456
sharding:
tables:
t_order: # 指定t_order表的數據分佈情況,配置數據節點
actualDataNodes: m1.t_order_$->{1..2}
tableStrategy:
inline: # 指定t_order表的分片策略,分片策略包括分片鍵和分片算法
shardingColumn: order_id
algorithmExpression: t_order_$->{order_id % 2 + 1}
keyGenerator: # 指定t_order表的主鍵生成策略爲SNOWFLAKE
type: SNOWFLAKE #主鍵生成策略爲SNOWFLAKE
column: order_id #指定主鍵
props:
sql:
show: true
#日誌打印
logging:
level:
root: info
org.springframework.web: info
com.lucifer.sharding.dao: debug
druid.sql: debug
t_order:在這裏是邏輯表名,並非真實表名。真實表名是t_order_1,t_order_2;
actualDataNodes:m1.t_order_$->{1..2} 這裏的m1就是庫名(上面已經設置了),相當於就是 庫名.邏輯表名_1,庫名.邏輯表名_2======》對應的就是兩個真實的表名。
shardingColumn:分片鍵,
algorithmExpression: t_order_$->{order_id % 2 + 1} :分片規則。t_order_$->{order_id % 2 + 1}分兩半來看:
(1)--》t_order_邏輯表名_值,至於這個值是1還是2,是由
(2)---》order_id % 2 + 1來的,order_id的值除以2取模再加1.
也就是order_id爲偶數的數據落在t_order_1,爲奇數的落在t_order_2。
spring.main.allow-bean-definition-overriding: true :必須設置,否者會報錯;
The bean 'dataSource', defined in class path resource [org/apache/shardingsphere/shardingjdbc/spring/boot/SpringBootConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [com/alibaba/druid/spring/boot/autoconfigure/DruidDataSourceAutoConfigure.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
意思很明確,有兩個同樣名字的bean。
查看SpringBoot和druid源碼,可以看到有相同名字的bean。
四、代碼段
ps:代碼很簡單,主要是配置,所以這裏就不多說了。
controller:
package com.lucifer.sharding.controller;
import com.lucifer.sharding.service.OrderService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @author Lucifer
*/
@RestController
public class OrderController {
@Resource
private OrderService orderService;
@GetMapping(value = "/add")
public void addOrder() {
orderService.addOrder();
}
@GetMapping(value = "/find")
public void findOrder() {
orderService.findOrder();
}
}
service接口:
package com.lucifer.sharding.service;
/**
* @author Lucifer
*/
public interface OrderService {
/**
* 新增訂單
*
*/
void addOrder();
/**
* 查詢
*/
void findOrder();
}
service實現類:
package com.lucifer.sharding.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lucifer.sharding.dao.OrderDao;
import com.lucifer.sharding.pojo.Order;
import com.lucifer.sharding.service.OrderService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* @author Lucifer
*/
@Service
public class OrderServiceImpl implements OrderService {
@Resource
OrderDao orderDao;
@Override
public void addOrder() {
for (int i = 0; i < 10; i++) {
Order order = new Order();
order.setPrice(new BigDecimal(Math.random()));
order.setUserId(new Random().nextLong());
order.setStatus("0");
orderDao.insert(order);
}
}
//執行新增後,將兩庫的數據各取一條,來測試
@Override
public void findOrder() {
List<Long> list=new ArrayList<>();
list.add(418415166183440384L);
list.add(418417197166100481L);
QueryWrapper<Order> queryWrapper=new QueryWrapper<>();
queryWrapper.in("order_id", list);
orderDao.selectList(queryWrapper);
}
}
dao層接口:
package com.lucifer.sharding.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lucifer.sharding.pojo.Order;
/**
* @author Lucifer
*/
public interface OrderDao extends BaseMapper<Order> {
}
實體類:
package com.lucifer.sharding.pojo;
import java.io.Serializable;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
/**
* @author Lucifer
*/
@TableName(value = "t_order")
@Data
public class Order implements Serializable {
/**
* 訂單id
*/
private Long orderId;
/**
* 訂單價格
*/
private BigDecimal price;
/**
* 下單用戶id
*/
private Long userId;
/**
* 訂單狀態
*/
private String status;
private static final long serialVersionUID = 1L;
}
ps:
需要說的是這個mybatis-plus的註解@TableName(value = "t_order")指定表名,這裏指定邏輯表名。
SpringBoot啓動類上添加@MapperScan註解。
五、測試
控制檯打印:
數據庫:
其實大概的邏輯就是ShardingSphere給你用雪花算法生成了一個主鍵order_id的值,而根據這個值在配置文件中所配置的規則來決定插入到哪個表中,至於查詢也是,根據你的order_id來決定來查哪張表(測試截圖忽略)。
也就是如果查詢字段不是分片鍵,那麼會查兩個表;如圖: