seata 分布式事务 -- seata-one 工程完整代码

 

 

eureka,沿用  TX-LCN分布式事务-- LCN事务模式(eureka模块)

seata-one  工程结构:

 

 

 

配置文件在最下面:

启动类:

 

package com.;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
public class SeataOneApplication {

    public static void main(String[] args) {
        SpringApplication.run(SeataOneApplication.class, args);
    }

    @Bean
    @LoadBalanced//开启负载均衡
    public RestTemplate restTemplate(){

        return new RestTemplate();
    }
}

 

入口  controller:

(一个 AT 模式,一个 TCC 模式)


package com..controller;

import com..service.Rm_One_Interface;
import com..service.Rm_One_Service;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Rm_One_Controller {

@Autowired
private Rm_One_Service rm_one_service;

@Autowired
private Rm_One_Interface rm_one_interface;


/**
* AT 模式
* @return
*/
@RequestMapping("/one_at")
@GlobalTransactional(rollbackFor = Exception.class)
public String at_one(){

String result = rm_one_service.rm1();
if(result.equals("err")){
return "err";
}
return "success_"+result;
}


/**
* TCC模式
* @return
* @throws InterruptedException
*/
@RequestMapping("/one_tcc")
@GlobalTransactional(rollbackFor = Exception.class)
public String oneTcc() throws InterruptedException {
rm_one_interface.rm1(null);
return "success";
}


}
 

 

数据库实体类:

package com..entity;


public class TbloneInfo {
    
    private String id;

    
    private String name;

    
    public String getId() {
        return id;
    }

    
    public void setId(String id) {
        this.id = id;
    }

    
    public String getName() {
        return name;
    }

   
    public void setName(String name) {
        this.name = name == null ? null : name.trim();
    }
}

 

mapper:

package com..mapper;

import com..entity.TbloneInfo;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Component;

import java.util.List;

@Mapper
@Component(value = "TbloneInfoMapper")
public interface TbloneInfoMapper {
    
    int deleteByPrimaryKey(String id);

    
    int insert(TbloneInfo record);

   
    TbloneInfo selectByPrimaryKey(String id);

   
    List<TbloneInfo> selectAll();

   
    int updateByPrimaryKey(TbloneInfo record);
}

 

AT 模式 实现类:

package com..service;


import com..entity.TbloneInfo;
import com..mapper.TbloneInfoMapper;
import com..sqlToJava.SnowFlake;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

/**
 * AT 模式 
 */
@Service
public class Rm_One_Service {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    TbloneInfoMapper tbloneInfoMapper;


    public String rm1(){

        long id = SnowFlake.nextId();
        TbloneInfo tbloneInfo = new TbloneInfo();
        tbloneInfo.setId(id+"");
        tbloneInfo.setName("Rm_One_"+id);
        int insert = tbloneInfoMapper.insert(tbloneInfo);

        rm2();

        rm3();

        if (insert==1){
            return id+"";
        }
        return "err";
    }


    public String rm2(){

        restTemplate.getForObject("http://seata-two/two_at", String.class);
        return "";
    }


    public String rm3(){

        restTemplate.getForObject("http://seata-three/three_at", String.class);

        return "";
    }
}

 

TCC模式 接口 / 实现类:

接口:

package com..service; import io.seata.rm.tcc.api.BusinessActionContext; import io.seata.rm.tcc.api.LocalTCC; import io.seata.rm.tcc.api.TwoPhaseBusinessAction; @LocalTCC public interface Rm_One_Interface { @TwoPhaseBusinessAction(name = "rm1TccAction",commitMethod = "rm1Commit",rollbackMethod = "rm1Rollback") public String rm1(BusinessActionContext businessActionContext); public boolean rm1Commit(BusinessActionContext businessActionContext); public boolean rm1Rollback(BusinessActionContext businessActionContext); }


实现类:
package com..service;

