Java中使用事务(注解实现)
事务的介绍
描述: 对于一个功能实现或者业务流程,要么全做,要么全不做!
特性: ACID
- A - 原子性:执行的最小单位,要么全做,要么全不做。(undo-log保证)
- C - 一致性:事务执行前后,数据库中的数据保持一致。(不一致:丢失修改、脏读、不可重复读、幻读)
- I - 隔离性:多个并发的事物之间是相互隔离的。
- D - 持久性:事务对数据的修改是永久性的。(redo-log保证)
第一步: 引入依赖
<!-- 项目启动依赖 @Service @Component @RestController tomcat等等 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
第二步:Java代码
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class HelperService {
@Resource
private TaskDao taskDao;
@Resource
private TaskDetailDao taskDetailDao;
// isolation:事务的隔离级别,此处使用后端数据库的默认隔离级别, propagation: 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中(常见)。
@Transactional(rollbackFor = Exception.class, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED)
public void test(Task task, TaskDetail taskDetail){
taskDao.saveTask(task);
int a = 3 / 0;
taskDetailDao.saveTaskDetail(taskDetail);
}
}
补充事务的传播行为
常用的事务传播行为: Propagation.REQUIRED或者Propagation.REQUIRES_NEW
补充事务的隔离级别
(1)DEFAULT
使用数据库设置的隔离级别(默认),由DBA 默认的设置来决定隔离级别。
(2)READ_UNCOMMITTED
这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。
会出现脏读、不可重复读、幻读 (隔离级别最低,并发性能高)。
(3)READ_COMMITTED
保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。
可以避免脏读,但会出现不可重复读、幻读问题(锁定正在读取的行)。
(4)REPEATABLE_READ(innodb默认的数据库隔离级别)
可以防止脏读、不可重复读,但会出幻读(锁定所读取的所有行)。
(5)SERIALIZABLE
这是花费最高代价但是最可靠的事务隔离级别,事务被处理为顺序执行。
保证所有的情况不会发生(锁表)。
注意:myisam与innodb的区别!
- myisam只有表级锁,innodb可以支持表级锁和行级锁(默认行级锁)。
- myisam强调查询性能,查询操作比innodb快,但是不提供事务支持。innodb提供事务、外键等高级功能,同时具有事务、回滚、崩溃修复能力。
- myisam不支持外键,innodb支持外键。
- MVCC支持:仅有innodb支持MVCC,同时MVCC只在READ_COMMITTED和REPEATABLE_READ这两个隔离级别下工作。【MVCC:多版本并发控制,使不同事务的读写操作并发执行,提升系统性能。】
第三部: 启动类增加注解
注意一定要启动类开启注解
// 开启注解
@EnableTransactionManagement
补充:事务失效的常见原因
1、 @Transactional
必须作用于public方法之上;
2、 @Transactional
注解的属性rollbackFor 配置错误,默认只有RuntimeException才会回滚;
3、 启动类没有添加@EnableTransactionManagement
4、 同一个类中调用事务方法,事务会失效。
@Service
public class A{
public void test01(){
// do something
test02();
// do something
}
@Transactional(rollbackFor = Exception.class, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED)
public void test02(){
// do something (操作多个表的增删改)
}
}
5、 异常被捕获了:在事务方法中捕获了异常,事务会失效;
6、 数据库引擎不支持事务;(常见数据库引擎:innodb、bdb支持事务,myisam不支持数据)