https://github.com/seata/seata-go是https://github.com/seata/seata的golang客户端,目前支持at和tcc两种分布式事务的实现。虽然官方的文档给的例子描述了如何处理分布式事务,但是如何部署和使用语焉不详。下面介绍下两种部署方式file、db
file模式是默认的模式性能最好,因为存在本地文件中,首先部署seata-server:
代码语言:javascript复制#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
version: '3'
services:
seata-server:
image: seataio/seata-server:1.5.2
ports:
- "8091:8091"
- "7091:7091"
environment:
- SEATA_PORT=8091
- STORE_MODE=file
zookeeper:
image: zookeeper
ports:
- "2181:2181"
restart: on-failure
mysql:
image: mysql:5.7
container_name: mysql
environment:
- MYSQL_ROOT_PASSWORD=12345678
command: --default-authentication-plugin=mysql_native_password --default-time-zone=' 08:00'
volumes:
- ./mysql:/docker-entrypoint-initdb.d
- ./mysql/mysqld.cnf:/etc/mysql/mysql.conf.d/mysqld.cnf
ports:
- "3306:3306"
代码语言:javascript复制docker compose -f seata-go/sample/dockercompose/docker-compose.yml up
然后运行我们的example
代码语言:javascript复制go run github.com/seata/seata-go/sample/at/basic
发现我们成功运行了
代码语言:javascript复制 127.0.0.1:3306)/seata_client, applicationData
2022-12-10 21:23:49.510 INFO getty/getty_remoting.go:79 send async message: {message.RpcMessage{ID:3, Type:0x1, Codec:0x1, Compressor:0x0, HeadMap:map[string]string(nil), Body:message.BranchCommitResponse{AbstractBranchEndResponse:message.AbstractBranchEndResponse{AbstractTransactionResponse:message.AbstractTransactionResponse{AbstractResultMessage:message.AbstractResultMessage{ResultCode:0x1, Msg:""}, TransactionErrorCode:0}, Xid:"172.20.0.3:8091:27358463220736003", BranchId:27358463220736004, BranchStatus:5}}}}
2022-12-10 21:23:49.510 INFO client/rm_branch_commit_processor.go:90 send branch commit success: xid 172.20.0.3:8091:27358463220736003, branchID 27358463220736004, resourceID root:12345678@tcp(127.0.0.1:3306)/seata_client, applicationData []
db模式相对复杂一些,我们需要修改配置
代码语言:javascript复制version: "3.1"
services:
mysql:
image: mysql:5.7
container_name: mysql
environment:
- MYSQL_ROOT_PASSWORD=12345678
command: --default-authentication-plugin=mysql_native_password --default-time-zone=' 08:00'
volumes:
- ./mysql:/docker-entrypoint-initdb.d
- ./mysql/mysqld.cnf:/etc/mysql/mysql.conf.d/mysqld.cnf
ports:
- "3306:3306"
extra_hosts:
- host.docker.internal:host-gateway
seata-server:
image: seataio/seata-server:1.5.2
ports:
- "7091:7091"
- "8091:8091"
environment:
- STORE_MODE=db
# 以SEATA_IP作为host注册seata server
# - SEATA_IP=host.docker.internal
# - SEATA_PORT=8091
volumes:
# - "/usr/share/zoneinfo/Asia/Shanghai:/etc/localtime" #设置系统时区
# - "/usr/share/zoneinfo/Asia/Shanghai:/etc/timezone" #设置时区
# 假设我们通过docker cp命令把资源文件拷贝到相对路径`./seata-server/resources`中
# 如有问题,请阅读上面的[注意事项]以及[使用自定义配置文件]
- "./seata-server/resources/resources:/seata-server/resources"
depends_on:
- mysql
extra_hosts:
- host.docker.internal:host-gateway
其中,我们可以把配置文件拷贝出来修改下
代码语言:javascript复制docker cp 6df7f484515e:/seata-server/resources ./seata-server/resources
修改后的application.yml如下:
代码语言:javascript复制server:
port: 7091
spring:
application:
name: seata-server
logging:
config: classpath:logback-spring.xml
file:
path: ${user.home}/logs/seata
extend:
logstash-appender:
destination: 127.0.0.1:4560
kafka-appender:
bootstrap-servers: 127.0.0.1:9092
topic: logback_to_logstash
console:
user:
username: seata
password: seata
seata:
config:
# support: nacos, consul, apollo, zk, etcd3
type: file
registry:
# support: nacos, eureka, redis, zk, consul, etcd3, sofa
type: file
store:
# support: file 、 db 、 redis
mode: db
db:
datasource: druid
dbType: mysql
# 需要根据mysql的版本调整driverClassName
# mysql8及以上版本对应的driver:com.mysql.cj.jdbc.Driver
# mysql8以下版本的driver:com.mysql.jdbc.Driver
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://host.docker.internal:3306/seata_server?useUnicode=true&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false
user: root
password: 12345678
# 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
其中三点改动需要关注
1,- STORE_MODE=file改成了- STORE_MODE=db
2,地址需要改成host.docker.internal,原因在前面的系列文章中介绍过
3,dsn的数据库名需要改成seata_server
否则会报错
代码语言:javascript复制java.sql.SQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.
启动
代码语言:javascript复制docker compose -f docker-compose-db.yaml up
最后链接上mysql,创建我们依赖的库和表
代码语言:javascript复制-- -------------------------------- The script used when storeMode is 'db' --------------------------------
create database `seata_server`;
use `seata_server`;
-- 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_status_gmt_modified` (`status` , `gmt_modified`),
KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
-- 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 = utf8mb4;
-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
`row_key` VARCHAR(128) NOT NULL,
`xid` VARCHAR(128),
`transaction_id` BIGINT,
`branch_id` BIGINT NOT NULL,
`resource_id` VARCHAR(256),
`table_name` VARCHAR(32),
`pk` VARCHAR(36),
`status` TINYINT NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
`gmt_create` DATETIME,
`gmt_modified` DATETIME,
PRIMARY KEY (`row_key`),
KEY `idx_status` (`status`),
KEY `idx_branch_id` (`branch_id`),
KEY `idx_xid` (`xid`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
CREATE TABLE IF NOT EXISTS `distributed_lock`
(
`lock_key` CHAR(20) NOT NULL,
`lock_value` VARCHAR(20) NOT NULL,
`expire` BIGINT,
primary key (`lock_key`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);
create database seata_client;
use seata_client;
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,
`ext` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `storage_tbl`;
CREATE TABLE `storage_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY (`commodity_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `order_tbl`;
CREATE TABLE `order_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`commodity_code` varchar(255) DEFAULT NULL,
`count` int(11) DEFAULT 0,
`money` int(11) DEFAULT 0,
`descs` varchar(255) DEFAULT "",
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `account_tbl`;
CREATE TABLE `account_tbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(255) DEFAULT NULL,
`money` int(11) DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
代码语言:javascript复制mysql -uroot -p12345678 -h127.0.0.1 -e 'source mysql.sql'
需要注意的是,官方默认的数据库创建文件里少了个字段,导致跑不起来,需要加个字段
代码语言:javascript复制 CREATE TABLE `order_tbl`
`descs` varchar(255) DEFAULT "",
启动我们的seata-go
代码语言:javascript复制 % go run github.com/seata/seata-go/sample/at/basic
2022-12-10 22:13:05.384 INFO client/rm_branch_commit_processor.go:90 send branch commit success: xid 172.19.0.3:8091:27358476928553095, branchID 27358476928553097, resourceID root:12345678@tcp(127.0.0.1:3306)/seata_client, applicationData []
发现已经成功了。
调试追踪过程中我们发现,会创建这种全局锁,事务完成后提交。
代码语言:javascript复制select * from global_table;
----------------------------------- ------------------- -------- ---------------- --------------------------- ----------------------- --------- --------------- ------------------ --------------------- ---------------------
| xid | transaction_id | status | application_id | transaction_service_group | transaction_name | timeout | begin_time | application_data | gmt_create | gmt_modified |
----------------------------------- ------------------- -------- ---------------- --------------------------- ----------------------- --------- --------------- ------------------ --------------------- ---------------------
| 172.19.0.3:8091:27358476928553113 | 27358476928553113 | 1 | seata-go | 127.0.0.1:8091 | ATSampleLocalGlobalTx | 30000 | 1670682517809 | NULL | 2022-12-10 22:28:37 | 2022-12-10 22:28:37 |
----------------------------------- ------------------- -------- ---------------- --------------------------- ----------------------- --------- --------------- ------------------ --------------------- ---------------------
1 row in set (0.00 sec)