繁体   English   中英

Spring 事务和尝试捕获块

[英]Spring transaction and try catch blocks

我对 Kotlin 和 Spring 非常陌生,并且有一个非常基本的疑问。 考虑这样的 function:

@transaction
fun accept() {
    try {
        write to table A
        throw Exception()
    } catch(){
        write to table B
    }
}

问题:我知道B表写会成功,但是A表会写成功吗? 为什么? 任何指向

Spring 对异常的“含义”有点奇怪。 它的作用如下。 事务方法在退出之前不会提交任何内容。 即:

@transaction
fun accept() {
  write to table A
  while (true) {} // loop forever
}

微不足道地从不实际提交任何东西,这可能很明显。 否则,该方法退出,它可以通过以下三种方式之一退出:

  • 方法“返回”。 就像在方法中一样,不会抛出异常 - 可能会抛出异常,但它们会被捕获。 然后在退出该方法时,事务被提交。 请注意,这描述了您的代码段——它不会方法中抛出异常 因此,对表 A 和 B 的写入都将发生并且对外部各方可见!
  • 该方法通过抛出一个 UNCHECKED 异常来结束。 Spring 的观点是,这是“意外”,并表明执行该方法的结果是失败 - 整个事务被中止。 对表 A 的写入永远不会对其他事务可见,对表 B 的写入也不可见(假设在 catch 块之后,您throw new RuntimeException() )。
  • 该方法以抛出一个 CHECKED 异常结束。 Spring 的观点是,这一定意味着它是“故意的”,并且表明代码成功; 它只是选择“返回”异常而不是正常完成。 事务已提交 - 其他人可以看到对表 A 的写入。 其他人也可以看到对表 B 的写入(这是假设您将throw new IOException()添加到 accept 方法的末尾,当然您的方法可以这样做。在 java 中意味着它必须当然,被声明为void accept() throws IOException {}

kotlin中不存在已检查和未检查的概念 - 在 kotlin 中,所有异常都是“未检查”,有效。 但是,spring 没有 go:“OOoooohhhh,kotlin 用户,我将把所有事情都视为未选中的事务,即抛出任何异常,” 不,因此,即使您只编写 kotlin,您也必须了解检查异常是什么

Unchecked exceptions are all throwables that have in their type hierarchy either java.lang.Error (such as java.lang.InternalError , which extends jlError ), or java.lang.RuntimeException , such as NullPointerException .

所有其他投掷物都被“检查”。 比如IOException ,它扩展了 Exception。 它扩展了 Throwable。 检查Exception本身。

注意:您可以添加拦截器等来改变这种行为; “检查异常意味着我们需要提交,检查意味着我们需要中止”只是默认行为。

如果“写入表 A”成功,那么是的,它将持续存在。

为什么? 因为事务划分是由对异常起作用的拦截器完成的,并且在您的代码中没有拦截器会看到该异常,因为它们只能围绕那些“写入表 X”调用(如果这些调用是通过可拦截代码完成的)或accept()执行。

让我尝试添加更多细节:

一般来说,您可以在概念上认为拦截器看起来像这样(它们看起来不同,但示例用于说明这一点 - 我还将使用 Java 代码,因为我对 Kotlin 不太熟悉):

void runInTransaction(Runnable interceptedCode) {
  Transaction tx = startTransaction();

  try {
    interceptedCode.run();
    tx.commit();
  } catch( Exception e) { //kept simple for illustration purposes, in reality this is way more complex
    tx.rollback();
  }
}

然后你会这样称呼它:

runInTransaction(() -> accept());

如您所见,由于异常仅在accept()中被抛出和捕获 - 因此不会离开方法 - 拦截器甚至不会看到它,因此将提交事务。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM