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("员工建立失败"); } } }