Using SEATA 1.4 and solving the problem of SEATA SEATA launch, the principle of Seata

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 EXISTSglobal_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), KEYidx_gmt_modified_status(gmt_modified,Case), KEYidx_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.

TMTC xid

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.

Leave a Comment