Seata 整合学习完成
This commit is contained in:
		@@ -20,7 +20,7 @@
 | 
			
		||||
    <dependencies>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.alibaba.cloud</groupId>
 | 
			
		||||
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
 | 
			
		||||
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.springframework.cloud</groupId>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package com.test;
 | 
			
		||||
 | 
			
		||||
import io.seata.spring.annotation.datasource.EnableAutoDataSourceProxy;
 | 
			
		||||
import org.springframework.boot.SpringApplication;
 | 
			
		||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
 | 
			
		||||
import org.springframework.cloud.openfeign.EnableFeignClients;
 | 
			
		||||
@@ -12,6 +13,7 @@ import org.springframework.cloud.openfeign.EnableFeignClients;
 | 
			
		||||
 * @Create 2023/8/14 16:25
 | 
			
		||||
 */
 | 
			
		||||
@EnableFeignClients
 | 
			
		||||
@EnableAutoDataSourceProxy
 | 
			
		||||
@SpringBootApplication
 | 
			
		||||
public class BorrowApplication {
 | 
			
		||||
    public static void main(String[] args) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,10 @@
 | 
			
		||||
package com.test.controller;
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.annotation.SentinelResource;
 | 
			
		||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
 | 
			
		||||
import com.alibaba.fastjson.JSONObject;
 | 
			
		||||
import com.test.entity.User;
 | 
			
		||||
import com.test.entity.UserBorrowDetail;
 | 
			
		||||
import com.test.service.BorrowService;
 | 
			
		||||
import org.springframework.web.bind.annotation.PathVariable;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestParam;
 | 
			
