我们可以将对存储过程的调用包装在一个事务中,并指定隔离级别。
或者,我们可以将事务放在存储过程内部,并在那里指定隔离级别。
哪种方法更好?
我们可以将对存储过程的调用包装在一个事务中,并指定隔离级别。
或者,我们可以将事务放在存储过程内部,并在那里指定隔离级别。
哪种方法更好?
您应该采用一致的方法。请注意,在存储过程中回滚事务将回滚任何嵌套事务范围,包括任何外部范围。
我建议您将事务保留在程序之外。这样,您可以保留完全控制权。
在我看来,存储过程内部是最合适的位置。
良好事务设计的基本规则之一是尽可能缩短事务生命周期,因此提交应该在事务逻辑完成后立即发生。在存储过程外控制事务将不必要地延长事务生命周期。
您还应考虑,在存储过程内定义事务也会为您的代码提供更清晰的说明。否则,如果另一个编码人员需要修改某个存储过程,则必须依赖于调用者确实将存储过程包装在事务中。在存储过程中包含事务可以明确定义您的事务处理。
提醒一下,Oracle不支持嵌套事务。如果您在外部级别开始一个事务,然后调用一系列存储过程,任何发出提交命令的存储过程都会提交到目前为止的整个事务,而不仅仅是它自己所引发的事务。因此,在像C#这样的语言中调用时,您必须在存储过程之外管理事务。
只是想与您分享做个比较。
如果您在数据库API的外部层进行操作,那么如果您在每个存储过程中都进行提交,那么您可能会像开启自动提交一样,考虑以下存储过程:
如果您在每个存储过程中进行提交,在出现错误时,您将无法回滚整个事务,因此建议您在外部层控制事务提交。
create_user_with_email_address
calls -> create_user
calls -> create_email_address
如果在create_user/create_email_address中提交了任何一个,则create_user_with_email_address不再是事务性的。如果create_email_address失败,则create_user已经被提交,您将会得到破损的数据。
将事务置于所需的最高位置以使其包含所有内容。
这取决于业务逻辑,如果存储过程是原子性的,则应该实现自己的事务。如果不这样做,未来可能会出现错误代码而没有创建包装事务的风险。因此,回答你的问题,我认为事务应该放在存储过程内部。
当然,你也可以同时进行两种方式,即原子性存储过程实现自己的事务,而在此范围之外,其他更广泛的事务可能已经存在。
通常在存储过程中使用事务时,你可能已经处于事务范围内,因此在执行提交/回滚时必须对此进行编码。
BEGIN TRANSACTION MySprocName_01
SAVE TRANSACTION MySprocName_02
...
IF @ErrorFlag = 0
BEGIN
COMMIT TRANSACTION MySprocName_01
END
ELSE
BEGIN
ROLLBACK TRANSACTION MySprocName_02
COMMIT TRANSACTION MySprocName_01
END