Java中使用事务(注解实现)
Posted czxmp
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中使用事务(注解实现)相关的知识,希望对你有一定的参考价值。
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不支持数据)
java笔记java中@Transactional注解的使用及其失效情景
本文转自文章一口气说出 6种,@Transactional注解的失效场景。
一、事务
spring中的事务管理机制可以分为编程式事务和声明式事务两种。
- 编程式事务:指在代码中手动的管理事务的提交、回滚等操作,代码侵入性比较强。
- 声明式事务: 基于AOP面向切面的,它将具体业务与事务处理部分解耦,代码侵入性很低,所以在实际开发中声明式事务用的比较多。声明式事务也有两种实现方式,是基于TX和AOP的xml配置文件方式,二种就是基于
@Transactional
注解了。
二、@Transactional注解
1. 用法
@Transactional
注解可以作用在类、接口、方法上。
- 作用于类:表示该类的所有public方法都配置了事务。
- 作用于接口:不推荐这种使用方法,因为一旦标注在Interface上并且配置了Spring AOP 使用CGLib动态代理,将会导致@Transactional注解失效。
- 作用于方法:当类配置了@Transactional,方法也配置了@Transactional,方法的事务会覆盖类的事务配置信息。
2. @Transactional的属性
(1) propagation属性
表示事务的传播行为,其取值如下:
Propagation.REQUIRED
:如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务。 为默认值。Propagation.SUPPORTS
:如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行。Propagation.MANDATORY
:如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常。Propagation.REQUIRES_NEW
:重新创建一个新的事务,如果当前存在事务,暂停当前的事务。Propagation.NOT_SUPPORTED
:以非事务的方式运行,如果当前存在事务,暂停当前的事务。Propagation.NEVER
:以非事务的方式运行,如果当前存在事务,则抛出异常。Propagation.NESTED
:和Propagation.REQUIRED
效果一样。
(2) isolation属性
表示事务的隔离级别,其取值如下:
solation.DEFAULT
:使用底层数据库默认的隔离级别。为默认值。Isolation.READ_UNCOMMITTED
:未提交读。Isolation.READ_COMMITTED
:提交读。Isolation.REPEATABLE_READ
:可重复读。Isolation.SERIALIZABLE
:序列化。
(3) timeout属性
事务的超时时间,默认为-1。如果超过该时间限制但事务还没有完成,则自动回滚事务。
(4) readOnly属性
指定事务是否为只读事务,默认值为false,当为true时可以忽略那些不需要事务的方法,如读取数据。
(5) rollbackFor属性
用于指定能够触发事务回滚的异常类型,可以指定多个异常类型。
(6) noRollbackFor属性
抛出指定的异常类型,不回滚事务,可以指定多个异常类型。
3. @Transactional失效的场景
(1) 应用在非public 方法上时
protected
、private
修饰的方法上使用@Transactional
注解,虽然事务无效,但不会有任何报错。
(2) propagation属性设置错误
若是错误的配置以下三种 propagation,事务将不会发生回滚:
Propagation.SUPPORTS
:如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行。Propagation.NOT_SUPPORTED
:以非事务的方式运行,如果当前存在事务,暂停当前的事务。Propagation.NEVER
:以非事务的方式运行,如果当前存在事务,则抛出异常。
(3) rollBackFor属性设置错误
Spring默认抛出了未检查unchecked异常(继承自 RuntimeException 的异常)或者 Error才回滚事务;其他异常不会触发回滚事务。如果在事务中抛出其他类型的异常,但却期望 Spring 能够回滚事务,就需要指定rollbackFor属性。
(4) 调用同一个类中的方法时
如果类中的方法A()调用同一个类中的方法B(),且方法A()没有声明事务,而方法B()声明了事务,那么在外部调用方法A()时,方法B()的事务是无效的。
这是由于使用Spring AOP代理造成的,因为只有当事务方法被当前类以外的代码调用时,才会由Spring生成的代理对象来管理。
(5) 异常被catch捕获导致注解失效
在方法A()上加了@Transactional注解,同时A()方法中调用方法B(),若方法B()抛出的异常被A()方法的catch捕获时,事务将不能正常回滚。
处理方法为:在catch块中再把注解中指定的异常抛出,若没指定异常,则可以抛出throw new RuntimeException()
。或者直接不用try-catch代码块。
(6) 数据库引擎不支持事务
常用的MySQL数据库默认使用支持事务的innodb引擎。一旦数据库引擎切换成不支持事务的myisam,那事务就从根本上失效了。
以上是关于Java中使用事务(注解实现)的主要内容,如果未能解决你的问题,请参考以下文章
Java开发Spring之AOP详解(xml--注解->方法增强事务管理(声明事务的实现))
java笔记java中@Transactional注解的使用及其失效情景
spring中声明式事务 配置好后,在java代码中怎么使用