分布式锁、任务、事务

it2023-05-18  68

一、分布式锁

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)