1 搭建基础环境
创建数据库lg_order, 模拟将订单表进行水平拆分, 创建两张表pay_order_1 与 pay_order_2,这两张表是订单表拆分后的表,我们通过Sharding-Jdbc向订单表插入数据,按照一定的分片规则,主键为偶数的落入pay_order_1表 ,为奇数的落入pay_order_2表, 再通过Sharding-Jdbc 进行查询.
CREATE DATABASE lg_order CHARACTER SET 'utf8';
DROP TABLE IF EXISTS pay_order_1;
CREATE TABLE pay_order_1 (
order_id BIGINT(20) PRIMARY KEY AUTO_INCREMENT ,
user_id INT(11) ,
product_name VARCHAR(128),
COUNT INT(11)
);
DROP TABLE IF EXISTS pay_order_2;
CREATE TABLE pay_order_2 (
order_id BIGINT(20) PRIMARY KEY AUTO_INCREMENT ,
user_id INT(11) ,
product_name VARCHAR(128),
COUNT INT(11)
);
- 创建SpringBoot项目引入maven依赖
sharding-jdbc
以
jar
包形式提供服务,所以要先引入
maven
依赖。
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.0.0-RC1</version>
</dependency>
2
分片规则配置
(
水平分表
)
使用sharding-jdbc 对数据库中水平拆分的表进行操作,通过sharding-jdbc对分库分表的规则进行配置,配置内容包括:数据源、主键生成策略、分片策略等。
application.properties
- 基础配置
spring.application.name = sharding-jdbc-simple
server.servlet.context-path = /sharding-jdbc
spring.http.encoding.enabled = true
spring.http.encoding.charset = UTF-8
spring.http.encoding.force = true
spring.main.allow-bean-definition-overriding = true
mybatis.configuration.map-underscore-to-camel-case = true
- 数据源
# 定义数据源
spring.shardingsphere.datasource.names = db1
spring.shardingsphere.datasource.db1.type = com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.db1.driver-class-name = com.mysql.jdbc.Driver
spring.shardingsphere.datasource.db1.url = jdbc:mysql://localhost:3306/lg_order_1?characterEncoding=UTF-8&useSSL=false
spring.shardingsphere.datasource.db1.username = root
spring.shardingsphere.datasource.db1.password = 123456
- 配置数据节点
#配置数据节点,指定节点的信息
spring.shardingsphere.sharding.tables.pay_order.actual-data-nodes = db1.pay_order_$->{1..2}
表达式
db1.pay_order_$->{1..2}
$
会被 大括号中的
{1..2}
所替换
会有两种选择
:
db1.pay_order_1
和
db1.pay_order_2
- 配置主键生成策略
#指定pay_order表 (逻辑表)的主键生成策略为 SNOWFLAKE
spring.shardingsphere.sharding.tables.pay_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.pay_order.key-generator.type=SNOWFLAKE
使用
shardingJDBC
提供的主键生成策略
,
全局主键
为避免主键重复
,
生成主键采用
SNOWFLAKE
分布式
ID
生成算法
- 配置分片算法
#指定pay_order表的分片策略,分片策略包括分片键和分片算法
spring.shardingsphere.sharding.tables.pay_order.table- strategy.inline.sharding-column = order_id
spring.shardingsphere.sharding.tables.pay_order.table- strategy.inline.algorithm-expression = pay_order_$->{order_id % 2 + 1}
分表策略表达式
: pay_order_$-> {order_id % 2 + 1}
{order_id % 2 + 1}
结果是偶数 操作
pay_order_1
表
{order_id % 2 + 1}
结果是奇数
操作
pay_order_2
表
- 打开SQL日志
# 打开sql输出日志
spring.shardingsphere.props.sql.show = true
- 步骤总结
- 1. 定义数据源
- 2. 指定pay_order 表的数据分布情况, 分布在 pay_order_1 和 pay_order_2
- 3. 指定pay_order 表的主键生成策略为SNOWFLAKE,是一种分布式自增算法,保证id全局唯一
- 4. 定义pay_order分片策略,order_id为偶数的数据下沉到pay_order_1,为奇数下沉到在pay_order_2
3 编写程序
@Mapper
@Component
public interface PayOrderDao {
/**
* 新增订单
* */
@Insert("INSERT INTO pay_order(user_id,product_name,COUNT) VALUES(#{user_id},#{product_name},#{count})")
int insertPayOrder(@Param("user_id") int user_id,@Param("product_name") String product_name,@Param("count") int count);
/**
* 根据ID 查询订单
* */
@Select({"<script>"+
"select * from pay_order p where p.order_id in " +
"<foreach collection='orderIds' item='id' open='(' separator = ',' close=')'>#{id}</foreach>"
+"</script>"})
List<Map> findOrderByIds(@Param("orderIds") List<Long> orderIds);
}
测试:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = RunBoot.class)
public class PayOrderDaoTest {
@Autowired
PayOrderDao orderDao;
@Test
public void testInsertPayOrder(){
for (int i = 0; i < 10; i++) {
orderDao.insertPayOrder(100+i,"华为手机",10);
}
}
@Test
public void testFindOrderByIds(){
List<Long> ids = new ArrayList<>();
//lg_order_1 数据库的 pay_order_2
ids.add(523895691341201409L);
ids.add(523895692029067265L);
ids.add(523895190771990528L); // lg_order_2 -> pay_order_1
ids.add(523895189668888577L); // lg_order_2 -> pay_order_2
// //order_1
ids.add(523812405814231040L);
ids.add(523812405851979776L);
//order_2
ids.add(523812055904419841L);
ids.add(523812405310914561L);
List<Map> list = orderDao.findOrderByIds(ids);
System.out.println(list);
}
}
4 ShardingJDBC
执行流程
当
ShardingJDBC
接收到发送的
SQL
之后
,
会执行下面的步骤
,
最终返回执行结果
- 1. SQL解析: 编写SQL查询的是逻辑表, 执行时 ShardingJDBC 要解析SQL ,解析的目的是为了找到需要改写的位置.
- 2. SQL路由: SQL的路由是指 将对逻辑表的操作,映射到对应的数据节点的过程. ShardingJDBC会获取分片键判断是否正确,正确 就执行分片策略(算法) 来找到真实的表.
- 3. SQL改写: 程序员面向的是逻辑表编写SQL, 并不能直接在真实的数据库中执行,SQL改写用于将逻辑SQL改为在真实的数据库中可以正确执行的SQL.
- 4. SQL执行: 通过配置规则 pay_order_$->{order_id % 2 + 1} ,可以知道当 order_id 为偶数时 ,应该向 pay_order_1表中插入数据, 为奇数时向 pay_order_2表插入数据.
- 5. 将所有真正执行sql的结果进行汇总合并,然后返回。