		||||
import org.springframework.web.bind.annotation.RestController;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
@@ -28,58 +24,20 @@ public class BorrowController {
 | 
			
		||||
    @Resource
 | 
			
		||||
    BorrowService service;
 | 
			
		||||
 | 
			
		||||
    @RequestMapping("/borrow1/{uid}")
 | 
			
		||||
    UserBorrowDetail findUserBorrows1(@PathVariable("uid") int uid) {
 | 
			
		||||
    @RequestMapping("/borrow/{uid}")
 | 
			
		||||
    UserBorrowDetail findUserBorrows(@PathVariable("uid") int uid){
 | 
			
		||||
        return service.getUserBorrowDetailByUid(uid);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @RequestMapping("/borrow2/{uid}")
 | 
			
		||||
    @SentinelResource(value = "findUserBorrows2", blockHandler = "test")
 | 
			
		||||
    UserBorrowDetail findUserBorrows2(@PathVariable("uid") int uid) throws InterruptedException {
 | 
			
		||||
        throw new RuntimeException();
 | 
			
		||||
    }
 | 
			
		||||
    @RequestMapping("/borrow/take/{uid}/{bid}")
 | 
			
		||||
    JSONObject borrow(@PathVariable("uid") int uid,
 | 
			
		||||
                      @PathVariable("bid") int bid){
 | 
			
		||||
        service.doBorrow(uid, bid);
 | 
			
		||||
 | 
			
		||||
    UserBorrowDetail test(int uid, BlockException e) {
 | 
			
		||||
//        输出降级异常
 | 
			
		||||
        System.out.println(e.getClass());
 | 
			
		||||
        return new UserBorrowDetail(new User(), Collections.emptyList());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @RequestMapping("/blocked")
 | 
			
		||||
    JSONObject blocked() {
 | 
			
		||||
        JSONObject object = new JSONObject();
 | 
			
		||||
        object.put("code", 403);
 | 
			
		||||
        object.put("success", false);
 | 
			
		||||
        object.put("massage", "您的请求频率过快,请稍后再试!");
 | 
			
		||||
        object.put("code", "200");
 | 
			
		||||
        object.put("success", true);
 | 
			
		||||
        object.put("message", "借阅成功!");
 | 
			
		||||
        return object;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //    @RequestMapping("/test")
 | 
			
		||||
//    @SentinelResource(value = "test", fallback = "except",    //fallback指定出现异常时的替代方案
 | 
			
		||||
//            blockHandler = "blocked",
 | 
			
		||||
////            特别注意这种方式会在没有配置blockHandler的情况下,将Sentinel机制内(也就是限流的异常)的异常也一并处理了,如果配置了blockHandler,那么在出现限流时,依然只会执行blockHandler指定的替代方案(因为限流是在方法执行之前进行的)
 | 
			
		||||
//            exceptionsToIgnore = IOException.class)
 | 
			
		||||
//        //忽略那些异常,也就是说这些异常出现时不使用替代方案
 | 
			
		||||
//    String test() {
 | 
			
		||||
//        throw new RuntimeException("HelloWorld!");
 | 
			
		||||
//    }
 | 
			
		||||
//
 | 
			
		||||
//    //替代方法必须和原方法返回值和参数一致,最后可以添加一个Throwable作为参数接受异常
 | 
			
		||||
//    String except(Throwable t) {
 | 
			
		||||
//        return t.getMessage();
 | 
			
		||||
//    }
 | 
			
		||||
    @RequestMapping("/test")
 | 
			
		||||
    @SentinelResource("test")
 | 
			
		||||
    //注意这里需要添加@SentinelResource才可以,用户资源名称就使用这里定义的资源名称
 | 
			
		||||
    String findUserBorrows2(@RequestParam(value = "a", required = false) String a, @RequestParam(value = "b", required = false) String b, @RequestParam(value = "c", required = false) String c) {
 | 
			
		||||
        return "请求成功!a = " + a + ", b = " + b + ", c = " + c;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //模拟慢调用
 | 
			
		||||
    @RequestMapping("/slowCall/{uid}")
 | 
			
		||||
    String slowCall(@PathVariable("uid") int uid) throws InterruptedException {
 | 
			
		||||
        //模拟慢调用
 | 
			
		||||
        Thread.sleep(1000);
 | 
			
		||||
        return "Hello World";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package com.test.mapper;
 | 
			
		||||
 | 
			
		||||
import com.test.entity.Borrow;
 | 
			
		||||
import org.apache.ibatis.annotations.Insert;
 | 
			
		||||
import org.apache.ibatis.annotations.Mapper;
 | 
			
		||||
import org.apache.ibatis.annotations.Select;
 | 
			
		||||
 | 
			
		||||
@@ -23,4 +24,7 @@ public interface BorrowMapper {
 | 
			
		||||
 | 
			
		||||
    @Select("select * from DB_BORROW where bid = #{bid} and uid = #{uid}")
 | 
			
		||||
    Borrow getBorrow(int uid, int bid);
 | 
			
		||||
 | 
			
		||||
    @Insert("insert into db_borrow(uid, bid) values (#{uid},#{bid})")
 | 
			
		||||
    int addBorrow(int uid, int bid);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,4 +13,5 @@ import com.test.entity.UserBorrowDetail;
 | 
			
		||||
public interface BorrowService {
 | 
			
		||||
 | 
			
		||||
    UserBorrowDetail getUserBorrowDetailByUid(int uid);
 | 
			
		||||
    boolean doBorrow(int uid, int bid);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,4 +17,10 @@ public interface BookClient {
 | 
			
		||||
 | 
			
		||||
    @RequestMapping("/book/{bid}")
 | 
			
		||||
    Book getBookById(@PathVariable("bid") int bid);
 | 
			
		||||
 | 
			
		||||
    @RequestMapping("/book/borrow/{bid}")
 | 
			
		||||
    boolean bookBorrow(@PathVariable("bid") int bid);
 | 
			
		||||
 | 
			
		||||
    @RequestMapping("/book/remain/{bid}")
 | 
			
		||||
    int bookRemain(@PathVariable("bid") int bid);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,4 +17,10 @@ public interface UserClient {
 | 
			
		||||
 | 
			
		||||
    @RequestMapping("/user/{uid}")
 | 
			
		||||
    User getUserById(@PathVariable("uid") int uid);
 | 
			
		||||
 | 
			
		||||
    @RequestMapping("/user/borrow/{uid}")
 | 
			
		||||
    boolean userBorrow(@PathVariable("uid") int uid);
 | 
			
		||||
 | 
			
		||||
    @RequestMapping("/user/remain/{uid}")
 | 
			
		||||
    int userRemain(@PathVariable("uid") int uid);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,21 +0,0 @@
 | 
			
		||||
package com.test.service.client;
 | 
			
		||||
 | 
			
		||||
import com.test.entity.User;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ClassName: UserClientImpl
 | 
			
		||||
 * Package: com.test.service.client
 | 
			
		||||
 *
 | 
			
		||||
 * @author yovinchen
 | 
			
		||||
 * @Create 2023/8/17 22:25
 | 
			
		||||
 */
 | 
			
		||||
@Component
 | 
			
		||||
public class UserClientImpl implements UserClient{
 | 
			
		||||
    @Override
 | 
			
		||||
    public User getUserById(int uid) {
 | 
			
		||||
        User user = new User();
 | 
			
		||||
        user.setName("我是替代方案");
 | 
			
		||||
        return user;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,8 +1,5 @@
 | 
			
		||||
package com.test.service.impl;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import com.alibaba.csp.sentinel.annotation.SentinelResource;
 | 
			
		||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
 | 
			
		||||
import com.test.entity.Book;
 | 
			
		||||
import com.test.entity.Borrow;
 | 
			
		||||
import com.test.entity.User;
 | 
			
		||||
@@ -11,6 +8,7 @@ import com.test.mapper.BorrowMapper;
 | 
			
		||||
import com.test.service.BorrowService;
 | 
			
		||||
import com.test.service.client.BookClient;
 | 
			
		||||
import com.test.service.client.UserClient;
 | 
			
		||||
import io.seata.spring.annotation.GlobalTransactional;
 | 
			
		||||
import org.springframework.stereotype.Service;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Resource;
 | 
			
		||||
@@ -38,7 +36,6 @@ public class BorrowServiceImpl implements BorrowService {
 | 
			
		||||
    BookClient bookClient;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @SentinelResource(value = "details", blockHandler = "blocked")
 | 
			
		||||
    public UserBorrowDetail getUserBorrowDetailByUid(int uid) {
 | 
			
		||||
        List<Borrow> borrow = mapper.getBorrowsByUid(uid);
 | 
			
		||||
        User user = userClient.getUserById(uid);
 | 
			
		||||
@@ -49,8 +46,26 @@ public class BorrowServiceImpl implements BorrowService {
 | 
			
		||||
        return new UserBorrowDetail(user, bookList);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //替代方案,注意参数和返回值需要保持一致,并且参数最后还需要额外添加一个BlockException
 | 
			
		||||
    public UserBorrowDetail blocked(int uid, BlockException e) {
 | 
			
		||||
        return new UserBorrowDetail(null, Collections.emptyList());
 | 
			
		||||
    @Override
 | 
			
		||||
    @GlobalTransactional
 | 
			
		||||
    public boolean doBorrow(int uid, int bid) {
 | 
			
		||||
        //1. 判断图书和用户是否都支持借阅
 | 
			
		||||
        if(bookClient.bookRemain(bid) < 1)
 | 
			
		||||
            throw new RuntimeException("图书数量不足");
 | 
			
		||||
        if(userClient.userRemain(uid) < 1)
 | 
			
		||||
            throw new RuntimeException("用户借阅量不足");
 | 
			
		||||
        //2. 首先将图书的数量-1
 | 
			
		||||
        if(!bookClient.bookBorrow(bid))
 | 
			
		||||
            throw new RuntimeException("在借阅图书时出现错误!");
 | 
			
		||||
        //3. 添加借阅信息
 | 
			
		||||
        if(mapper.getBorrow(uid, bid) != null)
 | 
			
		||||
            throw new RuntimeException("此书籍已经被此用户借阅了!");
 | 
			
		||||
        if(mapper.addBorrow(uid, bid) <= 0)
 | 
			
		||||
            throw new RuntimeException("在录入借阅信息时出现错误!");
 | 
			
		||||
        //4. 用户可借阅-1
 | 
			
		||||
        if(!userClient.userBorrow(uid))
 | 
			
		||||
            throw new RuntimeException("在借阅时出现错误!");
 | 
			
		||||
        //完成
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,17 +17,23 @@ spring:
 | 
			
		||||
        # 将ephemeral修改为false,表示非临时实例(用于持续监控)
 | 
			
		||||
        ephemeral: false
 | 
			
		||||
        cluster-name: Chengdu
 | 
			
		||||
        namespace: dd668135-0bfe-489f-ab2b-24aefb21d156
 | 
			
		||||
    loadbalancer:
 | 
			
		||||
      nacos:
 | 
			
		||||
        enabled: true
 | 
			
		||||
    sentinel:
 | 
			
		||||
      transport:
 | 
			
		||||
        # 添加监控页面地址即可
 | 
			
		||||
        dashboard: localhost:8858
 | 
			
		||||
      # 关闭Context收敛,这样被监控方法可以进行不同链路的单独控制
 | 
			
		||||
      web-context-unify: false
 | 
			
		||||
      block-page: /blocked
 | 
			
		||||
feign:
 | 
			
		||||
  circuitbreaker:
 | 
			
		||||
    enabled: true
 | 
			
		||||
seata:
 | 
			
		||||
  # 注册
 | 
			
		||||
  registry:
 | 
			
		||||
    # 使用Nacos
 | 
			
		||||
    type: nacos
 | 
			
		||||
    nacos:
 | 
			
		||||
      # 使用Seata的命名空间,这样才能正确找到Seata服务,由于组使用的是SEATA_GROUP,配置默认值就是,就不用配了
 | 
			
		||||
      namespace: c0495138-b5b3-440d-8f1c-dc8cc9ba5fbc
 | 
			
		||||
      username: nacos
 | 
			
		||||
      password: nacos
 | 
			
		||||
  # 配置
 | 
			
		||||
  config:
 | 
			
		||||
    type: nacos
 | 
			
		||||
    nacos:
 | 
			
		||||
      namespace: c0495138-b5b3-440d-8f1c-dc8cc9ba5fbc
 | 
			
		||||
      username: nacos
 | 
			
		||||
      password: nacos
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user