Java中使用事务(注解实现)

Posted czxmp

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中使用事务(注解实现)相关的知识,希望对你有一定的参考价值。

Java中使用事务(注解实现)

事务的介绍

描述: 对于一个功能实现或者业务流程,要么全做,要么全不做!
特性: ACID

  1. A - 原子性:执行的最小单位,要么全做,要么全不做。(undo-log保证)
  2. C - 一致性:事务执行前后,数据库中的数据保持一致。(不一致:丢失修改、脏读、不可重复读、幻读)
  3. I - 隔离性:多个并发的事物之间是相互隔离的。
  4. 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的区别!

  1. myisam只有表级锁,innodb可以支持表级锁和行级锁(默认行级锁)。
  2. myisam强调查询性能,查询操作比innodb快,但是不提供事务支持。innodb提供事务、外键等高级功能,同时具有事务、回滚、崩溃修复能力。
  3. myisam不支持外键,innodb支持外键。
  4. 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 方法上时

protectedprivate修饰的方法上使用@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代码中怎么使用

Java--SpringBoot使用@Transactional注解添加事务

推荐学java——Spring事务

推荐学java——Spring事务