service事務失效(接口方法A調用類方法B)

1.問題點

service服務層中常常會出現各類其餘服務的依賴調用,特別是在寫操做相關場景下。mysql

  • 場景 tx_1程序員

  • 分析spring

spirng中事務的控制處理基於代理模式,而代理模式能夠略分爲三種sql

  • JDK靜態代理(靈活性差,排除)
  • JDK動態代理(基於接口)
  • Cglib代理(基於類)

spring內部的代理採用的式JDK動態代理 + Cglib代理springboot

簡單來講,若是實現了某個接口,那麼Spring就選擇JDK代理(不必定),若是沒有,那麼就選擇CGLIB代理,提及來簡單,Spring還會鬧脾氣,不代理呢(如上圖使用事務的場景)mybatis

2.案例解決

  • 案例表
CREATE TABLE `dep` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
    `dep_name` varchar(255) NOT NULL COMMENT '部門名稱',
    `description` varchar(255) DEFAULT NULL COMMENT '描述',
    PRIMARY KEY (`id`),
    UNIQUE KEY `uk_depname` (`dep_name`)
  ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;

  CREATE TABLE `emp` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
    `emp_name` varchar(255) NOT NULL COMMENT '名稱',
    `dep_id` bigint(20) NOT NULL COMMENT '部門Id',
    `status` varchar(255) NOT NULL DEFAULT '1' COMMENT '狀態 1.有效,2.無效',
    `description` varchar(255) DEFAULT NULL COMMENT '描述',
    PRIMARY KEY (`id`),
    UNIQUE KEY `uk_name` (`emp_name`) USING BTREE
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

  CREATE TABLE `task` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
    `task_name` varchar(255) NOT NULL,
    `task_status` varchar(255) NOT NULL DEFAULT '0' COMMENT '任務狀態 0:進行中 1:成功 -1:失敗',
    PRIMARY KEY (`id`)
  ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
  • 基礎代碼

可基於mybatis-plus進行基礎代碼等生成(此處略)app

  • 配置(基於springboot + mybatis-plus)
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/tx_demo?useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false
    username: root
    password: root
    druid:
      # 初始化大小,最小,最大
      initial-size: 10
      min-idle: 10
      maxActive: 20
      # 配置獲取鏈接等待超時的時間
      maxWait: 60000
      # 配置間隔多久才進行一次檢測,檢測須要關閉的空閒鏈接,單位是毫秒
      timeBetweenEvictionRunsMillis: 60000
      # 配置一個鏈接在池中最小生存的時間,單位是毫秒
      minEvictableIdleTimeMillis: 300000
      validationQuery: SELECT 1 FROM DUAL
mybatis-plus:
  mapper-locations: classpath:mappers/*Mapper.xml
  typeAliasesPackage: com.base.transaction.model
  global-config:
    id-type: 0
    field-strategy: 1
    db-column-underline: true
  configuration:
    map-underscore-to-camel-case: true
    cache-enabled: false
    jdbc-type-for-null: 'null'
  • springboot項目啓動類
@SpringBootApplication
  @EnableTransactionManagement // 開啓事務
  @EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true) // 處理事務問題,如類中非事務方法A調用事務方法B
  public class BaseTransactionApplication {

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

  }
  • controller代碼
@RestController
  @RequestMapping("/task")
  @Slf4j
  public class TaskController {

      @Autowired
      private TaskService taskService;

      @GetMapping("/add")
      public void addTask() {

          Task task = new Task();
          task.setTaskName(String.valueOf(new Random().nextInt(100)));

          taskService.save(task);

          log.info("task create success");

          // 更新任務狀態
          taskService.insertDepAndEmpTask(task.getId());
      }
  }
  • service代碼
@Service
  @Slf4j
  public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements TaskService {

      @Autowired
      private EmpService empService;

      @Autowired
      private DepService depService;

      @Autowired
      private TaskMapper taskMapper;

      @Override
      public void insertDepAndEmpTask(Long taskId) {
          try {
              ((TaskServiceImpl)AopContext.currentProxy()).insertDepAndEmp();

              Task task = new Task();
              task.setId(taskId);
              task.setTaskStatus("1");
              taskMapper.updateById(task);
              log.info("update task status success");
          } catch (Exception e) {
              Task task = new Task();
              task.setId(taskId);
              task.setTaskStatus("-1");
              taskMapper.updateById(task);
              log.info("update task status failed");
              //TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
              e.printStackTrace();
          }
      }

      @Transactional//(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
      public void insertDepAndEmp() {
          Dep dep = new Dep();
          dep.setDepName("技術部" + new Random().nextInt(100));
          dep.setDescription("這是一羣屌絲的天下");

          // 1.建立部門
          boolean depSave = depService.save(dep);
          if (!depSave) {
              throw new RuntimeException("部門建立失敗");
          }

          dep.setId(null);

          Emp emp = new Emp();
          emp.setDepId(dep.getId());
          emp.setEmpName("屌絲" + new Random().nextInt(100));
          emp.setDescription("我是一個屌絲程序員");

          // 2.建立員工
          boolean empSave = empService.save(emp);
          if (!empSave) {
              throw new RuntimeException("員工建立失敗");
          }
      }
  }
相關文章
相關標籤/搜索