分布式事务
如何使用
第一步
首次访问: https://seata.apache.org/unversioned/download/seata-server
下载我们需要使用的 seata1.5.2 服务
第二步
- 将 undo_log 表添加到参与全局事务的数据库中(TCC、SAGA、XA 可以跳过此步骤)
-- for AT mode you must to init this sql for you business database. the seata server not need it.
CREATE TABLE IF NOT EXISTS `undo_log`
(
`branch_id` BIGINT(20) NOT NULL COMMENT 'branch transaction id',
`xid` VARCHAR(100) NOT NULL COMMENT 'global transaction id',
`context` VARCHAR(128) NOT NULL COMMENT 'undo_log context, such as serialization',
`rollback_info` LONGBLOB NOT NULL COMMENT 'rollback info',
`log_status` INT(11) NOT NULL COMMENT '0: normal status,1: defense status',
`log_created` DATETIME(6) NOT NULL COMMENT 'create datetime',
`log_modified` DATETIME(6) NOT NULL COMMENT 'modify datetime',
UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8 COMMENT = 'AT transaction mode undo table';
- 在您的 mysql 数据库中创建一个名为 seata 的库,并使用以下 sql
-- -------------------------------- The script used when storeMode is 'db' ------- -------------------------
-- the table to store GlobalSession data
CREATE TABLE IF NOT EXISTS `global_table`
(
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`status` TINYINT NOT NULL,
`application_id` VARCHAR(32),
`transaction_service_group` VARCHAR(32),
`transaction_name` VARCHAR(128),
`timeout` INT,
`begin_time` BIGINT,
`application_data` VARCHAR(2000),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`xid`),
KEY `idx_gmt_modified_status` (`gmt_modified`, `status`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
`branch_id` BIGINT NOT NULL,
`xid` VARCHAR(128) NOT NULL,
`transaction_id` BIGINT,
`resource_group_id` VARCHAR(32),
`resource_id` VARCHAR(256),
`branch_type` VARCHAR(8),
`status` TINYINT,
`client_id` VARCHAR(64),
`application_data` VARCHAR(2000),
`gmt_create` DATETIME(6),
`gmt_modified` DATETIME(6),
PRIMARY KEY (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
`row_key` VARCHAR(128) NOT NULL,
`xid` VARCHAR(96),
`transaction_id` BIGINT,
`branch_id` BIGINT NOT NULL,
`resource_id` VARCHAR(256),
`table_name` VARCHAR(32),
`pk` VARCHAR(36),
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`row_key`),
KEY `idx_branch_id` (`branch_id`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8;
第三步
将 seata 依赖项引入您的项目
spring-boot 应用程序
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.5.2</version>
</dependency>
spring 应用程序
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-all</artifactId>
<version>1.5.2</version>
</dependency>
第四步
spring-boot 应用程序
参考 seata/script/client/spring at develop seata/seata (github.com)
将其添加到您的项目的 application.yml 中。
seata:
enabled: true
application-id: applicationName
tx-service-group: my_test_tx_group
enable-auto-data-source-proxy: true #Only AT and XA modes need to be true, and the data source will be automatically proxied after opening
data-source-proxy-mode: AT #Optional AT&XA
config:
type: nacos
nacos:
#namespace: If the configuration is created in a non-default namespace, please fill in the id of the namespace here
serverAddr: 127.0.0.1:8848
group: SEATA_GROUP
username: "nacos"
password: "nacos"
data-id: seata.properties
registry:
type: nacos
nacos:
application: seata-server
server-addr: 127.0.0.1:8848
group: SEATA_GROUP
#namespace: If the configuration is created in a non-default namespace, please fill in the id of the namespace here
username: "nacos"
password: "nacos"
spring 应用程序
添加 seata/script/client/conf at develop · seata/seata (github.com) 在 registry.conf 下,因为高可用性部署使用第三方配置中心,所以不需要 file.conf
registry {
# file, nacos, eureka, redis, zk, consul, etcd3, sofa, custom
type = "nacos"
nacos {
application = "seata-server"
serverAddr = "127.0.0.1:8848"
group = "SEATA_GROUP"
namespace = ""
username = ""
password = ""
##if use MSE Nacos with auth, mutex with username/password attribute
#accessKey = ""
#secretKey = ""
##if use Nacos naming meta-data for SLB service registry, specify nacos address pattern rules here
#slbPattern = ""
}
}
config {
# file, nacos, apollo, zk, consul, etcd3, springCloudConfig, custom
type = "nacos"
nacos {
serverAddr = "127.0.0.1:8848"
namespace = ""
group = "SEATA_GROUP"
username = ""
password = ""
##if use MSE Nacos with auth, mutex with username/password attribute
#accessKey = ""
#secretKey = ""
dataId = "seata.properties"
}
}
第五步
运行您下载的 nacos,并参考 https://github.com/seata/seata/tree/develop/script/config-center 并修改 config.txt
#Only used by client
#The transaction group is called my_test_tx_group and the corresponding seata-server cluster is default
service.vgroupMapping.my_test_tx_group=default
#The following are only used by server
store.mode=db
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true
store.db.user=username
store.db.password=password
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000
打开 nacos 控制台,创建一个数据Id 为 seata.properties 的配置,在对应的命名空间下,填写 group 为 SEATA_GROUP,填写上面的内容,选择类型为 properties 保存
第六步
更改服务器中的 application.yml
server:
port: 7091
spring:
application:
name: seata-server
record:
config: classpath:logback-spring.xml
file:
path: ${user.home}/logs/seata
console:
user:
username: seata
password: seata
seata:
config:
# support: nacos, consul, apollo, zk, etcd3
type: nacos
nacos:
server-addr: 127.0.0.1:8848
#namespace: If the configuration is created in a non-default namespace, please fill in the id of the namespace here
group: SEATA_GROUP
username:
password:
##if use MSE Nacos with auth, mutex with username/password attribute
#access-key: ""
#secret-key: ""
data-id: seata.properties
registry:
# support: nacos, eureka, redis, zk, consul, etcd3, sofa
type: nacos
nacos:
application: seata-server
server-addr: 127.0.0.1:8848
group: SEATA_GROUP
namespace:
cluster: default
#namespace: If the configuration is created in a non-default namespace, please fill in the id of the namespace here
password:
##if use MSE Nacos with auth, mutex with username/password attribute
#access-key: ""
#secret-key: ""
# server:
# service-port: 8091 #If not configured, the default is '${server.port} + 1000'
security:
secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
tokenValidityInMilliseconds: 1800000
ignore:
urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*. png, /**/*.ico, /console-fe/public/**, /api/v1/auth/login
第七步
以下是一个在全局事务调用者(启动全局事务的服务)的接口中添加 @GlobalTransactional 的示例
@GetMapping(value = "testCommit")
@GlobalTransactional
public Object testCommit(@RequestParam(name = "id",defaultValue = "1") Integer id,
@RequestParam(name = "sum", defaultValue = "1") Integer sum) {
Boolean ok = productService. reduceStock(id, sum);
if (ok) {
LocalDateTime now = LocalDateTime.now();
Orders orders = new Orders();
orders.setCreateTime(now);
orders.setProductId(id);
orders. setReplaceTime(now);
orders. setSum(sum);
orderService. save(orders);
return "ok";
} else {
return "fail";
}
}
Spring 应用程序在使用 AT 或 XA 模式时,需要手动代理数据源以选择事务模式并初始化事务扫描器
@Primary
@Bean("dataSource")
public DataSource dataSource(DataSource druidDataSource) {
//AT agent choose one of the two
return new DataSourceProxy(druidDataSource);
//XA Proxy
return new DataSourceProxyXA(druidDataSource)
}
@Bean
public GlobalTransactionScanner globalTransactionScanner() {
return new GlobalTransactionScanner("application name", "my_test_tx_group");
}
如果您使用 tcc 模式,则需要在相应提供者的 serviceimpl 中额外定义两阶段 try 和 confirm(commit) cancel(rollback)
spring-boot 应用程序需要关闭数据源代理
seata:
enable-auto-data-source-proxy: false
/**
* Define two-phase commit name = the bean name of the tcc, globally unique commitMethod = commit is the two-phase confirmation method rollbackMethod = rollback is the two-phase cancellation method
* useTCCFence=true is to enable anti-hanging
* BusinessActionContextParameter annotation to pass parameters to the second stage
*
* @param params - input parameters
* @return String
*/
@TwoPhaseBusinessAction(name = "beanName", commitMethod = "commit", rollbackMethod = "rollback", useTCCFence = true)
public void insert(@BusinessActionContextParameter(paramName = "params") Map<String, String> params) {
logger.info("You can reserve resources here, or use the characteristics of tcc to mix with AT. In the second stage, use the messages stored here in the first stage and send them out through the second stage, such as redis, mq and other operations");
}
/**
* The confirmation method can be named otherwise, but it must be consistent with the commitMethod. The context can pass the parameters of the try method
*
* @param context context
* @return boolean
*/
public void commit(BusinessActionContext context) {
logger.info("Reserved resources are actually processed, or send mq messages and redis storage");
}
/**
* Two-stage cancellation method
*
* @param context context
* @return boolean
*/
public void rollback(BusinessActionContext context) {
logger.info("Release reserved resources, or clear the message cache sent when the first phase is ready to be submitted by the second phase");
}
linux/macos
cd bin
sh seata-server.sh
windows
cd bin
./seata-server.bat
运行 seata-server,成功后,运行您自己的服务 dubbo provider&consumer
第八步是构建高可用的 Seata-server
由于 seata-server 支持计算和存储分离模式,并支持将服务地址暴露给多个注册中心,因此只需要按照第六步配置,然后进行水平扩展即可
详情请访问: https://seata.io/