shardingsphere sharding-jdbc配置和使用教程
sharding-jdbc使用教程概念分库分表Sharding-JDBC逻辑表真实表数据节点环境要求Sharding-JDBC配置行表达式代码项目依赖配置数据库初始化源码片段代码结构代码清单测试类运行结果概念分库分表分库:从单个数据库拆分成多个数据库的过程,将数据散落在多个数据库中。分表:从单张表拆分成多张表的过程,将数据散落在多张表内。本文主要针对水平拆分。Sharding-JDBCShardi
文章共6,597字 · 阅读需要大约22分钟
一键AI生成摘要,助你高效阅读
问答
·
sharding-jdbc使用教程
概念
分库分表
分库:从单个数据库拆分成多个数据库的过程,将数据散落在多个数据库中。
分表:从单张表拆分成多张表的过程,将数据散落在多张表内。
本文主要针对水平拆分。
Sharding-JDBC
Sharding-JDBC是一套开源的分布式数据库中间件解决方案,定位为轻量级Java框架,在Java的JDBC层提供的额外服务。 它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的JDBC驱动,完全兼容JDBC和各种ORM框架。
逻辑表
水平拆分的数据库(表)的相同逻辑和数据结构表的总称。例:订单数据根据主键尾数拆分为2张表,分别是biz_order_1到biz_order_1,他们的逻辑表名为biz_order。
真实表
在分片的数据库中真实存在的物理表。即上个示例中的biz_order_1到t_order_2。
数据节点
数据分片的最小单元。由数据源名称和数据表组成,例:m_1.biz_order_1。
环境要求
jdk版本:1.8
mysql版本:5.7
spring-boot版本:2.2.1.RELEASE
sharding-jdbc版本:4.1.1
Sharding-JDBC配置
行表达式
行表达式标识符可以使用${...}或$->{...},但前者与Spring本身的属性文件占位符冲突,因此在Spring环境中使用行表达式标识符建议使用$->{...}。
代码
项目依赖
pom.xml
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.sharding</groupId>
<artifactId>sharding-demo</artifactId>
<version>1</version>
<name>sharding-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.20</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.70</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
配置
application.properties分片配置
。
#定义两个数据源m1,m2
spring.shardingsphere.datasource.names=m1,m2
#配置数据源具体内容,包含连接池,驱动,地址,用户名和密码
#m1数据源配置
spring.shardingsphere.datasource.m1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m1.url=jdbc:mysql://192.168.1.1:3306/edu_db_1?characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m1.username=root
spring.shardingsphere.datasource.m1.password=123456
#m2数据源配置
spring.shardingsphere.datasource.m2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.m2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.m2.url=jdbc:mysql://192.168.1.2:3306/edu_db_2?characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.shardingsphere.datasource.m2.username=root
spring.shardingsphere.datasource.m2.password=123456
#指定数据库分布情况,数据库里面表分布情况
# m1 m2 biz_order_1 biz_order_2
spring.shardingsphere.sharding.tables.biz_order.actual-data-nodes=m$->{1..2}.biz_order_$->{1..2}
# 指定 biz_order 表里面主键 order_id 生成策略 SNOWFLAKE(雪花算法)
spring.shardingsphere.sharding.tables.biz_order.key-generator.column=order_id
spring.shardingsphere.sharding.tables.biz_order.key-generator.type=SNOWFLAKE
# 指定数据库分片策略 是偶数添加 m1,是奇数添加 m2
spring.shardingsphere.sharding.tables.biz_order.database-strategy.inline.sharding-column=order_id
spring.shardingsphere.sharding.tables.biz_order.database-strategy.inline.algorithm-expression=m$->{order_id % 2 + 1}
#指定数据表分片策略 按order_user_id进行分表 偶数到表1 奇数到2
spring.shardingsphere.sharding.tables.biz_order.table-strategy.inline.sharding-column=order_user_id
spring.shardingsphere.sharding.tables.biz_order.table-strategy.inline.algorithm-expression=biz_order_$->{order_user_id%2+1}
#订单item
spring.shardingsphere.sharding.tables.biz_order_item.actual-data-nodes=m$->{1..2}.biz_order_item_$->{1..2}
# 指定 biz_order_item 表里面主键 cid 生成策略 SNOWFLAKE
spring.shardingsphere.sharding.tables.biz_order_item.key-generator.column=order_item_id
spring.shardingsphere.sharding.tables.biz_order_item.key-generator.type=SNOWFLAKE
# 指定数据库分片策略 是偶数添加 m1,是奇数添加 m2
spring.shardingsphere.sharding.tables.biz_order_item.database-strategy.inline.sharding-column=order_id
spring.shardingsphere.sharding.tables.biz_order_item.database-strategy.inline.algorithm-expression=m$->{order_id % 2 + 1}
#指定数据表分片策略 按order_user_id进行分表 偶数到表1 奇数到2
spring.shardingsphere.sharding.tables.biz_order_item.table-strategy.inline.sharding-column=order_user_id
spring.shardingsphere.sharding.tables.biz_order_item.table-strategy.inline.algorithm-expression=biz_order_item_$->{order_user_id%2+1}
#设置绑定关系
spring.shardingsphere.sharding.binding-tables=biz_order,biz_order_item
#默认数据源,即未配置分表规则的表数据存储表
spring.shardingsphere.sharding.default-data-source-name=m1
# 打开 sql 输出日志
spring.shardingsphere.props.sql.show=true
# mybatis配置
mybatis-plus.mapper-locations=classpath:mapper/*.xml
数据库初始化
首先准备两个数据库,例如本文中的为192.168.1.1:3306/edu_db_1,192.168.1.2:3306/edu_db_2.
初始化表:
biz_order表
:
CREATE TABLE `biz_order_1` (
`order_id` bigint(20) NOT NULL,
`order_no` varchar(15) COLLATE utf8mb4_bin DEFAULT NULL,
`order_time` datetime DEFAULT NULL,
`order_money` decimal(20,2) DEFAULT NULL,
`order_status` char(1) COLLATE utf8mb4_bin DEFAULT NULL,
`order_user_id` int(11) DEFAULT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
CREATE TABLE `biz_order_2` (
`order_id` bigint(20) NOT NULL,
`order_no` varchar(15) COLLATE utf8mb4_bin DEFAULT NULL,
`order_time` datetime DEFAULT NULL,
`order_money` decimal(20,2) DEFAULT NULL,
`order_status` char(1) COLLATE utf8mb4_bin DEFAULT NULL,
`order_user_id` int(11) DEFAULT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
biz_order_item
表:
CREATE TABLE `biz_order_item_1` (
`order_item_id` bigint(20) NOT NULL,
`order_id` bigint(20) DEFAULT NULL,
`goods_name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
`goods_num` int(11) DEFAULT NULL,
`order_user_id` int(11) DEFAULT NULL,
`goods_price` decimal(10,2) DEFAULT NULL,
PRIMARY KEY (`order_item_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
CREATE TABLE `biz_order_item_2` (
`order_item_id` bigint(20) NOT NULL,
`order_id` bigint(20) DEFAULT NULL,
`goods_name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
`goods_num` int(11) DEFAULT NULL,
`order_user_id` int(11) DEFAULT NULL,
`goods_price` decimal(10,2) DEFAULT NULL,
PRIMARY KEY (`order_item_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
源码片段
代码结构
代码清单
启动类
:
@SpringBootApplication
@MapperScan(value = "com.sharding.shardingdemo.dao")
public class ShardingDemoApplication {
public static void main(String[] args) {
SpringApplication.run(ShardingDemoApplication.class, args);
}
}
实体类BizOrder
:
@TableId
private Long orderId;
private String orderNo;
private Date orderTime;
private BigDecimal orderMoney;
private String orderStatus;
private Integer orderUserId;
实体类BizOrderItem
:
@TableId
private Long orderItemId;
private Long orderId;
private String goodsName;
private int goodsNum;
private Integer orderUserId;
private BigDecimal goodsPrice;
联表查询结果集OrderAndItemModel
:
private Long orderId;
private String orderNo;
private Date orderTime;
private BigDecimal orderMoney;
private String orderStatus;
private Integer orderUserId;
private List<BizOrderItem> items;
dao层mapper
:
@Repository
public interface BizOrderMapper extends BaseMapper<BizOrder> {
}
@Repository
public interface BizOrderItemMapper extends BaseMapper<BizOrderItem> {
List<OrderAndItemModel> selectOrderAndItem(@Param("orderId") Long orderId, @Param("userId")Integer userId);
}
mapper.xml
<mapper namespace="com.sharding.shardingdemo.dao.BizOrderItemMapper">
<resultMap id="orderMap" type="com.sharding.shardingdemo.model.OrderAndItemModel">
<id column="order_id" property="orderId" />
<result column="order_no" property="orderNo" />
<result column="order_time" property="orderTime" />
<result column="order_money" property="orderMoney" />
<result column="order_status" property="orderStatus" />
<result column="order_user_id" property="orderUserId" />
<collection property="items" ofType="com.sharding.shardingdemo.entity.BizOrderItem">
<id column="order_item_id" property="orderItemId" />
<result column="goods_name" property="goodsName" />
<result column="goods_num" property="goodsNum" />
<result column="goods_price" property="goodsPrice" />
</collection>
</resultMap>
<select id="selectOrderAndItem" resultMap="orderMap">
SELECT
ord.order_id order_id,
ord.order_no order_no,
ord.order_time order_time,
ord.order_money order_money,
ord.order_status order_status,
ord.order_user_id order_user_id,
item.order_item_id order_item_id,
item.goods_name goods_name,
item.goods_num goods_num,
item.goods_price goods_price
FROM biz_order ord
LEFT JOIN biz_order_item item ON ord.order_id = item.order_id
<where>
<if test="orderId!=null">
and ord.order_id = #{orderId}
</if>
<if test="userId!=null">
and ord.order_user_id = #{userId}
</if>
</where>
</select>
</mapper>
测试类
测试类
:
import com.alibaba.fastjson.JSONObject;
import com.sharding.shardingdemo.dao.BizOrderItemMapper;
import com.sharding.shardingdemo.dao.BizOrderMapper;
import com.sharding.shardingdemo.entity.BizOrder;
import com.sharding.shardingdemo.entity.BizOrderItem;
import com.sharding.shardingdemo.model.OrderAndItemModel;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
@SpringBootTest
@RunWith(SpringRunner.class)
class ShardingDemoApplicationTests {
@Autowired
private BizOrderMapper orderMapper;
@Autowired
private BizOrderItemMapper orderItemMapper;
@Test
void addOrder(){
// 插入订单
BizOrder order = new BizOrder();
order.setOrderMoney(new BigDecimal("100"));
order.setOrderNo(System.currentTimeMillis()/1000+"");
order.setOrderStatus("0");
order.setOrderUserId(1);
order.setOrderTime(new Date());
orderMapper.insert(order);
Long orderId = order.getOrderId();
System.out.println(orderId);
// 插入订单item
BizOrderItem item1 = new BizOrderItem();
BizOrderItem item2 = new BizOrderItem();
item1.setGoodsName("APPLE手机");
item1.setGoodsNum(3);
item1.setGoodsPrice(new BigDecimal("1200"));
item1.setOrderId(orderId);
item1.setOrderUserId(order.getOrderUserId());
orderItemMapper.insert(item1);
item2.setGoodsName("HONOR手机");
item2.setGoodsNum(4);
item2.setGoodsPrice(new BigDecimal("3300"));
item2.setOrderId(orderId);
item2.setOrderUserId(order.getOrderUserId());
orderItemMapper.insert(item2);
}
@Test
void selectOrder(){
// 关联查询订单和订单item
List<OrderAndItemModel> orderAndItemModels = orderItemMapper.selectOrderAndItem(orderId,orderUserId);
System.out.println(JSONObject.toJSONString(orderAndItemModels));
}
}
运行结果
打印日志
:
[ main] ShardingSphere-SQL: Logic SQL: (逻辑SQL)
INSERT INTO biz_order ( order_id,order_no,order_time,order_money,order_status,order_user_id ) VALUES ( ?,?,?,?,?,? )
[ main] ShardingSphere-SQL: Actual SQL: (实际入库SQL)
m1 ::: INSERT INTO biz_order_2 ( order_id,order_no,order_time,order_money,order_status,order_user_id )
VALUES (?, ?, ?, ?, ?, ?) ::: [1461169036709548034, 1637204820, 2021-11-18 11:07:00.098, 100, 0, 1]
[main] ShardingSphere-SQL: Logic SQL:
INSERT INTO biz_order_item ( order_item_id,order_id,goods_name,goods_num,order_user_id,goods_price ) VALUES ( ?,?,?,?,?,? )
[ main] ShardingSphere-SQL: Actual SQL: m1 :::
INSERT INTO biz_order_item_2 ( order_item_id,order_id,goods_name,goods_num,order_user_id,goods_price ) VALUES (?, ?, ?, ?, ?, ?)
::: [1461169040706719745, 1461169036709548034, APPLE手机2, 3, 1, 1200]
[ main] ShardingSphere-SQL : Logic SQL:
INSERT INTO biz_order_item ( order_item_id,order_id,goods_name,goods_num,order_user_id,goods_price ) VALUES ( ?,?,?,?,?,? )
[main] ShardingSphere-SQL: Actual SQL: m1 :::
INSERT INTO biz_order_item_2 ( order_item_id,order_id,goods_name,goods_num,order_user_id,goods_price ) VALUES (?, ?, ?, ?, ?, ?)
::: [1461169041067429890, 1461169036709548034, HONOR手机2, 4, 1, 3300]
结果分析
:
日志打印显示sharding-jdbc会根据配置对入库数据进行分片计算,然后将数据插入对应数据库和对应表。
执行ShardingDemoApplicationTests.addOrder()方法后,可以看到订单数据和订单详情分别会根据order_id分布到两个数据库中,是偶数添加到 m1,是奇数添加到m2;根据order_user_id进行分表 偶数到表1 奇数到表2。
执行selectOrder()方法,会根据传入的orderId和orderUserId自动查询对应分片规则下的库表,若都不指定,则会按m{1,2} * order{1,2}的笛卡尔集进行查询所有组合方式的库表。
更多推荐
已为社区贡献1条内容
所有评论(0)