SpringCloud Hoxton.RELEASE
SpringCloud alibaba 2.2.0.RELEASE
SpringBoot 2.2.2.RELEASE
pom文件:父pom
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
<junit.version>4.12junit.version>
<log4j.version>1.2.17log4j.version>
<lombok.version>1.16.18lombok.version>
<mysql.version>5.1.47mysql.version>
<druid.version>1.1.16druid.version>
<mybatis.spring.boot.version>1.3.0mybatis.spring.boot.version>
<spring-nacos.version>2.2.1.RELEASEspring-nacos.version>
<mybatis-plus.version>3.0.3mybatis-plus.version>
<mybatis-starter.version>1.0.5mybatis-starter.version>
<sharding.jdbc.starter.version>4.1.1sharding.jdbc.starter.version>
<sharding.jdbc.at.version>4.1.1sharding.jdbc.at.version>
<fastjson.version>1.2.69fastjson.version>
<spring-cloud.version>Hoxton.RELEASEspring-cloud.version>
<seata.starter.version>1.4.2seata.starter.version>
properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>2.2.2.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>Hoxton.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-dependenciesartifactId>
<version>2.2.0.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>${mysql.version}version>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
<version>${spring-nacos.version}version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>${druid.version}version>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>${mybatis.spring.boot.version}version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatisplus-spring-boot-starterartifactId>
<version>${mybatis-starter.version}version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>${mybatis-plus.version}version>
dependency>
<dependency>
<groupId>org.apache.shardingspheregroupId>
<artifactId>sharding-jdbc-spring-boot-starterartifactId>
<version>${sharding.jdbc.starter.version}version>
dependency>
<dependency>
<groupId>org.apache.shardingspheregroupId>
<artifactId>sharding-transaction-base-seata-atartifactId>
<version>${sharding.jdbc.at.version}version>
dependency>
<dependency>
<groupId>io.seatagroupId>
<artifactId>seata-spring-boot-starterartifactId>
<version>${seata.starter.version}version>
dependency>
dependencies>
dependencyManagement>
子pom
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<scope>providedscope>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-seataartifactId>
<exclusions>
<exclusion>
<groupId>io.seatagroupId>
<artifactId>seata-spring-boot-starterartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>io.seatagroupId>
<artifactId>seata-spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.apache.shardingspheregroupId>
<artifactId>sharding-transaction-base-seata-atartifactId>
dependency>
dependencies>
seata-serverseata官方文档:https://seata.io/zh-cn/docs/overview/what-is-seata.html,可以去看看
seate-serverhttps://github.com/seata/seata/releases
总是打不开…我下载的版本是seata-server.1.4.2
下载完成后解压,conf目录下修改一下配置文件file.conf,mode改为db,并且将对应的数据库连接以及用户密码修改
store {
mode = "db"
publicKey = ""
file {
## ...省略
}
## database store property
db {
datasource = "druid"
dbType = "mysql"
driverClassName = "com.mysql.jdbc.Driver"
## 改成你自己的
url = "jdbc:mysql://127.0.0.1:3306/seata?rewriteBatchedStatements=true"
user = "root"
password = "xxxx"
## ...省略
}
## redis store property
redis {
## ...省略
}
}
然后再修改conf目录下的register.conf配置文件