import com..entity.TbloneInfo;
import com..mapper.TbloneInfoMapper;
import com..sqlToJava.SnowFlake;
import io.seata.rm.tcc.api.BusinessActionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@Component
public class Rm_One_InterfaceImpl implements Rm_One_Interface {

@Autowired
RestTemplate restTemplate;

@Autowired
TbloneInfoMapper tbloneInfoMapper;

private static ConcurrentMap<String,String> maps = new ConcurrentHashMap<>();

@Override
@Transactional
public String rm1(BusinessActionContext businessActionContext) {

long id = SnowFlake.nextId();
TbloneInfo tbloneInfo = new TbloneInfo();
tbloneInfo.setId(id+"");
tbloneInfo.setName("Rm_One_"+id);
maps.put("id",id+"");
int insert = tbloneInfoMapper.insert(tbloneInfo);
System.out.println("rm1 try....."+insert);
rm2();
rm3();

return null;
}

@Override
@Transactional
public boolean rm1Commit(BusinessActionContext businessActionContext) {
System.out.println("rm1 rm1Commit...");
return true;
}

@Override
@Transactional
public boolean rm1Rollback(BusinessActionContext businessActionContext) {

String id = maps.get("id");
int i = tbloneInfoMapper.deleteByPrimaryKey(id);
System.out.println("rm1 rm1Rollback..."+i);
return true;
}



public String rm2(){

restTemplate.getForObject("http://seata-two/two_tcc", String.class);
return "";
}


public String rm3(){

restTemplate.getForObject("http://seata-three/three_tcc", String.class);

return "";
}

}
 

 

一个数据库主键生成工具类(雪花算法):

package com..sqlToJava;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;

/**
 * id自增器(雪花算法)
 *
 * @author renjie
 * @version 1.0.0
 */
public class SnowFlake {

    private final static long twepoch = 12888349746579L;
    // 机器标识位数
    private final static long workerIdBits = 5L;
    // 数据中心标识位数
    private final static long datacenterIdBits = 5L;

    // 毫秒内自增位数
    private final static long sequenceBits = 12L;
    // 机器ID偏左移12位
    private final static long workerIdShift = sequenceBits;
    // 数据中心ID左移17位
    private final static long datacenterIdShift = sequenceBits + workerIdBits;
    // 时间毫秒左移22位
    private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
    //sequence掩码,确保sequnce不会超出上限
    private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
    //上次时间戳
    private static long lastTimestamp = -1L;
    //序列
    private long sequence = 0L;
    //服务器ID
    private long workerId = 1L;
    private static long workerMask = -1L ^ (-1L << workerIdBits);
    //进程编码
    private long processId = 1L;
    private static long processMask = -1L ^ (-1L << datacenterIdBits);

    private static SnowFlake snowFlake = null;

    static{
        snowFlake = new SnowFlake();
    }
    public static synchronized long nextId(){
        return snowFlake.getNextId();
    }

    private SnowFlake() {

        //获取机器编码
        this.workerId=this.getMachineNum();
        //获取进程编码
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        this.processId=Long.valueOf(runtimeMXBean.getName().split("@")[0]).longValue();

        //避免编码超出最大值
        this.workerId=workerId & workerMask;
        this.processId=processId & processMask;
    }

