当前位置: 首页 > 图灵资讯 > 技术篇> java中的异常,Spring中Transactional说明以及@Aysc的使用

java中的异常,Spring中Transactional说明以及@Aysc的使用

来源:图灵教育
时间:2023-06-02 09:28:17

当我们开发代码时,当代码出现异常时,我们首先会想到事物回滚机制。我们在以前的工作中没有认真学习,导致了很多坑。现在我们记录下来,提高我们对@transactional事物的知识。

首先,我们需要了解一些关于异常的知识。

在程序运行过程中,不可预测的事件阻止了程序按照程序员的预期正常执行,这是不正常的。

Java提供了更好的解决方案:异常处理机制。

异常处理机制可以使程序根据代码预设的异常处理逻辑,尽可能恢复正常并继续执行,并保持代码清晰。 Java中的异常可能是由函数中的语句执行引起的,也可能是程序员通过throw 如果语句手动抛出,只要Java程序中出现异常,就会用相应类型的异常对象包装异常,JRE会试图找到异常处理程序来处理异常。

Throwable是Java异常类型的顶层父类,只有一个对象 Throwable 类别(直接或间接)的例子,他是一个可以被异常处理机制识别的异常对象。JDK中建立了一些常用的异常类别,我们也可以定制异常。

(1)Java异常分类

Throwable还衍生出Error类和Exception类。

错误:Error类和他的子类的例子代表了JVM本身的错误。程序员无法通过代码处理错误,Eror很少出现。因此,程序员应注意Exception作为父类分支下的各种异常类别。

异常:Exception及其子类代表程序运行过程中发送的各种意想不到的事件。Java异常处理机制可以使用,是异常处理的核心。

有些需要内部检查,有些不需要内部检查。

非检查异常(unckecked exception):Error 和 RuntimeException 以及他们的子类。在编译javac时,javac不会提示和发现这些异常,也不需要在程序中处理这些异常。因此,如果我们愿意,我们可以编写代码处理(使用try...catch…finally)这种异常,也可以不处理。对于这些异常,我们应该修改代码,而不是通过异常处理器处理 。这种异常的原因大多是代码写作有问题。例如,除0错误Arithmeticexception、错误强制类型转换错误Clascascastexception、数组索引越界Arrayindexoution、空对象Nulpointerexception等。

检查异常(checked exception):除了Error 和 Runtimeexception的其他异常。Javac强迫程序员为这种异常做准备(使用try...catch…finally或throws)。要么用try-catch语句捕获并处理,要么用throws声明抛出,否则编译不会通过。这种异常通常是由程序的运行环境引起的。由于程序可能在各种未知的环境中运行,程序员不能干预用户如何使用他编写的程序,程序员应该为这样一个不正常的时刻做好准备。如SQLException , IOException,ClassNotFoundException 等。

(2)异常处理的基本语法

编写代码处理异常时,检查异常有两种不同的处理方法:使用trycatch…finally语句块处理它。或者在函数签名中使用throws 声明交给函数调用器caller解决。

try…catch..finally语句块

