分布式锁、任务、事务

本文探讨了分布式锁的实现,包括使用Zookeeper和Redis的方法,并介绍了分布式事务在MQ和LCN框架下的应用。通过压力测试展示了分布式锁防止超卖问题的重要性。同时,详细说明了LCN分布式事务管理器的配置和使用,以及在遇到错误时如何影响事务处理。
摘要由CSDN通过智能技术生成

一、分布式锁

在这里插入图片描述
java测试

@RestController
public class SecondKillController {
    //1准备商品库存
    private static Map<String,Integer> itemStock = new HashMap<>();
    //2.准备订单
    private static Map<String,Integer> itemOrder = new HashMap<>();
    static {
        itemStock.put("牙刷", 10000);
        itemOrder.put("牙刷", 0);
    }
    @GetMapping("kill")
    public String kill(String item) throws InterruptedException {
        //减库存
        Integer stock = itemStock.get(item);
        if(stock <= 0){
            return "没有商品了";

        }else{
            Thread.sleep(100);
            itemStock.put(item, stock-1);
        }
        Thread.sleep(100);
        itemOrder.put(item, itemOrder.get(item)+1);
        return "抢够成功了,"+item+"剩余:"+itemStock.get(item)+",订单数--"+itemOrder.get(item);
    }

在这里插入图片描述
下载ab压力测试
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
1000请求 500并发
D:\environment\ab\Apache24\bin>ab -n 1000 -c 500 http://localhost:8082/kill?ite
=%E7%89%99%E5%88%B7
刷新发现超卖现象
在这里插入图片描述

zoekeeper实现分布式锁

在这里插入图片描述

@Configuration
public class ZkConfig {

    @Bean
    public CuratorFramework cf(){
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000,2 );
        CuratorFramework curatorFramework = CuratorFrameworkFactory.builder()
                .connectString("192.168.232.128:2181")
                .retryPolicy(retryPolicy)
                .build();
        curatorFramework.start();
        return curatorFramework;

    }
}
 @Autowired
    private CuratorFramework cf;
    //1准备商品库存
    private static Map<String,Integer> itemStock = new HashMap<>();
    //2.准备订单
    private static Map<String,Integer> itemOrder = new HashMap<>();
    static {
        itemStock.put("牙刷", 10000);
        itemOrder.put("牙刷", 0);
    }
    @GetMapping("kill")
    public String kill(String item) throws Exception {
        //开始访问共享资源,这里是访问商品信息
        InterProcessMutex lock = new InterProcessMutex(cf,"/lock" );
        //。。。分布式 加锁
        lock.acquire();
        //减库存
        Integer stock = itemStock.get(item);
        if(stock <= 0){
            return "没有商品了";
        }
        Thread.sleep(100);
        itemStock.put(item, stock-1);
        Thread.sleep(100);
        itemOrder.put(item, itemOrder.get(item)+1);
        //释放锁
        lock.release();
        //将锁归还
        return "抢够成功了,"+item+"剩余:"+itemStock.get(item)+",订单数--"+itemOrder.get(item);
    }

redis实现分布式锁

在这里插入图片描述

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-redis</artifactId>
        <version>1.4.5.RELEASE</version>
    </dependency>
@Component
public class RedisLockUtil {
    @Autowired
    private RedisTemplate redisTemplate;
    //加锁
    public boolean lock(String key, String value,int second){
        return redisTemplate.opsForValue().setIfAbsent(key, value, second, TimeUnit.SECONDS);
    }
    //释放锁
    public void unlock(String key){
        redisTemplate.delete(key);
    }
}
@Autowired
    private RedisLockUtil lockUtil;
