假设想到一个场景:
function a(){
create savepoint s1
insert x1
insert x2
b()
insert x4
if we get an error rollback to s1
else commit.
}
function b(){
create savepoint s2
insert x3
if we get an error rollback to s2
else commit
}
我的问题是假设我的b()传递没有错误,并且在插入x4时出现问题,所以我解雇了回滚。所以我的问题是它是否也将还原作为b()的一部分插入的东西,即x3。
答案 0 :(得分:1)
方法b()
根本不应该提交,commit()
只应在一切完成后才允许。
您应该将场景修改为:
function a(){
create savepoint s1
insert x1
insert x2
b()
insert x4
if we get an error rollback to s1
else commit.
}
function b(){
create savepoint s2
insert x3
if we get an error rollback to s2
}
唯一的区别是删除b()
中的提交分支。 Connection
将保留保存点s2,直到回滚到s1
或提交。
请注意,如果函数a()
本身也是较大事务的一部分,那么else commit
也应该被删除。如果a()
是事务的开始,那么您应该回滚(而不是rollback to s1
)。
如果您希望这些可以独立调用或可组合,那么我建议您使用某种形式的事务管理器,并将其传递给方法调用。
说出
的内容interface TransactionManager() {
void commit();
void rollback();
TransactionManager subTransaction();
}
class RootTransactionManager() implements TransactionManager {
private final Connection connection;
RootTransactionManager(Connection connection) {
this.connection = connection;
}
public void commit() {
connection.commit();
}
public void rollback() {
connection.rollback();
}
public TransactionManager subTransaction() {
return new SubTransactionManager(this);
}
Connection getConnection() {
return connection;
}
}
class SubTransactionManager implements TransactionManager() {
private final RootTransactionManager manager;
private final SavePoint savePoint;
SubTransactionManager (RootTransactionManager manager) {
this.manager = manager;
savePoint = manager.getConnection().setSavePoint();
}
public void commit() {
// do nothing (semantics of Connection.releaseSavePoint not useful for nesting)
}
public void rollback() {
connection.rollback(savePoint);
}
public TransactionManager subTransaction() {
return new SubTransactionManager(manager);
}
}
您可以使用它来实现您的方法:
void someOtherMethod() {
Connection connection; // = ...
a(new RootTransactionManager(connection));
}
void a(TransactionManager tm) {
try {
// do stuff
b(tm.subTransaction);
// do stuff
tm.commit();
} catch (SQLException ex) {
tm.rollback();
}
}
void b(TransactionManager tm) {
try {
// do stuff
tm.commit();
} catch (SQLException ex) {
tm.rollback();
}
}
这只是一个快速草图,如果我真的花了更多时间,我可能会想出一些完全不同的东西。
答案 1 :(得分:0)
它将在最后一个保存点之前还原事物,即不会还原插入X1,X2和b()的修改。
理想情况下,为了保持事务的原子性,我们不应该在它之间发出commit语句。只有在所有操作都成功完成后才会发出Commit()。但是,如果某些内容失败,则应发出回滚(通常在catch块中)。