service服務層中常常會出現各類其餘服務的依賴調用,特別是在寫操做相關場景下。mysql
場景 程序員
分析spring
spirng中事務的控制處理基於代理模式,而代理模式能夠略分爲三種sql
spring內部的代理採用的式JDK動態代理 + Cglib代理springboot
簡單來講,若是實現了某個接口,那麼Spring就選擇JDK代理(不必定),若是沒有,那麼就選擇CGLIB代理,提及來簡單,Spring還會鬧脾氣,不代理呢(如上圖使用事務的場景)mybatis
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
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'
@SpringBootApplication @EnableTransactionManagement // 開啓事務 @EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true) // 處理事務問題,如類中非事務方法A調用事務方法B public class BaseTransactionApplication { public static void main(String[] args) { SpringApplication.run(BaseTransactionApplication.class, args); } }
@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 @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("員工建立失敗"); } } }