diff --git a/pom.xml b/pom.xml index 66d561096fe27ff9fec675b10fe7c9c06822beef..9707eeea2ed8f019978934710bd7bdde30cf6c51 100644 --- a/pom.xml +++ b/pom.xml @@ -121,6 +121,16 @@ redisson-spring-boot-starter 3.23.4 + + org.apache.shardingsphere + shardingsphere-jdbc-core + 5.4.1 + + + org.yaml + snakeyaml + 1.33 + diff --git a/xfg-frame-archetype-std-app/pom.xml b/xfg-frame-archetype-std-app/pom.xml index 4bf649afa6031f572c52025beaa77c94719fc94a..4cf6c37c1698e04c48cd2d29eb4feba6415e9f0f 100644 --- a/xfg-frame-archetype-std-app/pom.xml +++ b/xfg-frame-archetype-std-app/pom.xml @@ -78,7 +78,6 @@ converter-gson 2.9.0 - org.apache.dubbo dubbo @@ -95,6 +94,14 @@ org.redisson redisson-spring-boot-starter + + org.apache.shardingsphere + shardingsphere-jdbc-core + + + org.yaml + snakeyaml + @@ -151,5 +158,4 @@ - diff --git a/xfg-frame-archetype-std-app/src/main/resources/application-dev.yml b/xfg-frame-archetype-std-app/src/main/resources/application-dev.yml index 9abba08839ab102eac3df00be5294bc8932ee4f7..38f3d51fb461466e9c9e8277191024dd4ebf330a 100644 --- a/xfg-frame-archetype-std-app/src/main/resources/application-dev.yml +++ b/xfg-frame-archetype-std-app/src/main/resources/application-dev.yml @@ -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: diff --git a/xfg-frame-archetype-std-app/src/main/resources/mybatis/mapper/frame_case_mapper.xml b/xfg-frame-archetype-std-app/src/main/resources/mybatis/mapper/frame_case_mapper.xml deleted file mode 100644 index 7e2ed513346996e764d31fe0edd9774d780eb880..0000000000000000000000000000000000000000 --- a/xfg-frame-archetype-std-app/src/main/resources/mybatis/mapper/frame_case_mapper.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - INSERT INTO table(a,b,c) VALUES(#{a}, #{b}, #{c}) - - - - UPDATE table SET a = #{a} WHERE b = #{b} - - - - - diff --git a/xfg-frame-archetype-std-app/src/main/resources/mybatis/mapper/user_order_mapper.xml b/xfg-frame-archetype-std-app/src/main/resources/mybatis/mapper/user_order_mapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..0ad6aa718400f2a0af51c5fa6434c0169340d0a5 --- /dev/null +++ b/xfg-frame-archetype-std-app/src/main/resources/mybatis/mapper/user_order_mapper.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UPDATE user_order SET order_status = 1 WHERE user_id = #{userId} + + + + + diff --git a/xfg-frame-archetype-std-app/src/main/resources/sharding/sharding-jdbc-dev.yaml b/xfg-frame-archetype-std-app/src/main/resources/sharding/sharding-jdbc-dev.yaml new file mode 100644 index 0000000000000000000000000000000000000000..859a90eccc3bb86ec245bfec098c4e23b0467642 --- /dev/null +++ b/xfg-frame-archetype-std-app/src/main/resources/sharding/sharding-jdbc-dev.yaml @@ -0,0 +1,74 @@ +# 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 diff --git a/xfg-frame-archetype-std-app/src/test/java/cn/bugstack/test/infrastructure/persistent/UserOrderTest.java b/xfg-frame-archetype-std-app/src/test/java/cn/bugstack/test/infrastructure/persistent/UserOrderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..88f8c3488182d8d5d91c6d84fcd4cb93eb0d1f38 --- /dev/null +++ b/xfg-frame-archetype-std-app/src/test/java/cn/bugstack/test/infrastructure/persistent/UserOrderTest.java @@ -0,0 +1,76 @@ +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 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); + } + } + +} diff --git a/xfg-frame-archetype-std-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/dao/IUserOrderDao.java b/xfg-frame-archetype-std-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/dao/IUserOrderDao.java new file mode 100644 index 0000000000000000000000000000000000000000..c2fc16822da29cad880f0dcdcd36963dda519540 --- /dev/null +++ b/xfg-frame-archetype-std-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/dao/IUserOrderDao.java @@ -0,0 +1,17 @@ +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 selectByUserId(String userId); + +} diff --git a/xfg-frame-archetype-std-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/po/UserOrderPO.java b/xfg-frame-archetype-std-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/po/UserOrderPO.java new file mode 100644 index 0000000000000000000000000000000000000000..7b782aab40373a28e522479e666b7e8a31b867a3 --- /dev/null +++ b/xfg-frame-archetype-std-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/po/UserOrderPO.java @@ -0,0 +1,60 @@ +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; + +}