1. Download
Official websites
2. Build a warehouse and build a table
create database seat;-- -------------------------------- The script used when storeMode is 'db' -------------------------------- -- the table to store GlobalSession data CREATE TABLE IF NOT EXISTS
global_table(
xidVARCHAR(128) NOT NULL,
Transaction numberBIGINT,
CaseTINYINT NOT NULL,
Form numberVARCHAR(32),
set_service_transactionVARCHAR(32),
transaction_nameVARCHAR(128),
time outINT,
start timeBIGINT,
order dataVARCHAR(2000),
gmt_createDATETIME,
gmt_modifiedDATETIME, PRIMARY KEY (
xid), KEY
idx_gmt_modified_status(
gmt_modified,
Case), KEY
idx_transaction_id(
transaction_id”)
) engine = InnoDB
default set = utf8;
– Branch session data storage table
Create a table if it does not exist branch_table
(branch_id
is not empty,xid
farchar (128) is not empty,transaction_id
begent,resource_group_id
Farkar (32),resource_id
Farkar (256),branch_type
Farkar (8),status
TINYINT,client_id
Farkar (64),application_data
Farshar (2000),gmt_create
date (6),gmt_modified
date (6),
The primary key (branch_id
),
key idx_xid
(xid
)
) engine = InnoDB
default set = utf8;
– Table to store lock data
Create a table if it does not exist lock_table
(row_key
farchar (128) is not empty,xid
Farkar (96),transaction_id
begent,branch_id
is not empty,resource_id
Farkar (256),table_name
Farkar (32),pk
Farkar (36),gmt_create
History ,gmt_modified
History ,
The primary key (row_key
),
key idx_branch_id
(branch_id
)
) engine = InnoDB
default set = utf8; `
3. Change the configuration file
.conf file in the conf directory
The above database address is filled in with the address of the newly built warehouse. (The above tables are required while running general states, but the data will be automatically deleted once the transaction ends)
4. Edit the Registry.conf file
5. If some computers are not configured well, they cannot be started
You may see an error message in the CMD command window.
May 1 error
It may suggest a jvm.dll file that you can navigate to a folder in the directory you provided to find that file (search directly in that directory)
May 2 error
Not enough space
You can change the content directly in the seata-server.bat file
For now, you can start off great.(The prerequisite is to start the NACOS server)
After the launch is successful, you can see at NACOS
6. Publication management
1. The Boom Boom Project
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<spring.boot.version>2.2.4.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
<spring.cloud.alibaba.version>2.2.0.RELEASE</spring.cloud.alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
2. POM sub-project
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.48</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-seata</artifactId>
</dependency>
<dependency>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>1.4.0</version>
</dependency>
<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>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
</dependencies>
7. Account Service
1. Map Maker
@Mapper
public interface AccountMapper {
public void payment(@Param("userId") Long userId, @Param("money") BigDecimal money);
}
2. Service
public interface AccountService {
public CommonResult payment(Long userId, BigDecimal money);
}
3. Simple service
@Service
@Slf4j
public class AccountServiceImpl implements AccountService {
@Resource
private AccountMapper accountMapper;
@Override
public CommonResult payment(Long userId, BigDecimal money) {
log.info("Начать оплату");
int a = 1/0;
accountMapper.payment(userId, money);
log.info("Оплата успешно");
return new CommonResult(200,"Оплата успешно");
}
}
4. Controller
@RestController
public class AccountController {
@Autowired
private AccountService accountService;
@PostMapping("/account/payment")
public CommonResult payment(@RequestParam("userId")Long userId, @RequestParam("money") BigDecimal money){
return accountService.payment(userId,money);
}
}
5. Domain
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Account {
private Long id;
private Long userId;
private BigDecimal total;
private BigDecimal used;
private BigDecimal residue;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T>
{
private Integer code;
private String message;
private T data;
public CommonResult(Integer code, String message)
{
this(code,message,null);
}
}
6. Presentation file
<?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.ljc.springcloud.mapper.AccountMapper">
<resultMap id="BaseResultMap" type="com.ljc.springcloud.domain.Account">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="user_id" property="userId" jdbcType="BIGINT"/>
<result column="total" property="total" jdbcType="DECIMAL"/>
<result column="used" property="used" jdbcType="DECIMAL"/>
<result column="residue" property="residue" jdbcType="DECIMAL"/>
</resultMap>
<update id="payment">
UPDATE t_account
SET
residue = residue - #{money},used = used + #{money}
WHERE
user_id = #{userId};
</update>
</mapper>
7. Let the Lord go
@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
@MapperScan("com.ljc.springcloud.mapper")
public class AccountMain2003 {
public static void main(String[] args) {
SpringApplication.run(AccountMain2003.class,args);
}
}
8. It works
server:
port: 2003
spring:
application:
name: seata-account-service
cloud:
nacos:
discovery:
server-addr: localhost:8848
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://192.168.83.130:3306/seata_account?useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
seata:
application-id: ${spring.application.name}
tx-service-group: ${spring.application.name}-group
service:
vgroup-mapping:
seata-account-service-group: default
registry:
type: nacos
nacos:
cluster: default
namespace:
serverAddr: localhost
logging:
level:
io:
seata: info
mybatis:
mapperLocations: classpath:mapper/*.xml
8. Inventory service
1. Map Maker
@Mapper
public interface StorageMapper {
public void update(@Param("productId") Long productId, @Param("count") Integer count);
}
2. Service
public interface StorageService {
public void update(Long productId,Integer count);
}
3. Service
@Service
@Slf4j
public class StorageServiceImpl implements StorageService {
@Resource
private StorageDao storageDao;
@Override
public void update(Long productId, Integer count) {
log.info("Стоиджестники снижения");
storageDao.update(productId,count);
log.info(«StorageserViceImpl успешно сократил инвентаризацию»);
}
}
4. Controller
@RestController
public class StorageController {
@Autowired
private StorageService storageService;
@PostMapping("/storage/update")
public CommonResult update(@RequestParam("productId") Long productId, @RequestParam("count") Integer count){
System.out.println(productId+" "+count);
storageService.update(productId,count);
return new CommonResult(200,"Успешное из склада !!!");
}
}
5. Domain
@Data
public class Storage {
000
private Long id;
private Long productId;
private Integer total;
private Integer used;
private Integer residue;
}
6. Yaml same as above (Just Port and Service Name)
7.xml map file
<?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.ljc.springcloud.dao.StorageDao">
<resultMap id="storageMap" type="com.ljc.springcloud.domain.Storage">
<id property="id" column="id" jdbcType="BIGINT"/>
<result property="productId" column="productId" jdbcType="BIGINT"/>
<result property="total" column="total" jdbcType="INTEGER"/>
<result property="used" column="used" jdbcType="BIGINT"/>
<result property="residue" column="residue" jdbcType="BIGINT"/>
</resultMap>
<update id="update">
update t_storage set used = used + #{count},residue = residue - #{count} where product_id = #{productId};
</update>
</mapper>
8. Let the Lord go
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@MapperScan({"com.ljc.springcloud.mapper"})
public class StorageMain2002 {
public static void main(String[] args) {
SpringApplication.run(StorageMain2002.class,args);
}
}
9. Service request
1. mappr
@Mapper
public interface OrderMapper {
public void createOrder(Order order);
public void update(@Param("userId") Long userId, @Param("status") Integer status);
}
2. Service
public interface OrderService {
public void createOrder(Order order);
}
3. Service
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
@Resource
private AccountService accountService;
@Resource
private OrderDao orderDao;
@Resource
private StorageService storageService;
@Override
public void createOrder(Order order) {
log.info("Создание заказа ...........");
orderDao.createOrder(order);
log.info("Заказать успешно созданный .......");
log.info("Уменьшите инвентарь .............");
storageService.update(order.getProductId(),order.getCount());
log.info("Успех -смягчающий инвентарь .........");
log.info("Вычет учетной записи ...........");
accountService.payment(order.getUserId(),order.getMoney());
log.info("Успешный вычет учетной записи ...");
log.info("Измените статус заказа ...");
orderDao.update(order.getUserId(),0);
log.info("Измените успех статуса заказа ...");
}
}
4. Confiscation
@FeignClient("seata-account-service")
public interface AccountService {
@PostMapping("/account/payment")
public CommonResult payment(@RequestParam("userId") Long userId, @RequestParam("money") BigDecimal money);
}
@FeignClient("seata-storage-service")
public interface StorageService {
@PostMapping("/storage/update")
public CommonResult update(@RequestParam("productId") Long productId, @RequestParam("count") Integer count);
}
5. Controller
@RestController
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping("/order/create")
@GlobalTransactional(name="tx-order-fsp",rollbackFor = Exception.class)
public CommonResult createOrder(Order order){
orderService.createOrder(order);
return new CommonResult(200,"Заказать успешно создан !!!!!");
}
}
Referring to the microservice call, the previous microservices (or microservices that need to manage the database first, note the current GlobalTransactional, this place is equivalent to TM initiating a transaction request in TC)
6.xml map file
<?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.ljc.springcloud.dao.OrderDao">
<resultMap id="OrderMap" type="com.ljc.springcloud.domain.Order">
<id property="id" column="id" jdbcType="BIGINT"/>
<result property="userId" column="userId" jdbcType="BIGINT"/>
<result property="productId" column="productId" jdbcType="BIGINT"/>
<result property="count" column="count" jdbcType="INTEGER"/>
<result property="money" column="money" jdbcType="DECIMAL"/>
<result property="status" column="status" jdbcType="INTEGER"/>
</resultMap>
<insert id="createOrder">
insert into t_order(id,user_id,product_id,count,money,status)
values(null,#{userId},#{productId},#{count},#{money},0);
</insert>
<update id="update">
update t_order set status = 1 where user_id = #{userId} and status = #{status};
</update>
</mapper>
7. Let the Lord go
@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
@MapperScan({"com.ljc.springcloud.dao"})
public class OrderMain2001 {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(OrderMain2001.class, args);
}
}
8. yml
Same port and service name
10. Audition
Database raw data
normal test
Test results
abnormal start
Add an anomaly to /null in the account service
Restart the account service
The same request visits once
a result
console information
Database
Global action is successful! intersection intersection intersection
11 principle
term
TC (Transaction Coordinator) – Transaction Coordinator
Maintain the state of the globe and branches, and drive global states to launch or rollback.
TM (Transaction Manager) – the ground manager
Scope of defining global states: starting global states, sending or canceling global states.
RM (Resource Manager) – resource manager
Affiliate case management resources are discussed with TC for affiliate registration and affiliate reporting, as well as asking affiliates to submit or decline them.
Seata has many modes in TCC mode, SAGA and XA modes
By default in the mode
AT: Non-invention automatic offset transaction model provides. Currently, MySQL, Oracle, PostgreSQL, and TIDB form are supported.
TM asks TC to open global cases. TC generates XID as a series of global states. The XID will be published in the microservice call reference to ensure that the sub-transaction of multiple microservices is bound together. RM tells TC to register the local states as a child of the global states and they are linked through the global states XID. TM Ask a TC to tell appropriate global XID cases whether to go or not. The TC RM driver presents local states corresponding to XID or backtracking.
Dirty write concept: In the case of high concurrency, the meta-collection can be changed many times and the actual database data is different from the background data.
There will be one before SQL is executedFront mirror imageHe will be lonely after the executionrear mirror imageThen add onea lock
When the execution is successful, the front mirror image, the back mirror image, and the line lock will be removed.
However, when the execution fails, the current database data will be compared with the back mirror image.
Front mirror and rear mirror activity
select money from account where uid = 1;
update account set money = money - 100 where uid = 1;
select money from account where uid = 1 ;
When anomalies occur when the database is 900 and the back end is also 900, it means that it is not badly written, so roll back. Change database data to forward data 1000
Learn from: SpringCloud2020, teacher Zhuyang, Shanxi Valley, white papers and Seata.io official blogs.