本文最后更新于:2025年5月30日 下午
Sharding-jdbc4.1.1 + Seata1.6.1
官方文档:https://shardingsphere.apache.org/document/4.1.1/cn/manual/sharding-jdbc/usage/sharding/#使用spring
核心依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 <dependencies > <dependency > <groupId > com.alibaba.cloud</groupId > <artifactId > spring-cloud-starter-alibaba-nacos-discovery</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-openfeign</artifactId > </dependency > <dependency > <groupId > com.github.xiaoymin</groupId > <artifactId > knife4j-openapi2-spring-boot-starter</artifactId > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-loadbalancer</artifactId > </dependency > <dependency > <groupId > com.alibaba.cloud</groupId > <artifactId > spring-cloud-starter-alibaba-sentinel</artifactId > </dependency > <dependency > <groupId > com.alibaba.cloud</groupId > <artifactId > spring-cloud-starter-alibaba-nacos-config</artifactId > </dependency > <dependency > <groupId > com.alibaba.cloud</groupId > <artifactId > spring-cloud-starter-alibaba-seata</artifactId > <exclusions > <exclusion > <groupId > org.antlr</groupId > <artifactId > antlr4-runtime</artifactId > </exclusion > </exclusions > </dependency > <dependency > <groupId > org.springframework.cloud</groupId > <artifactId > spring-cloud-starter-bootstrap</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.projectlombok</groupId > <artifactId > lombok</artifactId > </dependency > <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-typehandlers-jsr310</artifactId > <version > 1.0.2</version > </dependency > <dependency > <groupId > com.baomidou</groupId > <artifactId > mybatis-plus-boot-starter</artifactId > <version > 3.5.3.1</version > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-aop</artifactId > </dependency > <dependency > <groupId > com.squareup.okhttp3</groupId > <artifactId > okhttp</artifactId > </dependency > <dependency > <groupId > cn.hutool</groupId > <artifactId > hutool-all</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-data-redis</artifactId > </dependency > <dependency > <groupId > org.apache.commons</groupId > <artifactId > commons-pool2</artifactId > </dependency > <dependency > <groupId > org.redisson</groupId > <artifactId > redisson-spring-boot-starter</artifactId > <version > 3.45.1</version > <exclusions > <exclusion > <groupId > org.redisson</groupId > <artifactId > redisson-spring-data-34</artifactId > </exclusion > </exclusions > </dependency > <dependency > <groupId > org.redisson</groupId > <artifactId > redisson-spring-data-27</artifactId > <version > 3.45.1</version > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-amqp</artifactId > </dependency > <dependency > <groupId > com.fasterxml.jackson.core</groupId > <artifactId > jackson-databind</artifactId > </dependency > <dependency > <groupId > org.apache.shardingsphere</groupId > <artifactId > sharding-jdbc-spring-boot-starter</artifactId > <version > 4.1.1</version > </dependency > <dependency > <groupId > org.apache.shardingsphere</groupId > <artifactId > sharding-transaction-base-seata-at</artifactId > <version > 4.1.1</version > </dependency > </dependencies >
application.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 server: port: 10040 spring: application: name: business-service redis: redisson: file: classpath:redisson.yaml host: localhost port: 6379 timeout: 10000 database: 0 lettuce: pool: max-idle: 8 max-active: 8 max-wait: 100ms min-idle: 0 enabled: true rabbitmq: host: localhost port: 5672 username: user password: 123 virtual-host: user listener: type: simple simple: prefetch: 1 acknowledge-mode: auto retry: enabled: true initial-interval: 1000ms multiplier: 1 max-attempts: 3 stateless: true cloud: nacos: config: group: SEATA_GROUP namespace: public discovery: server-addr: 127.0 .0 .1 :8848 namespace: public group: SEATA_GROUP seata: enabled: true application-id: seata-server tx-service-group: test-tx-group enable-auto-data-source-proxy: false data-source-proxy-mode: AT service: vgroup-mapping: test-tx-group: default grouplist: default: 127.0 .0 .1 :8091 feign: httpclient: enabled: false okhttp: enabled: true sentinel: enabled: false client: config: default: connectTimeout: 5000 readTimeout: 3000 loggerLevel: full test02: connectTimeout: 5000 readTimeout: 5000 loggerLevel: full mybatis-plus: type-aliases-package: com.business.domain mapper-locations: classpath:/mapper/*.xml configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl auto-mapping-behavior: full map-underscore-to-camel-case: true default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler global-config: db-config: id-type: assign_id logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0
使用
调用方
1 2 3 4 5 6 7 @GlobalTransactional(rollbackFor = Exception.class) @ShardingTransactionType(TransactionType.BASE) public void buyItem (OrderDTO orderDTO) { itemClient.update(orderDTO.getItemId(), orderDTO.getAmount()); }
被调用方
1 2 3 4 5 6 7 8 9 @Transactional(rollbackFor = Exception.class) @ShardingTransactionType(TransactionType.BASE) public void updateUserMoney (BigDecimal money, Long id) throws SQLException { int i = userMapper.updateMoney(money, id); if (i == 0 ){ throw new SQLException ("更新失败!" ); } }
注意事项:
枚举类异常问题
shardingsphere
与mybatisplus
一起使用时,对于枚举类可能会出现异常:InvalidDataAccessApiUsageException: Error attempting to get column 'status' from result set. Cause: java.sql.SQLFeatureNotSupportedException: getObject with type。
这主要是因为shardingsphere
与当前版本的mybatisplus
不兼容。
根据参考资料2,mybatisplus3.4.1虽然不会出现这个问题,但是这个版本查询出来的数据,对应的枚举类是null值,也是有问题,3.4.3以上没有这问题,但是又与shardingsphere冲突导致出现枚举类异常,而且mybatisplus官方说不做这个组件的兼容。所以需要自行处理。
方法一:不使用枚举类
既然是枚举类异常,那就不使用枚举类不就好了,这样倒是简单粗暴,但是并不是解决问题的好方法
方法二:自定义类型处理器方法
1、枚举类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package com.order.enums;import com.baomidou.mybatisplus.annotation.EnumValue;import com.fasterxml.jackson.annotation.JsonValue;import lombok.Getter;@Getter public enum OrderStatusEnums { WAITING_PAYMENT(0 , "待付款" ), PAID(1 , "已付款" ), WAITING_DELIVER(2 , "待发货" ), WAITING_RECEIVE(3 , "待收货" ), FINISHED(4 , "已完成" ), CANCELED(5 , "已取消" ); @EnumValue private final int code; @JsonValue private final String message; OrderStatusEnums(int code, String message) { this .code = code; this .message = message; } public static OrderStatusEnums fromDbCode (String dbCode) { for (OrderStatusEnums orderStatusEnums : values()) { if (orderStatusEnums.code == Integer.parseInt(dbCode) || orderStatusEnums.name().equals(dbCode)) { return orderStatusEnums; } } throw new IllegalArgumentException ("Unknown color code: " + dbCode); } }
2、枚举类处理方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 package com.order.enums.handler;import com.alibaba.druid.util.StringUtils;import com.order.enums.OrderStatusEnums;import org.apache.ibatis.type.BaseTypeHandler;import org.apache.ibatis.type.JdbcType;import org.apache.ibatis.type.MappedJdbcTypes;import org.apache.ibatis.type.MappedTypes;import org.springframework.stereotype.Component;import java.sql.CallableStatement;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;@Component @MappedTypes(OrderStatusEnums.class) @MappedJdbcTypes(value = JdbcType.INTEGER, includeNullJdbcType = true) public class OrderStatusEnumsTypeHandler extends BaseTypeHandler <OrderStatusEnums> { @Override public void setNonNullParameter (PreparedStatement ps, int i, OrderStatusEnums parameter, JdbcType jdbcType) throws SQLException { if (parameter != null ) { ps.setString(i, String.valueOf(parameter.getCode())); } } @Override public OrderStatusEnums getNullableResult (ResultSet rs, String columnName) throws SQLException { String code = rs.getString(columnName); if (StringUtils.isEmpty(code)) { return null ; } return OrderStatusEnums.fromDbCode(code); } @Override public OrderStatusEnums getNullableResult (ResultSet rs, int columnIndex) throws SQLException { String code = rs.getString(columnIndex); if (StringUtils.isEmpty(code)) { return null ; } return OrderStatusEnums.fromDbCode(code); } @Override public OrderStatusEnums getNullableResult (CallableStatement cs, int columnIndex) throws SQLException { String code = cs.getString(columnIndex); if (StringUtils.isEmpty(code)) { return null ; } return OrderStatusEnums.fromDbCode(code); } }
3、注册到mybatis
1 2 mybatis-plus: type-handlers-package: com.order.domain.enums.handler
4、指定需要处理的属性(可选)
若无法正常转换的话,指定一下试试,我试过的情况是,自定义的类型处理器只要被扫描到,就可以生效。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?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 ="com.order.mapper.OrderMapper" > <resultMap id ="BaseResultMap" type ="com.order.domain.Order" > <result property ="id" column ="id" jdbcType ="BIGINT" /> <result property ="userId" column ="userId" jdbcType ="BIGINT" /> <result property ="itemId" column ="itemId" jdbcType ="BIGINT" /> <result property ="amount" column ="amount" jdbcType ="INTEGER" /> <result property ="price" column ="price" jdbcType ="DECIMAL" /> <result property ="status" column ="status" jdbcType ="INTEGER" typeHandler ="com.order.enums.handler.OrderStatusEnumsTypeHandler" /> </resultMap > <sql id ="Base_Column_List" > <if test ="true" > id,user_id,item_id,amount,price,`status` </if > </sql > </mapper >
日期类异常
在搜索枚举类异常问题解决方法时,很多人都出现过日期时间类型也会报错的问题。同样也是缺少对应的处理器,可通过引入依赖解决日期相关问题。可参考参考资料3。
这个依赖中,包含了多种日期相关的类型处理器。
此依赖是直接加入到了mybatis的类型处理中,所以无需额外配置即可生效。
1 2 3 4 5 <dependency > <groupId > org.mybatis</groupId > <artifactId > mybatis-typehandlers-jsr310</artifactId > <version > 1.0.2</version > </dependency >
数据源不能为空异常
对于无需直接访问数据库的服务,作为入口分布式调用入口,会出现数据源不能为空的错误,所以需要在启动类中排除对应的自动装配,参考资料4。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @EnableFeignClients(basePackages = "com.business.feign", defaultConfiguration = DefaultFeignConfig.class) @EnableDiscoveryClient @SpringBootApplication(exclude={DataSourceAutoConfiguration.class, SpringBootConfiguration.class}) public class BusinessApplication { public static void main (String[] args) { SpringApplication.run(BusinessApplication.class, args); } }
参考资料:
Shardingsphere-jdbc整合Feign、Seata AT 模式实现分布式事务的解决方案
整合sharding jdbc查询时,枚举类型出错
sharding-jdbc 出现 java.sql.SQLFeatureNotSupportedException: getObject with type 异常处理
sharding-jdbc Data sources cannot be empty.