版本:
SpringCloudAlibaba2021.0.5
Seata1.6.1
Sharding4.1.1
其余SpringCloudAlibaba的版本选择看这里:
https://sca.aliyun.com/zh-cn/docs/2021.0.5.0/overview/version-explain
SpringCloudAlibaba脚手架看这里:
具体的理论概念可以去Shardingsphere先过一遍https://shardingsphere.apache.org/document/current/cn/overview/
依赖:
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-spring-boot-starter</artifactId>
<version>4.1.1</version>
</dependency>
<!-- 使用BASE事务时,需要引入此模块 -->
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-transaction-base-seata-at</artifactId>
<version>4.1.1</version>
</dependency>
加入依赖后必须要在resources下加入seata.conf文件,里面的配置如下:
client {
## 应用唯一id
application.id=order-service
## 所属事务组
transaction.service.group=sharding_tx_group
}
application.yml配置:
spring:
#sharding
shardingsphere:
datasource:
names: m1,m2 #指定多个虚拟数据库名称
m1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/seata-order?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true&useInformationSchema=false
username: admin
password: admin
m2:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/seata-order-slave?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true&useInformationSchema=false
username: admin
password: admin
#分库分表配置
sharding:
tables:
b_order: #指定一个虚拟表名称
actual-data-nodes: m$->{1..2}.b_order_$->{1..2} #数据库.表名
key-generator: #主键自动生成策略
column: id
type: SNOWFLAKE #使用雪花ID
table-strategy: #分表策略
inline: #inline策略
sharding-column: id #分表字段
algorithm-expression: b_order_$->{id % 2 + 1} #分表算法,求模取余算法
database-strategy: #分库策略
inline: #inline策略
sharding-column: product_id #分库字段
algorithm-expression: m$->{product_id % 2 + 1} #分库算法,求模取余算法
props:
sql:
show: true
#seata配置
seata:
enabled: true
application-id: ccxi-order
tx-service-group: sharding_tx_group
service:
vgroup-mapping:
sharding_tx_group: default
registry:
type: nacos
nacos:
server-addr: 127.0.0.1:8848
namespace: public
group: SEATA_GROUP
application: seata-server
username: nacos #未开启nacos鉴权不用账号密码
password: nacos
使用时只需要在调用方的方法上加上两个注解就阔以了,以下是我的demo示例:
//A服务加上以上注解,seata的全局事务注解就不用加了,因为已经与Shrding集成了
@Transactional
@ShardingTransactionType(TransactionType.BASE) // 支持TransactionType.LOCAL, TransactionType.XA, TransactionType.BASE
public List<BOrder> submitOrder3(List<BOrder> order) {
saveBatch(order);
//这里发起调用B服务,B服务方法上不必加事务注解也会一起回滚
//不过本人建议最好在B方法上加seata的@GlobalTransactional全局事务注解
//这样B服务方法单独运行时会生成一个全局事务,多服务联调时则会以发起方事务为准。
String s = productFeignService.productInfo(order.get(0).getProductId());
return order;
}
场景描述:
SpringCloudAlibaba+Seata整合Shardingsphere分库分表,新建了两个测试库,
seata-order和seata-order-slave做分库分表。这两个库的表结构都是一样的,表分别是
b_order_1
b_order_2
undo_log(这张表是seata里面的,分库分表如果要实现分布式事务必须将这张表在每个库中生成,用于后续全局事务回滚)
在我把环境都搭建好之后,通过A服务调用B服务,A服务中有分库分表的操作,B服务没有。
我在B服务中抛出了一个自定义异常,正常来说异常抛出后A服务中分库分表插入的数据都应该要回滚,但现实却和我预想的不一致。
实际情况:
1.seata-order和seata-order-slave两个库的数据都正常回滚
2.要么seata-order回滚成功,要么seata-order-slave回滚成功(后续我通过查看日志发现,决定哪个库能回滚成功取决与Shardingsphere分库的最后一条语句走的是哪个数据库)
通过第二点可以看出,seata回滚的语句在被Shardingsphere处理后,数据源不是正常的库,所以导致本该回滚seata-order的语句被分配到了seata-order-slave中处理,那么回滚就会出现混乱。
如果有朋友出现了这种问题,不要急不要慌,只需要在上面application.yml的配置中加上一行配置就搞定
配置如下:
default-data-source-name: m1
给sharding指定一个默认数据库就好啦!这样sharding就不会找不到数据源了,保你次次回滚成功。
今天的坑就分享到这了,祝各位好运!散会