提交 8f5e9c98 编写于 作者: 小傅哥's avatar 小傅哥

小傅哥,feat:分库分表路由组件 sharding-jdbc

上级 0db5b6e1
......@@ -121,6 +121,16 @@
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.23.4</version>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core</artifactId>
<version>5.4.1</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.33</version>
</dependency>
<!-- 工程模块 -->
<dependency>
......
......@@ -78,7 +78,6 @@
<artifactId>converter-gson</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
......@@ -95,6 +94,14 @@
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core</artifactId>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<!-- 工程模块;启动依赖 trigger->domain, infrastructure-->
<dependency>
......@@ -151,5 +158,4 @@
</plugins>
</build>
</project>
......@@ -12,27 +12,15 @@ thread:
block-queue-size: 5000
policy: CallerRunsPolicy
# 数据库配置;启动时配置数据库资源信息
# 数据库配置 - sharding-jdbc 分库分表
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://127.0.0.1:13306/xfg_frame_archetype?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC&useSSL=true
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
pool-name: Retail_HikariCP
minimum-idle: 15 #最小空闲连接数量
idle-timeout: 180000 #空闲连接存活最大时间,默认600000(10分钟)
maximum-pool-size: 25 #连接池最大连接数,默认是10
auto-commit: true #此属性控制从池返回的连接的默认自动提交行为,默认值:true
max-lifetime: 1800000 #此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
connection-timeout: 30000 #数据库连接超时时间,默认30秒,即30000
connection-test-query: SELECT 1
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriver
url: jdbc:shardingsphere:classpath:sharding/sharding-jdbc-dev.yaml
#mybatis:
# mapper-locations: classpath:/mybatis/mapper/*.xml
# config-location: classpath:/mybatis/config/mybatis-config.xml
mybatis:
mapper-locations: classpath:/mybatis/mapper/*.xml
config-location: classpath:/mybatis/config/mybatis-config.xml
# Redis
redis:
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.bugstack.infrastructure.persistent.dao.Xxx">
<resultMap id="CaseMap" type="cn.bugstack.infrastructure.persistent.po.A">
<id column="id" property="id"/>
<result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/>
</resultMap>
<insert id="insert" parameterType="cn.bugstack.infrastructure.persistent.po.A">
INSERT INTO table(a,b,c) VALUES(#{a}, #{b}, #{c})
</insert>
<update id="update" parameterType="cn.bugstack.infrastructure.persistent.po.A">
UPDATE table SET a = #{a} WHERE b = #{b}
</update>
<select id="queryEmployeeByEmployNumber" parameterType="java.lang.String" resultMap="CaseMap">
SELECT a, b, c
FROM table
WHERE a = #{a}
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.bugstack.infrastructure.persistent.dao.IUserOrderDao">
<resultMap id="dataMap" type="cn.bugstack.infrastructure.persistent.po.UserOrderPO">
<id column="id" property="id"/>
<result column="user_name" property="userName"/>
<result column="user_id" property="userId"/>
<result column="user_mobile" property="userMobile"/>
<result column="sku" property="sku"/>
<result column="sku_name" property="skuName"/>
<result column="order_id" property="orderId"/>
<result column="quantity" property="quantity"/>
<result column="unit_price" property="unitPrice"/>
<result column="discount_amount" property="discountAmount"/>
<result column="tax" property="tax"/>
<result column="total_amount" property="totalAmount"/>
<result column="order_date" property="orderDate"/>
<result column="order_status" property="orderStatus"/>
<result column="is_delete" property="isDelete"/>
<result column="uuid" property="uuid"/>
<result column="ipv4" property="ipv4"/>
<result column="ipv6" property="ipv6"/>
<result column="ext_data" property="extData"/>
<result column="update_time" property="updateTime"/>
</resultMap>
<select id="insert" parameterType="cn.bugstack.infrastructure.persistent.po.UserOrderPO">
INSERT INTO user_order (user_name, user_id, user_mobile, sku, sku_name,
order_id, quantity, unit_price, discount_amount, tax,
total_amount, order_date, order_status, is_delete, uuid,
ipv4, ipv6, ext_data, update_time, create_time)
VALUES (#{userName}, #{userId}, #{userMobile}, #{sku}, #{skuName},
#{orderId}, #{quantity}, #{unitPrice}, #{discountAmount}, #{tax},
#{totalAmount}, #{orderDate}, #{orderStatus}, #{isDelete}, #{uuid},
INET_ATON(#{ipv4}), INET6_ATON(#{ipv6}), #{extData}, now(), now())
</select>
<update id="updateOrderStatusByUserId" parameterType="java.lang.String">
UPDATE user_order SET order_status = 1 WHERE user_id = #{userId}
</update>
<select id="selectByUserId" parameterType="java.lang.String" resultMap="dataMap">
SELECT id, user_name, user_id, user_mobile, sku, sku_name,
order_id, quantity, unit_price, discount_amount, tax,
total_amount, order_date, order_status, is_delete, uuid,
ipv4, ipv6, ext_data, update_time, create_time
FROM user_order
WHERE user_id = #{userId}
</select>
</mapper>
# https://shardingsphere.apache.org/index_zh.html
mode:
# 运行模式类型。可选配置:内存模式 Memory、单机模式 Standalone、集群模式 Cluster - 目前为单机模式
type: Standalone
dataSources:
ds_0:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://127.0.0.1:13306/xfg_dev_tech_db_00?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC&useSSL=true
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 15
minPoolSize: 5
ds_1:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://127.0.0.1:13306/xfg_dev_tech_db_01?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC&useSSL=true
username: root
password: 123456
connectionTimeoutMilliseconds: 30000
idleTimeoutMilliseconds: 60000
maxLifetimeMilliseconds: 1800000
maxPoolSize: 15
minPoolSize: 5
rules:
- !SHARDING
# 库的路由
defaultDatabaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: database_inline
# 表的路由
tables:
user_order:
actualDataNodes: ds_$->{0..1}.user_order_$->{0..3}
tableStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: user_order_inline
# 路由算法
shardingAlgorithms:
# 库-路由算法 2是两个库,库的数量。库的数量用哈希模2来计算。
database_inline:
type: INLINE
props:
algorithm-expression: ds_$->{Math.abs(user_id.hashCode()) % 2}
# 表-路由算法 4是一个库里,表的数量。4 - 1 为了获得 011 这样的二进制值。不推荐 user_order_$->{Math.abs(user_id.hashCode()) % 2} 作为表的路由
user_order_inline:
type: INLINE
props:
algorithm-expression: user_order_$->{(user_id.hashCode() ^ (user_id.hashCode()) >>> 16) & (4 - 1)}
props:
# 是否在日志中打印 SQL。
# 打印 SQL 可以帮助开发者快速定位系统问题。日志内容包含:逻辑 SQL,真实 SQL 和 SQL 解析结果。
# 如果开启配置,日志将使用 Topic ShardingSphere-SQL,日志级别是 INFO。 false
sql-show: true
# 是否在日志中打印简单风格的 SQL。false
sql-simple: true
# 用于设置任务处理线程池的大小。每个 ShardingSphereDataSource 使用一个独立的线程池,同一个 JVM 的不同数据源不共享线程池。
executor-size: 20
# 查询请求在每个数据库实例中所能使用的最大连接数。1
max-connections-size-per-query: 1
# 在程序启动和更新时,是否检查分片元数据的结构一致性。
check-table-metadata-enabled: false
# 在程序启动和更新时,是否检查重复表。false
check-duplicate-table-enabled: false
\ No newline at end of file
package cn.bugstack.test.infrastructure.persistent;
import cn.bugstack.infrastructure.persistent.dao.IUserOrderDao;
import cn.bugstack.infrastructure.persistent.po.UserOrderPO;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.UUID;
/**
* 单元测试
* @author Fuzhengwei bugstack.cn @小傅哥
*/
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserOrderTest {
@Resource
private IUserOrderDao userOrderDao;
@Test
public void test_selectByUserId() {
List<UserOrderPO> list = userOrderDao.selectByUserId("xfg_FOawiP");
log.info("测试结果:{}", JSON.toJSONString(list));
}
@Test
public void test_insert() {
for (int i = 0; i < 10; i++) {
UserOrderPO userOrderPO = UserOrderPO.builder()
.userName("小傅哥")
.userId("xfg_" + RandomStringUtils.randomAlphabetic(6))
.userMobile("+86 13521408***")
.sku("13811216")
.skuName("《手写MyBatis:渐进式源码实践》")
.orderId(RandomStringUtils.randomNumeric(11))
.quantity(1)
.unitPrice(BigDecimal.valueOf(128))
.discountAmount(BigDecimal.valueOf(50))
.tax(BigDecimal.ZERO)
.totalAmount(BigDecimal.valueOf(78))
.orderDate(new Date())
.orderStatus(0)
.isDelete(0)
.uuid(UUID.randomUUID().toString().replace("-", ""))
.ipv4("127.0.0.1")
.ipv6("2001:0db8:85a3:0000:0000:8a2e:0370:7334".getBytes())
.extData("{\"device\": {\"machine\": \"IPhone 14 Pro\", \"location\": \"shanghai\"}}")
.build();
userOrderDao.insert(userOrderPO);
}
}
/**
* 路由测试
*/
@Test
public void test_idx() {
for (int i = 0; i < 50; i++) {
String user_id = "xfg_" + RandomStringUtils.randomAlphabetic(6);
log.info("测试结果 {}", (user_id.hashCode() ^ (user_id.hashCode()) >>> 16) & 3);
}
}
}
package cn.bugstack.infrastructure.persistent.dao;
import cn.bugstack.infrastructure.persistent.po.UserOrderPO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface IUserOrderDao {
void insert(UserOrderPO userOrderPO);
void updateOrderStatusByUserId(String userId);
List<UserOrderPO> selectByUserId(String userId);
}
package cn.bugstack.infrastructure.persistent.po;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.util.Date;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserOrderPO {
/** 自增ID */
private Long id;
/** 用户姓名 */
private String userName;
/** 用户编号 */
private String userId;
/** 用户电话 */
private String userMobile;
/** 商品编号 */
private String sku;
/** 商品名称 */
private String skuName;
/** 订单ID */
private String orderId;
/** 商品数量 */
private int quantity;
/** 商品价格 */
private BigDecimal unitPrice;
/** 折扣金额 */
private BigDecimal discountAmount;
/** 费率金额 */
private BigDecimal tax;
/** 支付金额 */
private BigDecimal totalAmount;
/** 订单日期 */
private Date orderDate;
/** 订单状态 */
private int orderStatus;
/** 逻辑删单 */
private int isDelete;
/** 唯一索引 */
private String uuid;
/** 设备地址 */
private String ipv4;
/** 设备地址 */
private byte[] ipv6;
/** 扩展数据 */
private String extData;
/** 更新时间 */
private Date updateTime;
/** 创建时间 */
private Date createTime;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册