#CSDN 年度征文|回顾 2023,赢专属铭牌等定制奖品#
目录
(1)事务是一组操作的集合,它会把所有的操作作为一个整体一起向数据库提交或者撤销操作请求,它是一个不可分割的工作单位,这些操作要么同时成功,要么同时失败。
(2)运用场景:
? 假设现在有两张数据库表,type(图片分类)和picture(图片),两张表中分别存有数据。现在有一个需求:删除图片分类为风景这个类型,且删除该分类下的所有图片。
? 假设这个需求分两步完成:1)删除type表中风景这个分类;2)删除picture表中type_id=1的这些图片。如果完成第一步操作的时候成功了,但是在完成第二步的时候失败了。在没有使用事务的情况下,数据库中的数据就会不一致。因为在type表中风景这个图片分类删除成功,但是picture表中属于type_id=1的这个分类的图片没有被删除,造成了数据不一致?。因此,对数据库中的数据有修改的一些连续操作,需要将他们放到一个事务中来确保数据库里面的数据一致。当这些操作都成功时,提交事务(分类及所属该分类的图片都成功在数据库中删除);当这些操作中有一个操作没有成功,回滚事务(数据库中的数据不会发生修改)。
id(主键) | name(名称) |
1 | 风景 |
2 | 萌宠 |
3 | 二次元 |
4 | 微信 |
id(主键) | type_id(分类id) | name(名称) |
1 | 1 | 风景1 |
2 | 1 | 风景2 |
3 | 2 | 萌宠1 |
4 | 2 | 萌宠2 |
5 | 3 | 二次元1 |
6 | 4 | 微信1 |
7 | 4 | 微信2 |
(1)开启事务:start transaction / begin;
一组操作开始前,开启事务。
(2)提交事务(这组数组全部成功后,提交事务):commit;
如果这组操作全部成功,就可以提交事物。
(3)回滚事务:rollback;
如果这组操作中有任何一个操作失败,就会回滚事物。
(1)使用模式:事务的使用模式都是下面三个步骤
1)开启事务
2)所进行的操作(比如:两个删除语句…………)
3)提交或回滚事物(比如:两个删除都成功就提交事物、其中任意一个删除失败就回滚事物)
(2)spring框架中已经封装好了事务的操作,所以不需要我们去实现,如果我们使用了spring框架,只需要通过一个注解@Transactional就可以完成事务的控制。
1)使用位置:业务(service)层的方法上、类上、接口上。
①将注解加到方法上:将该方法交给spring进行事务管理
②将注解加到类上:当前类中所有的方法都交给spring进行事务管理
③将注解加到接口上:这个接口下所有的实现类中的所有的方法都交给spring进行事务管理
一般加到业务层(service)执行多次数据访问的增删改操作的方法上,查询操作不会影响数据库中数据的变更,所以无需控制事务。如果业务中只是简单的增删改,也不需要控制事务。
2)作用:将当前方法交给spring进行事务管理,方法执行前,开启事务;成功执行完毕,提交事务;出现异常,回滚事务。
/**
* 删除分类及该分类下的图片数据
*/
@Transactional //事务管理
@Override
public void delete(Integer id) {
deptMapper.deleteById(id); //根据id删除图片分类
//出现异常,后面代码不执行
int i = 1/0; //运行时异常
//调用empmapper中的方法根据分类id删除图片的数据
empMapper.deleteByTypeId(id); //根据分类id删除该分类下的图片
}
在配置文件中加入该配置,事务相关日志会输出到控制台。
#spring事务管理日志
logging:
level:
org.springframework.jdbc.support.JdbcTransactionManager: debug
? 以下异常,虽然后面的删除操作没有执行,方法加了@Transactional注解,但是事务依然会提交,因为默认情况下,只有出现RuntimeException(运行时异常)才回滚事务,比如:int i = 1/0; 因此需要一个@Transactional 的属性来控制出现的异常,从而更好的进行事务回滚操作。
/**
* 删除分类及该分类下的图片数据
*/
@Transactional //事务管理
@Override
public void delete(Integer id) throws Exception {
deptMapper.deleteById(id); //根据id删除图片分类
//出现异常,后面代码不执行
//int i = 1/0; //运行时异常
if(true){ //此判断恒成立,无法执行后面的删除操作
throw new Exception("error………………");
}
//调用empmapper中的方法根据分类id删除图片的数据
empMapper.deleteByTypeId(id); //根据分类id删除该分类下的图片
}
(1)rollbackFor属性:用于控制出现何种异常类型,回滚事务。
(2)rollbackFor属性值:异常的类型。比如:Exception.class(所有的异常)
(3)在@Transactional?注解的属性中加入rollbackFor来指定出现何种异常回滚事物。比如:
//事务管理
@Transactional (rollbackFor = Exception.class) //所有的异常都会进行事务回滚
(1)事务传播行为:指当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制。
(2)比如:这里有两个事物方法,fun1() 和 fun2(),且都加了@Transactional注解,代表这两个方法都具有事务,在fun1方法中又调用了fun2方法。
? 事务的传播行为是指:在fun1方法运行的时候将会开启一个事物,然后在fun1方法中又调用了fun2方法,fun2方法也具有事务,那么fun2方法运行的时候是加入fun1方法的事务中还是fun2方法运行的时候新建一个新的事务,这就涉及到事务的传播行为。
1)fun1
import com.tliaswebmanagement.service.Fun1Service;
import com.tliaswebmanagement.service.Fun2Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class Fun1ServiceImpl implements Fun1Service {
@Autowired
private Fun2Service fun2Service;
@Transactional
@Override
public void fun1(){
//------------
fun2Service.fun2();
//------------
}
}
2)fun2?
import com.tliaswebmanagement.service.Fun2Service;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class Fun2ServiceImpl implements Fun2Service {
@Transactional(propagation= Propagation.REQUIRED)
@Override
public void fun2() {
//------------
}
}
(3)如果想控制事务的传播行为,就可以在@Transactional注解中指定一个属性:propagation,通过这个属性指定传播行为。
属性值 | 含义 |
REQUIRED | 【默认值】需要事务,有则加入,无则创建新事务 |
REQUIRES_NEW | 需要新事务,无论有无,总是创建新事务 |
SUPPORTS | 支持事务,有则加入,无则在无事务状态中运行 |
NOT_SUPPORTED | 不支持事务,在无事务状态下运行,如果当前存在已有事务,则挂起当前事务 |
MANDATORY | 必须有事务,否则抛异常 |
NEVER | 必须没事务,否则抛异常 |
……… | ……… |
使用方式:
@Transactional(propagation= Propagation.REQUIRED)