try{     ///在try块中放异常代码。     //如果try执行后没有异常,请执行finaly块和finaly后面的代码(如果有的话)。     //如有异常,试着匹配catch块。 }catch(SQLException SQLexception){    ///每个catch块用于捕获和处理特定类型的异常或子类。一个catch可以在Java7中发表多个异常声明。    //catch后面的括号定义了异常类型和参数。若异常与之匹配,且是第一匹配,则虚拟机将使用此catch块来处理异常。    该块的异常参数可用于catch块获取异常相关信息。该catch块中的局部变量为异常参数,其它块无法访问。    ///如果当前try块中的异常没有在后续的所有catch中捕获,则先执行finally,然后在此函数的外部caller中匹配异常处理器。    //如果try中没有异常,所有catch块都将被忽略。 }catch(Exception exception){    //...}finally{     //finaly块通常是可选的。   finally将执行,无论异常是否发生,异常是否与处理相匹配。   //一个try至少要有一个catch块,否则, 至少要有一个finaly块。但是finally不是用来处理异常的,finally不会捕捉异常。  //finally主要做一些清洁工作,如关闭流量、关闭数据库连接等。 这一点需要特别注意 。}

throws 函数声明

throws声明:如果一种方法的内部代码会抛出异常检查(checked exception),如果方法本身没有完全处理,javac确保您必须在方法签名上使用throws关键字来声明这些可能抛出的异常,否则编译将失败。

throws是另一种处理异常的方法,它不同于try...catch…finally,throws只向调用者声明函数中可能出现的异常,而不具体处理。

这种异常处理的原因可能是方法本身不知道如何处理这种异常,或者让调用器处理得更好,调用器需要对可能的异常负责。

(3)自定义异常

以后细说。

上面提到了异常,接下来,让我们来了解一下事情。

@Transactional在Spring中的解释

事物管理有两种方式:

1:一是编程事务管理,需要取消数据库的自动提交,需要编写自己的事务代码

2:二是声明式事务管理模式,spring使用spring AOP特征编写注释,即标题中提到的管理事务的方式,以避免开发人员编写大量的事务代码。

(1)特性

让我们先了解一下@Transactional注释的特点,这样可以更好地调查问题

1. service标签(一般不建议在接口上添加)@Transactional,整个类别可以纳入spring事务管理,在执行每个业务方法时都会开始一个事务,但这些事务采用相同的管理方法。

当另一种实现方法被调用到某个service实现类中时,两种方法都必须声明事务才能被管理为事务

2. @Transactional 注释只能应用 public 可见度的方法。 如果应用于protected,、或者private 在package的可见度方法上,不会报错,但事务设置不会起作用。

3. 默认情况下,spring将事务回滚unchecked异常;如果是checked异常,则不会回滚。这个地方需要特别说明

4。 只读事务: @Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true) 只读标志只在事务开始时使用,否则即使配置也会被忽略。 由于共享阅读,启动事务会增加线程成本(具体与数据库类型和事务隔离级别有关)。通常情况下,只读取数据时,不需要设置只读取事务来增加额外的系统费用。

(2)事务传播模式

Propagation列举了多种事务传播模式,部分列举如下:

1. REQUIRED(默认模式):业务方法需要在容器中运行。如果该方法已经在一个事务中运行,则加入该事务,否则将建立一个新的事务。

2. NOT_SUPPORTED:声明方法不需要事务。如果该方法与事务无关,容器不会为他打开事务。如果该方法在事务中被调用,则事务将被挂断。调用后,原始事务将恢复执行。

3. REQUIRESNEW:无论是否有事务,这种方法总是为自己发起新的事务。如果该方法已经在事务中运行,则原始事务将被挂断,新事务将被创建。

4. MANDATORY:该方法只能在现有事务中执行,业务方法不能启动自己的事务。如果在没有事务的情况下被调用,容器除外。

5. SUPPORTS:如果该方法在一定范围内被调用,则该方法将成为该事务的一部分。如果该方法在事务范围外被调用,则该方法将在没有事务的情况下执行。

6. NEVER:这种方法绝对不能在事务范围内执行。如果有例外。只有当该方法与任何事务无关时,才能正常执行。

7. NESTED:如果存在活动事务,则在嵌套事务中运行。如果没有活动事务,则按照REQUIRED属性执行。它使用一个单独的事务,它有多个保存点可以回滚。内部事务的回滚不会影响外部事务。它只对DatasourcetransactionManager事务管理器有效。

(3)解决Transactional注释不回滚

1. 检查你的方法是否是public。

2. 您的异常类型是unchecked异常吗?空指针异常是unchecked异常 如果我想check异常也想回滚怎么办?注意上面写着异常类型。

@Transactional(rollbackFor={Exception.class.RuntimeException.class})

还有norollbackFor,自定义不回滚的异常。

另外 如果try已经在service中进行了 catch 操作 因已被抓获异常 故事不会回滚

3. 数据库引擎应该支持事务。如果是mysql,请注意使用支持事务的引擎,如inodb。如果是myisam,事务不起作用。

4. 是否打开了对注释的分析(SpringMVC,SpringBoot不需要看)

5. spring是否扫描到您的包,如下所示.test下面的包(SpringMVC,springBoot不需要看)

@Asyc和@Transactional一起使用

@transactional也适用于@async标记的方法;在调用数据库操作时,由于是基于异步处理的操作,无法产生事务管理控制。

那么如何将事务管理添加到这些操作中呢?需要事务管理操作的方法可以放置在异步法中,并添加到内部调用的方法中@Transactional.

例如: 方法A,用了@Async/标注Transactional,但不能产生事务控制的目的。

方法B,用@Async标注, C在B中被调用、D,C/D分别用@transactional做标记,可以达到事务控制的目的。