@GetMapping("redis/kill")
    public String redisKill(String item) throws Exception {
        //。。。分布式 加锁
        if(lockUtil.lock(item, System.currentTimeMillis()+"",1 )){
            //减库存
            Integer stock = itemStock.get(item);
            if(stock <= 0){
                return "没有商品了";
            }
            Thread.sleep(100);
            itemStock.put(item, stock-1);
            Thread.sleep(100);
            itemOrder.put(item, itemOrder.get(item)+1);
            //释放锁
            lockUtil.unlock(item);
            //将锁归还
            return "抢够成功了,"+item+"剩余:"+itemStock.get(item)+",订单数--"+itemOrder.get(item);
        }else{
            return "你没有抢到商品";
        }

分布式事务

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

MQ实现分布式事务

在这里插入图片描述
LCN实现分布式事务

在这里插入图片描述
准备3个项目 txlcn-manager txlcn-order txlcn-item

txlcn-manager:

 <dependency>
   <groupId>com.codingapi.txlcn</groupId>
    <artifactId>txlcn-tm</artifactId>
    <version>5.0.2.RELEASE</version>
</dependency>
server:
  port: 8083
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/lcn?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
    username: root
    password:
  redis:
    host: 192.168.232.128
    port: 6379
tx-lcn:
  manager:
    port: 8070
@SpringBootApplication
@EnableTransactionManagerServer
public class application {
    public static void main(String[] args) {
        SpringApplication.run(application.class,args);
    }
}

lcn对yml不友好,可再建一个空application.properties
访问http://localhost:8083/admin/index.html#/login
类似注册中心那种,可以看到你有哪些服务需要做事务处理的。登录的默认密码为codingapi
在这里插入图片描述

txlcn-order:

 <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.codingapi.txlcn</groupId>
            <artifactId>txlcn-tc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.codingapi.txlcn</groupId>
            <artifactId>txlcn-txmsg-netty</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
    </dependencies>
server:
  port: 8084
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/lcn?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
    username: root
    password:
tx-lcn:
  client:
    manager-address: localhost:8070
@SpringBootApplication
@EnableDistributedTransaction
@MapperScan(basePackages = "com.rayc.mapper")
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class,args);
    }

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}
 @GetMapping("/order")
    public String create(){
        orderService.createOrder();
        return "创建订单成功";
    }
    
    public interface OrderService {
    	void createOrder();
   }
   
    @Service
	public class OrderServiceImpl implements OrderService {
	    @Autowired
	    private OrderMapper orderMapper;
	    @Autowired
	    RestTemplate restTemplate;
	    @Override
	    @Transactional
	    @LcnTransaction
	    public void createOrder() {
	        //1、减库存
	        restTemplate.getForObject("http://localhost:8085/item", String.class);
	        System.out.println("减库存");
	//        int i = 1/0;
	        //2、创建订单
	        orderMapper.save();
	    }
	}

    public interface OrderMapper {
    @Insert("insert into order_item (id,name,money) values (1,'张三',123)")
    void save();
}

txlcn-item

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.codingapi.txlcn</groupId>
            <artifactId>txlcn-tc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>com.codingapi.txlcn</groupId>
            <artifactId>txlcn-txmsg-netty</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
    </dependencies>
server:
  port: 8085
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/lcn?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
    username: root
    password:
tx-lcn:
  client:
    manager-address: localhost:8070
@SpringBootApplication
@EnableDistributedTransaction
@MapperScan(basePackages = "com.rayc.mapper")
public class ItemApplication {
    public static void main(String[] args) {
        SpringApplication.run(ItemApplication.class,args);
    }
}

@RestController
public class ItemController {
    @Autowired
    private ItemService itemService;
    @GetMapping("/item")
    public String item(){
        System.out.println("开始减库存");
        itemService.update();
        return null;
    }
}

public interface ItemService {
    void update();
}

@Service
public class ItemServiceImpl implements ItemService {
    @Autowired
    private ItemMapper itemMapper;
    @Override
    @Transactional
    @LcnTransaction
    public void update() {
        //1、减库存
        itemMapper.update();
    }
}

public interface ItemMapper {
    @Update("update item set stock = stock - 1 where id = 1")
    void update();
}

另需创建lcn数据库及表

CREATE TABLE `t_tx_exception`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `group_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `unit_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `mod_id` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `transaction_state` tinyint(4) NULL DEFAULT NULL,
  `registrar` tinyint(4) NULL DEFAULT NULL,
  `remark` varchar(4096) NULL DEFAULT  NULL,
  `ex_state` tinyint(4) NULL DEFAULT NULL COMMENT '0 未解决 1已解决',
  `create_time` datetime(0) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

加上自己的数据库 order_item和item表

int i = 1/0;
失败库存未减订单未生成
去掉则成功
在这里插入图片描述
学习视频: https://www.bilibili.com/video/BV17D4y1S7GQ?p=17

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值