A(){
con.begin;
.........
.........
B();
........
........(con.rollback;)
con.commit;
}
B{
con.begin;
.......
.......
con.commit;
}
在上面的代码中,我在A()处开始一个新的DB事务。它成功执行了一些事务。在那之后B()开始执行并且它也成功执行了一些事务,现在控制返回到A()。此时会发生一些异常,我会进行回滚。我想知道B()中成功的事务是否会回滚。
答案 0 :(得分:11)
简短的回答,没有。答案如下:
支持Java中的嵌套事务取决于各种变量。
首先,如果您使用的是JTA,则事务管理器最多可以支持嵌套事务。如果尝试在已与事务关联的线程中启动新事务,则任何开始事务的尝试都可能导致事务管理器(不支持嵌套事务)抛出NotSupportedException。
来自Java Transaction API 1.1规范:
3.2.1开始交易
TransactionManager.begin方法启动 全球交易和员工 与事务上下文 调用线程。如果是交易 经理实施没有 支持嵌套事务, TransactionManager.begin methodthrowsthe NotSupportedException 当调用线程已经存在时 与交易相关联。
JDBC 3.0引入了Savepoint类,它或多或少类似于数据库中保存点的概念。必须使用返回Savepoint实例的Connection.setSavepoint()方法初始化保存点。可以使用Connection.rollback(Savepoint svpt)方法稍后回滚到此保存点。当然,所有这些都取决于您是否使用支持JDBC 3.0的驱动程序,该驱动程序支持保存点的设置并回滚到它们。
默认情况下,获取的所有连接都设置为自动提交,除非JDBC驱动程序在此前面存在明显偏差。此功能(如果启用)会自动排除嵌套事务的范围,因为通过连接在数据库中进行的所有更改都会在执行时自动提交。
如果禁用自动提交功能,并选择显式提交和回滚事务,则提交事务始终会提交连接执行的所有更改,直到该时间点为止。请注意,为提交选择的更改不能由程序员定义 - 直到该瞬间的所有更改都被选择用于提交,无论它们是在一种方法还是另一种方法中执行。唯一的出路是定义保存点,或者破解你的方式通过JDBC驱动程序 - 驱动程序通常会提交由与线程关联的连接执行的所有更改,因此启动新线程(这很糟糕)并在其中获取新连接,经常给你一个新的交易背景。
您可能还想检查框架如何为嵌套事务提供支持,特别是如果您与JDBC API隔离或者自己启动新的JTA事务。
基于以上关于如何在各种场景中实现嵌套事务支持的描述,似乎代码中的回滚将回滚与Connection对象关联的所有更改。
答案 1 :(得分:0)
我害怕看起来糟糕的交易管理。如果你处理从调用者到A和B的提交和回滚会很好。
A()
{
//business code A
B();
//more business code A
}
B()
{
//business code B
}
DoA()
{
try
{
con.begin();
A();
con.commit();
}
catch(Exception e)
{
con.rollback();
}
}
DoB()
{
try
{
con.begin();
B();
con.commit();
}
catch(Exception e)
{
con.rollback();
}
}
答案 2 :(得分:0)
根据您的代码,在A()中,您正在开始交易。然后跳转到B(),再次启动事务,然后将提交所有先前的事务。然后在B()结束时,显式提交事务。此时,您的所有代码都已提交。现在代码返回A()并处理剩余的代码。如果发生异常,只会回滚B()调用后的这一部分。
答案 3 :(得分:0)
您可以在Postgres 8及更高版本中使用Java.SQL的内置SavePoint功能。
Connection conn = null;
Savepoint save = null;
DatabaseManager mgr = DatabaseManager.getInstance();
try {
conn = mgr.getConnection();
proc = conn.prepareCall("{ call writeStuff(?, ?) }");
//Set DB parameters
proc.setInt(1, stuffToSave);
proc.setString(2, moreStuff);
//Set savepoint here:
save = conn.setSavepoint();
//Try to execute the query
proc.execute();
//Release the savepoint, otherwise buffer memory will be eaten
conn.releaseSavepoint(save);
} catch (SQLException e) {
//You may want to log the first one only.
//This block will attempt to rollback
try {
//Rollback to the Savepoint of prior transaction:
conn.rollback(save);
} catch (SQLException e1) {
e1.printStackTrace();
}
}
发生SQL异常时,当前事务将回滚到SavePoint,并且可能会发生其余事务。如果没有回滚,后续交易将失败。