检查Oracle连接是否具有关联本地事务的最佳方法

时间:2015-08-20 11:06:01

标签: .net oracle oracle11g transactions odp.net

所以我有一些代码可以通过Oracle ODP.NET更新一组数据库表。更新需要是原子的,因此需要在事务中运行。但是代码可以在两个不同的场景中调用:一个已经启动了一个事务(我需要共享),一个不会(因此我需要自己开始)。

我的问题是,我认为没有简单的方法可以检查Oracle连接是否已启动事务。可能的解决方案(我都不满意):

  1. 尝试创建新事务并捕获异常(如果已经启动)

    Try
        tx = OracleConnection.BeginTransaction
    Catch ex As Exception
        'do something
    End Try
    
  2. 问题:使用异常进行正常程序流控制的不良做法

    1. 检查V $ TRANSACTION或类似的表格,例如[Oracle: How to find out if there is a transaction pending?
    2. 问题:Oracle用户需要访问系统表。

      1. Oracle连接对象上有一个私有成员,即m_oraTransaction,我可以通过反射检索。
      2. 问题:因为某种原因而私有。

        有更好的方法吗?

        NB。我在Oracle12c中看到Oracle连接上有一个LogicalTransactionId属性。我认为这可能表明Oracle发现了一个缺陷并添加了这个属性。

2 个答案:

答案 0 :(得分:1)

当DML语句至少更新一行时,Oracle会物理创建事务(以及V $ TRANSACTION中的记录)。

使用V $ TRANSACTION并不理想,因为您需要额外的权限才能访问此视图。

我知道的最简单的检查是SELECT DBMS_TRANSACTION.LOCAL_TRANSACTION_ID FROM DUAL。如果它返回NOT NULL值,则表示已创建物理事务(或者您已经在之前启动的现有事务中)。

我在OracleConnection.LogicalTransactionId中从未见过任何其他值而非null。

答案 1 :(得分:0)

使用System.Transactions.TransactionScope?

public void Senario1()
{
  using (var transaction = new TransactionScope())
  {
    //your odp.net op here:
    //var cmd = new OracleCommand();

    //also do senario2 - the outer TransactionScope here will be detected by the new one in senario2
    Senario2();

    transaction.Complete();
  }
}
public void Senario2()
{
  using (var transaction = new TransactionScope())
  {
    //your odp.net op here:
    //var cmd = new OracleCommand();
    transaction.Complete();
  }
}