    public synchronized long getNextId() {
        //获取时间戳
        long timestamp = timeGen();
        //如果时间戳小于上次时间戳则报错
        if (timestamp < lastTimestamp) {
            try {
                throw new Exception("Clock moved backwards.  Refusing to generate id for " + (lastTimestamp - timestamp) + " milliseconds");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //如果时间戳与上次时间戳相同
        if (lastTimestamp == timestamp) {
            // 当前毫秒内,则+1,与sequenceMask确保sequence不会超出上限
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                // 当前毫秒内计数满了,则等待下一秒
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0;
        }
        lastTimestamp = timestamp;
        // ID偏移组合生成最终的ID,并返回ID
        long nextId = ((timestamp - twepoch) << timestampLeftShift) | (processId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
        return nextId;
    }

    /**
     * 再次获取时间戳直到获取的时间戳与现有的不同
     * @param lastTimestamp
     * @return 下一个时间戳
     */
    private long tilNextMillis(final long lastTimestamp) {
        long timestamp = this.timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = this.timeGen();
        }
        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }

    /**
     * 获取机器编码
     * @return
     */
    private long getMachineNum(){
        long machinePiece;
        StringBuilder sb = new StringBuilder();
        Enumeration<NetworkInterface> e = null;
        try {
            e = NetworkInterface.getNetworkInterfaces();
        } catch (SocketException e1) {
            e1.printStackTrace();
        }
        while (e.hasMoreElements()) {
            NetworkInterface ni = e.nextElement();
            sb.append(ni.toString());
        }
        machinePiece = sb.toString().hashCode();
        return machinePiece;
    }
}

 

application.yml  :

server:
  port: 8080

#应用名称及验证账号
spring:
  application:
    name: seata-one


  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3307/seata-rm-one?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: root
    password: root
    dbcp2:
      initial-size: 5
      min-idle: 5
      max-total: 5
      max-wait-millis: 200
      validation-query: SELECT 1
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false

mybatis:
  mapper-locations:
    - classpath:mapper/*.xml

eureka:
  client:
    prefer-ip-address: true
    service-url:
      defaultZone: http://localhost:7900/eureka/

 

数据库链接 TbloneInfoMapper.xml:

(项目地址需要根据情况补充)

<?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..mapper.TbloneInfoMapper">
  <resultMap id="BaseResultMap" type="com..entity.TbloneInfo">
    <!--
      WARNING - @mbg.generated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Mon May 17 11:02:49 CST 2021.
    -->
    <id column="id" jdbcType="VARCHAR" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
  </resultMap>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.String">
    <!--
      WARNING - @mbg.generated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Mon May 17 11:02:49 CST 2021.
    -->
    delete from tbl_one
    where id = #{id,jdbcType=VARCHAR}
  </delete>
  <insert id="insert" parameterType="com..entity.TbloneInfo">
    <!--
      WARNING - @mbg.generated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Mon May 17 11:02:49 CST 2021.
    -->
    insert into tbl_one (id, name)
    values (#{id,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR})
  </insert>
  <update id="updateByPrimaryKey" parameterType="com..entity.TbloneInfo">
    <!--
      WARNING - @mbg.generated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Mon May 17 11:02:49 CST 2021.
    -->
    update tbl_one
    set name = #{name,jdbcType=VARCHAR}
    where id = #{id,jdbcType=VARCHAR}
  </update>
  <select id="selectByPrimaryKey" parameterType="java.lang.String" resultMap="BaseResultMap">
    <!--
      WARNING - @mbg.generated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Mon May 17 11:02:49 CST 2021.
    -->
    select id, name
    from tbl_one
    where id = #{id,jdbcType=VARCHAR}
  </select>
  <select id="selectAll" resultMap="BaseResultMap">
    <!--
      WARNING - @mbg.generated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Mon May 17 11:02:49 CST 2021.
    -->
    select id, name
    from tbl_one
  </select>
</mapper>

 

pom:

(<groupId>com.</groupId> 需要根据情况补充 )

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.</groupId>
    <artifactId>seata-one</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>seata-one</name>
    <description>seata-oneBoot</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2020.0.2</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- euekea 依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- mysql:MyBatis相关依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.0</version>
        </dependency>

        <!-- 整合MyBatis java类依赖 -->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-maven-plugin</artifactId>
            <version>1.4.0</version>
            <type>maven-plugin</type>
        </dependency>

        <!-- mysql:mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!-- mysql:阿里巴巴数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.12</version>
        </dependency>
        <!--  JSONObject  -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.60</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-seata</artifactId>
            <version>2.2.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-commons</artifactId>
            <version>3.0.2</version>
        </dependency>

    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>



    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

 

posted @ 2021-05-18 16:48  Li&Fan  阅读(184)  评论(0编辑  收藏  举报