spring - 事务管理源码分析
1,关于事务的案例分析
下单成功 --> 修改库存
提出问题:
1,实现原理?
aop -》 动态代理
2,spring如何控制事务的的提交与回滚?
3,有哪些不同类型的事务传播属性?分别有什么效果?
2,spring事务管理的实现原理
3,spring事务管理的传播属性
事务挂起是什么意思?
新建事务 与 嵌套事务的区别?
新建事务:使用 @transactional 时传播属性设置为 required_new 时
如果不想让内部事务影响外部事务,需要在内部事务的方法里面进行 try。。catch。。,但是 try。。catch。。后如果异常发生在SQL语句之后,内部事务是不会回滚的。
嵌套事务:
MySQL的事务
嵌套事务的内部事务是不影响外部事务的,当内部事务出现异常时,会把整个保存点抹除;但是嵌套事务的外部事务会影响内部事务,当外部事务发生异常时整个事务下的SQL都会回滚。
4,通过源码理解事务管理的存在
org.springframework.aop.framework.CglibAopProxy
retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();
org.springframework.aop.framework.ReflectiveMethodInvocation
proceed(){
// ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
org.springframework.transaction.interceptor.TransactionInterceptor
invoke(){
invokeWithinTransaction(){
org.springframework.transaction.interceptor.TransactionAspectSupport
invokeWithinTransaction(){
createTransactionIfNecessary(){
// 父类 org.springframework.transaction.support.AbstractPlatformTransactionManager
tm.getTransaction(){
// 判断不同的传播属性
// 执行正在的业务方法
invocation.proceedWithInvocation()
}
}
}
}
}
}
5,事务的总结
代码示例:
依赖:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
entity:
package com.test.spring.transaction.entity;
import lombok.Data;
@Data
public class Order {
private Integer orderId;
private Integer productId;
private String customer;
private Integer number;
private Integer status;
}
mapper
package com.test.spring.transaction.mapper;
import com.test.spring.transaction.entity.Order;
import org.apache.ibatis.annotations.Insert;
import org.springframework.stereotype.Repository;
@Repository
public interface OrderMapper {
int inster(Order order);
}
package com.test.spring.transaction.mapper;
import com.test.spring.transaction.entity.Order;
import org.springframework.stereotype.Repository;
@Repository
public interface ProductMapper {
int update(Order order);
}
service
package com.test.spring.transaction.service;
import com.test.spring.transaction.entity.Order;
public interface IOrderService {
int shopping(Order order);
}
package com.test.spring.transaction.service;
import com.test.spring.transaction.entity.Order;
public interface IProductService {
int updateProduct(Order order);
}
package com.test.spring.transaction.service;
import com.test.spring.transaction.entity.Order;
import com.test.spring.transaction.mapper.OrderMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class OrderServiceImpl implements IOrderService{
@Autowired
private OrderMapper orderMapper;
@Autowired
private IProductService productService;
@Override
@Transactional(rollbackFor = Exception.class)
public int shopping(Order order) {
System.out.println("==================>进入shopping方法");
// 下单,插入数据到order表中
int row = orderMapper.inster(order);
// 更新库存数量
productService.updateProduct(order);
System.out.println("==================>完成shopping方法");
return row;
}
}
package com.example.mytransaction.service;
import com.example.mytransaction.entity.Order;
import com.example.mytransaction.mapper.ProductMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class ProductServiceImpl implements IProductService {
@Autowired
private ProductMapper productMapper;
@Override
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
public int updateProduct(Order order) {
System.out.println("==================>进入updateProduct方法");
int row = 0;
try {
// 更新库存数量
row = productMapper.update(order);
// 在SQL语句执行之后报错时,不会回滚。
int i = 1/0;
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("==================>完成updateProduct方法");
return row;
}
}
test 类
package com.test;
import com.test.spring.transaction.service.IOrderService;
import com.test.spring.transaction.entity.Order;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@SpringBootTest
@RunWith(SpringJUnit4ClassRunner.class)
public class TransactionTest {
@Autowired
private IOrderService orderService;
@Test
public void test(){
System.out.println("==================>进入test方法");
Order order = new Order();
order.setProductId(100);
order.setCustomer("张三");
order.setNumber(1);
// 调用shopping方法之前,调用了springaop 事务管理器去完成事务的初始化
orderService.shopping(order);
System.out.println("==================>进入test方法");
}
}
数据库表结构
CREATE TABLE `temp_order` (
`product_Id` int(11) DEFAULT NULL COMMENT '产品类型编号',
`customer` varchar(255) DEFAULT NULL COMMENT '购买用户',
`number` int(11) DEFAULT NULL COMMENT '购买数量',
`order_id` int(11) NOT NULL AUTO_INCREMENT,
`status` int(11) DEFAULT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4;
CREATE TABLE `temp_product` (
`product_id` int(11) NOT NULL,
`product_name` varchar(255) DEFAULT NULL,
`product_count` int(11) DEFAULT NULL,
PRIMARY KEY (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
配置文件
server:
port: 8080
spring:
datasource:
username: cNkTl4FnJuGl3AXMOsxnW81YKyVZEMl7
password: cNkTl4FnJuGl3AXMOsxnW81YKyVZEMl7
url: jdbc:mysql://10.5.6.129:3306/contract_manage?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
driver-class-name: com.mysql.jdbc.Driver
mybatis:
mapper-locations: classpath:mapping/*Mapper.xml
启动类上添加
@MapperScan("com.example.mytransaction.mapper")