我用的注册中心是nacos,你改成你相应的即可
然后启动seata-server,可以到nacos控制台看下是否注册成功
如果你没有seata数据库,则需要创建,并且创建相应的表,在git里是有脚本的,但是我打不开,索性先把我本地的贴到这里把,能打开的可以参考这里:https://seata.io/zh-cn/docs/ops/deploy-ha.html
CREATE TABLE `branch_table` (
`branch_id` bigint(20) NOT NULL,
`xid` varchar(128) NOT NULL,
`transaction_id` bigint(20) DEFAULT NULL,
`resource_group_id` varchar(32) DEFAULT NULL,
`resource_id` varchar(256) DEFAULT NULL,
`branch_type` varchar(8) DEFAULT NULL,
`status` tinyint(4) DEFAULT NULL,
`client_id` varchar(64) DEFAULT NULL,
`application_data` varchar(2000) DEFAULT NULL,
`gmt_create` datetime(6) DEFAULT NULL,
`gmt_modified` datetime(6) DEFAULT NULL,
PRIMARY KEY (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `distributed_lock` (
`lock_key` char(20) NOT NULL,
`lock_value` varchar(20) NOT NULL,
`expire` bigint(20) DEFAULT NULL,
PRIMARY KEY (`lock_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `global_table` (
`xid` varchar(128) NOT NULL,
`transaction_id` bigint(20) DEFAULT NULL,
`status` tinyint(4) NOT NULL,
`application_id` varchar(32) DEFAULT NULL,
`transaction_service_group` varchar(32) DEFAULT NULL,
`transaction_name` varchar(128) DEFAULT NULL,
`timeout` int(11) DEFAULT NULL,
`begin_time` bigint(20) DEFAULT NULL,
`application_data` varchar(2000) DEFAULT NULL,
`gmt_create` datetime DEFAULT NULL,
`gmt_modified` datetime DEFAULT NULL,
PRIMARY KEY (`xid`),
KEY `idx_gmt_modified_status` (`gmt_modified`,`status`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `lock_table` (
`row_key` varchar(128) NOT NULL,
`xid` varchar(128) DEFAULT NULL,
`transaction_id` bigint(20) DEFAULT NULL,
`branch_id` bigint(20) NOT NULL,
`resource_id` varchar(256) DEFAULT NULL,
`table_name` varchar(32) DEFAULT NULL,
`pk` varchar(36) DEFAULT NULL,
`gmt_create` datetime DEFAULT NULL,
`gmt_modified` datetime DEFAULT NULL,
PRIMARY KEY (`row_key`),
KEY `idx_branch_id` (`branch_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
seata的服务的resources文件夹下添加eata.conf配置文件在项目的resources文件夹下添加seata.conf配置文件,当然也有其他方式,我用yml+seata.conf的方式,内容如下
client {
application.id = shop-account-service
transaction.service.group = shop-account-service-group
}
## 两种方式执行
## 1.yml配置文件+seata.conf执行
## 2.registry.conf+seata.conf执行
yml seata配置seata:
client:
undo:
log-serialization: fastjson
#config:
#type: nacos
#nacos:
#group: SEATA_GROUP
#server-addr: 127.0.0.1:8848
registry:
type: nacos
nacos:
application: seata-server
server-addr: 127.0.0.1:8848
group: SEATA_GROUP
namespace: public
enabled: true # 开启自动装配
tx-service-group: shop-account-service-group # 事务组, 直接设置为项目名即可
enable-auto-data-source-proxy: true
service: # 如果配置中心用nacos, 可以将该配置写到nacos config中
vgroup-mapping:
shop-account-service-group: default
如果你采用了nacos作为配置中心,则可以将配置放到nacos里,如何操作这里就不讲了
sharding-jdbc配置spring:
application:
name: shop-account-service
main:
allow-bean-definition-overriding: true
shardingsphere:
datasource:
names: ds0, ds1, ds2, ds3, ds-common
ds0:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/overseas_shop_account_0?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&useSSL=false
username: root
password: root
ds1:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/overseas_shop_account_1?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&useSSL=false
username: root
password: root
ds2:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/overseas_shop_account_2?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&useSSL=false
username: root
password: root
ds3:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/overseas_shop_account_3?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&useSSL=false
username: root
password: root
ds-common:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/overseas_shop_common?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&useSSL=false
username: root
password: root
sharding:
# 默认分库策略
default-database-strategy:
inline:
algorithm-expression: ds$->{user_id % 4}
sharding-column: user_id
# 分表策略
tables:
t_user:
actual-data-nodes: ds$->{0..3}.t_user
table-strategy:
inline:
sharding-column: user_id
algorithm-expression: t_user
t_login_name_id_map:
actual-data-nodes: ds-common.t_login_name_id_map
table-strategy:
inline:
sharding-column: login_name
algorithm-expression: t_login_name_id_map
database-strategy:
inline:
sharding-column: login_name
algorithm-expression: ds-common
t_user_id_name_map:
actual-data-nodes: ds-common.t_user_id_name_map
table-strategy:
inline:
sharding-column: user_id
algorithm-expression: t_user_id_name_map
database-strategy:
inline:
sharding-column: user_id
algorithm-expression: ds-common
seata的服务对应的数据库创建undolog表需要注意的是在每个库都要创建,分库了,就需要在各个分库创建
CREATE TABLE `undo_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`branch_id` bigint(20) NOT NULL,
`xid` varchar(100) NOT NULL,
`context` varchar(128) NOT NULL,
`rollback_info` longblob NOT NULL,
`log_status` int(11) NOT NULL,
`log_created` datetime NOT NULL,
`log_modified` datetime NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
@ShardingTransactionType(TransactionType.BASE)
@Transactional
public UserPO buildAndSaveUseAndMappings(long userId, AccountReqDTO reqDTO) {
log.info("【 构建用户即userId与username映射, 落库... 】");
UserPO userPO = new UserPO();
userPO.setUserId(userId);
this.save(userPO); // account库
// seata测试
System.out.println(1 / 0);
LoginNameIdMapPO loginNameIdMapDO = new LoginNameIdMapPO();
String loginName = reqDTO.getLoginName();
loginNameIdMapDO.setLoginName(loginName);
loginNameIdMapDO.setUserId(userId);
loginNameIdMapService.save(loginNameIdMapDO); // common库
UserIdNameMapPO userIdNameMapPO = new UserIdNameMapPO();
userIdNameMapPO.setLoginName(loginName);
userIdNameMapPO.setUserId(userId);
userIdNameMapService.save(userIdNameMapPO); // common库
return userPO;
}
下面内容请仔细观看
PS:可以看上面代码一个方法操作了多个数据库,其中account库分了四个库,另外还涉及到了一个common库,所以可以确定是分布式事务,或者微服务之间的调用产生的分布式事务,需要注意的是,单用seata时,我们只需要在存在分布式事务的地方加@GlobalTransactional注解就可以了,但是引入shardingjdbc后,有两点需要注意:
@ShardingTransactionType和@Transactional注解,必须同时使用TransactionType.BASE是不生效的,需要在方法执行前,调用TransactionTypeHolder.set(TransactionType.BASE);你可以在方法最开始加上这行代码,也可以写aop,都行我是用的aop的方式,可以参考下:
@Component
@Aspect
@Order(-1) // 如果一个方法被多个aop增强, 可以用@Order来控制增强顺序
public class ShardingTransactionAspect {
private final static Logger LOGGER = LoggerFactory.getLogger(ShardingTransactionAspect.class);
// 切点, 执行增强代码的地方
@Pointcut("@annotation(org.apache.shardingsphere.transaction.annotation.ShardingTransactionType)")
public void pointCut() {
}
//@Before 标识一个前置增强方法, 方法内部的增强代码叫做Advice切面或通知
@Before("pointCut()")
public void doBefore(JoinPoint point) {
ShardingTransactionType ShardingTransaction = point.getTarget().getClass().getAnnotation(ShardingTransactionType.class);
if (ShardingTransaction == null) {
//注解在类上
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
ShardingTransaction = method.getAnnotation(ShardingTransactionType.class);
}
TransactionTypeHolder.set(ShardingTransaction.value());
LOGGER.info("选择Sharding分布式事务---" + ShardingTransaction.value().toString());
}
// @After 标识一个后置增强方法, 方法内部的增强代码叫做Advice切面或通知
@After("pointCut()")
public void doAfter() {
TransactionTypeHolder.clear();
}
}
执行后可以看到如下日志

然后可以去检查数据库,也可以去查看undolog表的自增值和修改时间,确定是否生效

能力有限,不足之处希望有大佬指正~