自助建网站平台,在学做网站还不知道买什么好,建筑工程有限公司起名大全,庐阳网站快速排名一、什么是事务管理
事务是一个最小的不可再分的工作单元。 一个事务对应一套完整的业务操作。事务管理是指这些操作要么全部成功执行#xff0c;要么全部回滚#xff0c;从而保证数据的一致性和完整性。比如银行转账#xff0c;需要保证转出和转入是一个原子操作。Spring提…一、什么是事务管理
事务是一个最小的不可再分的工作单元。 一个事务对应一套完整的业务操作。事务管理是指这些操作要么全部成功执行要么全部回滚从而保证数据的一致性和完整性。比如银行转账需要保证转出和转入是一个原子操作。Spring提供了声明式和编程式两种事务管理方式。
二、Spring编程式事务管理
Spring框架提供了专门用于事务管理的API。要使用Spring实现事务管理需要引入spring-tx依赖
首先在pom.xml文件中引入spring-tx依赖
!--spring-tx依赖--
dependencygroupIdorg.springframework/groupIdartifactIdspring-tx/artifactIdversion6.1.8/version
/dependency其中有三个核心接口
PlatformTransactionManager.classTransactionDefinitionn.classTransactionStatus.class
PlatformTransactionManager接口
PlatformTransactionManager 接口是 Spring 提供的平台事务管理器主要用于管理事务。该接口中提供了三个事务操作的方法。
TransactionStatus getTransaction(TransactionDefinition definition); 用于获取事务以及状态信息void commit(TransactionStatus status); 用于提交事务void rollback(TransactionStatus status); 用于回滚事务
PlatformTransactionManager 接口只是代表事务管理的接口并不知道底层是如何管理事务的具体如何管理事务则由它的实现类来完成。该接口常见的几个实现类如下
TransactionDefinition接口
TransactionDefinition 接口是事务定义描述的对象该对象中定义了事务基本属性并提供了获取事务基本属性的方法具体如下
String getName( ); ---------- 获取事务对象名称int getIsolationLevel( ); ---------- 获取事务的隔离级别int getPropagationBehavior( ); ---------- 获取事务的传播行为int getTimeout( ); ---------- 获取事务的超时时间boolean isReadOnly( ); ---------- 获取事务是否只读
事务的传播行为
当事务方法被另一个事务方法调用时必须指定事务应该如何传播。Spring定义了七种传播行为。
事务的隔离级别
定义了一个事务可能受其他并发事务的影响程度。多个事务并发运行经常会操作相同的数据来完成各自的任务可能会出现脏读不可重复读和幻读的问题。隔离级别有四种。
脏读一个事务读取到了另一个事务未提交的数据不可重复读同一个事务内多次读取同一数据,但前后两次读取的结果不一致。由其他事务的更新操作造成。幻读同一个事务内多次查询记录数量,但前后两次查询的结果不一致。由其他事务的插入或删除操作造成。
是否只读
如果一个方法内都是对数据库的select操作那么可以设置方法事务为只读数据库也会对该事务进行特定的优化。只读事务内不能有insert、update、delete的操作。
事务超时
事务可能涉及对后端数据库的锁定所以长时间的事务运行会不必要的占用数据库资源设置事务超时时间可以及时释放资源。
默认实现类DefaultTransactionDefinition
DefaultTransactionDefinition 是 Spring 提供的 TransactionDefinition 接口的默认实现类
SuppressWarnings(serial)
public class DefaultTransactionDefinition implements TransactionDefinition, Serializable {private int propagationBehavior PROPAGATION_REQUIRED; // 必须使用事务private int isolationLevel ISOLATION_DEFAULT; //数据库默认隔离级别可重复读private int timeout TIMEOUT_DEFAULT; // 永不超时private boolean readOnly false; // 不是只读// 其他省略
}TransactionStatus接口
TransactionStatus 接口是事务的状态它描述了某一时间点上事务的状态信息。该接口中包含6个方法具体如下
void flush(); ---------- 刷新事务boolean hasSavepoint(); ---------- 获取是否存在保存点boolean isCompleted(); ---------- 获取事务是否完成boolean isNewTransaction(); ---------- 获取是否为新事务boolean isRollbackOnly(); ---------- 获取事务是否回滚void setRollbackOnly(); ---------- 设置事务回滚
1.在配置文件中配置事务管理器组件
spring-mybatis.xml !-- 配置事务管理器 --bean idtxManager classorg.springframework.jdbc.datasource.DataSourceTransactionManagerproperty namedataSource refdataSource//bean2.在业务逻辑组件方法中使用事务管理器组件实现事务管理功能
// 以添加学生信息为例,需要同时往学生表和学生证表插入数据
Service
public class StudentService {Autowiredprivate StudentMapper studentMapper;Autowiredprivate StudentCardMapper studentCardMapper;Autowiredprivate PlatformTransactionManager transactionManager;public void addStudent(StudentParam param) {// 1.定义事务属性DefaultTransactionDefinition def new DefaultTransactionDefinition();// 可以设置事务的隔离级别、传播行为等def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);// 2.获取事务状态TransactionStatus status transactionManager.getTransaction(def);try {// 3.执行业务逻辑Student student BeanUtil.copyProperties(param, Student.class);studentMapper.insertStudent(student);StudentCard card BeanUtil.copyProperties(param, StudentCard.class);card.setStuId(student.getStuId());studentCardMapper.insertStudentCard(card);// 4.提交事务transactionManager.commit(status);} catch (Exception e) {// 5.异常回滚transactionManager.rollback(status);throw new RuntimeException(添加学生信息失败, e);}}
}三、Spring声明式事务管理
Spring声明式事务管理最大的优点在于开发者无需通过编程的方式来管理事务只需在配置文件中进行相关的事务规则声明就可以将事务应用到业务逻辑中。在实际开发中通常都推荐使用声明式事务管理。 Spring声明式事务管理通过AOP技术实现的事务管理主要思想是将事务作为一个“切面”代码单独编写然后通过AOP技术将事务管理的“切面”植入到业务目标类方法中。 Spring的声明式事务管理可以通过两种方式来实现
基于XML方式基于注解方式
首先在pom.xml文件中引入AOP切面依赖 !-- AOP --dependencygroupIdorg.springframework/groupIdartifactIdspring-aspects/artifactIdversion6.1.8/version/dependencyXML配置方式
1. 在Spring配置文件中配置事务管理器
spring-mybatis.xml
!-- 配置事务管理器 --
bean idtxManager classorg.springframework.jdbc.datasource.DataSourceTransactionManagerproperty namedataSource refdataSource/
/bean2.使用tx:advice标签配置事务规则
spring-mybatis.xml
!-- 配置事务通知 --
!-- id表示唯一标识 transaction-manager表示关联的事务管理器--
tx:advice idtxAdvice transaction-managertxManagertx:attributes!-- 定义哪些方法需要进行事务处理*表示任意字符比如find*表示以find开头的方法 --!-- 查询方法:只读事务 --tx:method nameget* read-onlytrue/tx:method namefind* read-onlytrue/tx:method nameselect* read-onlytrue/!-- 增删改方法:读写事务 --tx:method nameadd* propagationREQUIRED isolationREAD_COMMITTED/tx:method namesave* propagationREQUIRED isolationREAD_COMMITTED/tx:method nameupdate* propagationREQUIRED isolationREAD_COMMITTED/tx:method namedelete* propagationREQUIRED isolationREAD_COMMITTED//tx:attributes
/tx:adviceattributes(属性) name 指定对哪些方法起作用propagation 指定事务的传播行为isolation 指定事务的隔离级别read-only 指定事务是否只读timeout 指定事务超时的时间rollback-for 指定异常回滚no-rollback-for 指定异常不回滚 3. 使用aop:config配置事务切面通过aop:pointcut配置切点通过aop:advisor标签配置切点执行的事务规则
spring-mybatis.xml
!-- 配置事务切面 --
!-- 定义切面 --
aop:config!-- 定义切点 --aop:pointcut idtxPointcut expressionexecution(* com.cg.service.*.*(..))/!-- 在指定的切点上应用事务规则 --!-- advice-ref关联事务规则 pointcut-ref关联切点 --aop:advisor advice-reftxAdvice pointcut-reftxPointcut/
/aop:config注解方式
基于注解方式实现是通过使用Transactional注解来实现方法的事务管理功能
1. 在Spring配置文件中配置事务管理器
spring-mybatis.xml
!-- 配置事务管理器 --
bean idtxManager classorg.springframework.jdbc.datasource.DataSourceTransactionManagerproperty namedataSource refdataSource/
/bean2. 在Spring容器中注册事务注解驱动
!--注册事务注解驱动--tx:annotation-driven transaction-managertxManager/3.在需要事务管理的类或方法上使用Transactional注解
使用Transactional注解时可以通过参数配置具体事务属性
四、事务传播行为详解
通过实际案例理解事务传播行为:
REQUIRED(默认)
如果当前没有事务,就创建一个新事务;如果已经存在一个事务,就加入到这个事务中。
Service
public class AService {Autowired private BService bService;Transactional(propagation Propagation.REQUIRED)public void methodA() {// methodA开启事务1insert(A);// methodB加入事务1bService.methodB(); // 如果这里抛异常,整个事务都会回滚}
}Service
public class BService {Transactional(propagation Propagation.REQUIRED)public void methodB() {// 加入methodA的事务1insert(B);throw new RuntimeException(); // 异常导致整个事务1回滚}
}
REQUIRES_NEW
总是会开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
Service
public class AService {Autowiredprivate BService bService;Transactional(propagation Propagation.REQUIRED)public void methodA() {// methodA开启事务1insert(A); // 这条数据会插入成功try {// methodB开启新事务2,事务1被挂起bService.methodB();} catch (Exception e) {// methodB事务2回滚,事务1不受影响}}
}Service
public class BService {Transactional(propagation Propagation.REQUIRES_NEW)public void methodB() {insert(B1); // 这条数据会回滚int i 1/0; // 抛出异常insert(B2); // 不会执行}
}
NESTED
如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则创建一个新事务。
Service
public class AService {Transactional(propagation Propagation.REQUIRED)public void methodA() {// 外部事务insert(A); // 这条数据会保存try {// 内部嵌套事务methodB();} catch (Exception e) {// 内部事务回滚,外部事务可以正常提交}}Transactional(propagation Propagation.NESTED)public void methodB() {insert(B); // 这条数据会回滚throw new RuntimeException();}
}
SUPPORTS
如果当前有事务就加入,没有就以非事务方式执行。
Service
public class AService { Transactional(propagation Propagation.REQUIRED)public void methodA() {// 有事务methodB(); // methodB会加入当前事务}public void methodC() {// 无事务调用methodB(); // methodB以非事务方式执行}
}Service
public class BService {Transactional(propagation Propagation.SUPPORTS)public void methodB() {// 有事务就用事务,没有就不用insert(B);}
}
NOT_SUPPORTED
总是以非事务方式执行,如果当前有事务则挂起。
Service
publicclass AService {Transactional(propagation Propagation.REQUIRED)public void methodA() {insert(A); // 在事务中执行methodB(); // 挂起当前事务,以非事务方式执行}Transactional(propagation Propagation.NOT_SUPPORTED)public void methodB() {// 总是以非事务方式执行insert(B); // 即使外部有事务也以非事务方式执行}
}
MANDATORY
必须在一个已有事务中执行,否则抛异常。
Service
public class AService {Transactional(propagation Propagation.REQUIRED)public void methodA() {methodB(); // 正常执行,因为当前有事务}public void methodC() {methodB(); // 抛出异常,因为没有事务}
}Service
public class BService {Transactional(propagation Propagation.MANDATORY)public void methodB() {// 必须在一个已有事务中执行insert(B);}
}
NEVER
总是以非事务方式执行,如果当前有事务就抛异常
Service
public class Aervice {Transactional(propagation Propagation.REQUIRED)public void methodA() {methodB(); // 抛出异常,因为当前有事务}public void methodC() {methodB(); // 正常执行,因为没有事务}Service
public class BService {Transactional(propagation Propagation.NEVER)public void methodB() {// 必须在非事务环境下执行insert(B);}
}