2014-09-02 85 views
0

注:超过here相关问题没有解决的OracleCommand与OracleDependency等待永远

请记住,我在Oracle方面的专家或编程反对甲骨文。这是我的测试环境。我在模式STVM中有一个名为STVM_NOTIFICATION的表。这是什么样子:

CREATE TABLE STVM_NOTIFICATION 
( 
    "ID"    NUMBER    NOT NULL, 
    "PROPERTYNAME" VARCHAR2(16 BYTE) NOT NULL, 
    "PROPERTYVALUE" VARCHAR2(16 BYTE) NOT NULL, 
    "ACTION"   VARCHAR2(32 BYTE) NOT NULL, 
    "POSTDATE"  TIMESTAMP (6)  NOT NULL, 
    "SENT"   CHAR(1 BYTE)  NOT NULL, 
    ADD CONSTRAINT "PK_ID" PRIMARY KEY ("ID") 
) 

我已经创建了如下的顺序和触发为每一行创建一个唯一的身份:

CREATE SEQUENCE STVM_NOTIF_SEQ 
    START WITH 1 
    INCREMENT BY 1 
    CACHE 100; 

CREATE OR REPLACE TRIGGER STVM_NOTIF_ID_TRG BEFORE INSERT ON STVM_NOTIFICATION 
    FOR EACH ROW 
    BEGIN 
     :NEW.ID := STVM_NOTIF_SEQ.NEXTVAL; 
    END; 

我然后设置以下拨款STVM:

GRANT CREATE SESSION TO STVM; 
GRANT CREATE TABLE TO STVM; 
GRANT CREATE VIEW TO STVM; 
GRANT CREATE ANY TRIGGER TO STVM; 
GRANT CREATE ANY PROCEDURE TO STVM; 
GRANT CREATE SEQUENCE TO STVM; 
GRANT CREATE SYNONYM TO STVM; 
GRANT CHANGE NOTIFICATION TO STVM; 

插入表格工作得很好。下面是由Oracle文档上OracleDependency提供了简单的测试应用(与小的修改),我使用来测试通知:

namespace SqlDependencyTest 
{ 
    class Program 
    { 
     private static string oraConnectionString = @"Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.0.164)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=XE)));User Id=STVM;Password=STVM;"; 
     private static string oraQuery = "SELECT ID FROM STVM_NOTIFICATION"; 
     private static OracleDependency oraDependency; 

     static void Main(string[] args) 
     { 
      using (OracleConnection oraConnection = new OracleConnection(oraConnectionString)) 
      { 
       try 
       { 
        // Open the connection 
        oraConnection.Open(); 

        // Create the Select command retrieving all data from the STVM_NOTIFICATION table. 
        OracleCommand selectCommand = new OracleCommand(oraQuery, oraConnection); 
        // Create an OracleDependency object and set it to track the result set returned by selectCommand. 
        oraDependency = new OracleDependency(selectCommand); 

        // Setting object-based change notification registration 
        oraDependency.QueryBasedNotification = false; 

        // When the IsNotifiedOnce property is true, only the first change 
        // of the traced result set will generate a notification. 
        // Otherwise, notifications will be sent on each change 
        // during the selectCommand.Notification.Timeout period. 
        selectCommand.Notification.IsNotifiedOnce = true; 

        // Set the event handler to the OnChange event. 
        oraDependency.OnChange += new OnChangeEventHandler(OnChange); 

        // When the select command is executed at the first time, a notification 
        // on changes of the corresponding result set is registered on the server. 
        //selectCommand.CommandTimeout = 5; 
        OracleDataReader reader = selectCommand.ExecuteReader(CommandBehavior.Default); 

        // Set and execute an insert command. The Dept table data will be changed, 
        // and a notification will be sent, causing the OnChange event of the 'dependency' object. 
        OracleCommand insertCommand = new OracleCommand 
         ("INSERT INTO STVM_NOTIFICATION (PROPERTYNAME, PROPERTYVALUE, ACTION, POSTDATE, SENT) VALUES ('Heartbeat', 'NOK', 'REFRESH', SYSDATE, 'N')", oraConnection); 
        insertCommand.ExecuteNonQuery(); 

        // Pause the current thread to process the event. 
        Console.Read(); 
       } 
       catch (Exception e) 
       { 
        Console.WriteLine("Exception encountered: {0}", e.Message); 
       } 
       // Always try to both remove the notification registration 
       // oraConnection.Close() is autimatically called by .Dispose at the end of our 'using' statement 
       finally 
       { 
        try 
        { 
         oraDependency.RemoveRegistration(oraConnection); 
        } 
        catch (Exception e) 
        { 
         Console.WriteLine("Exception encountered: {0}", e.Message); 
        } 
       } 
      } 
     } 

     // A simple event handler to handle the OnChange event. 
     // Prints the change notification details. 
     private static void OnChange(Object sender, OracleNotificationEventArgs args) 
     { 
      DataTable dt = args.Details; 

      Console.WriteLine("The following database objects were changed:"); 
      foreach (string resource in args.ResourceNames) 
      { 
       Console.WriteLine(resource); 
      } 

      Console.WriteLine("\n Details:"); 
      Console.Write(new string('*', 80)); 
      for (int rows = 0; rows < dt.Rows.Count; rows++) 
      { 
       Console.WriteLine("Resource name: " + dt.Rows[rows].ItemArray[0]); 
       string type = Enum.GetName(typeof(OracleNotificationInfo), dt.Rows[rows].ItemArray[1]); 
       Console.WriteLine("Change type: " + type); 
       Console.Write(new string('*', 80)); 
      } 
     } 
    } 
} 

这实际工作!但是:,直到另一个进程在同一张表上执行插入,至少,这是我的观察。我从SQL Developer中多次执行插入操作,这个问题是可以回顾的,并且我已经完成了10次以上。

只要另一个进程进行所述的插入,我的应用程序挂在下面的语句: OracleDataReader reader = selectCommand.ExecuteReader(CommandBehavior.Default);

我可以清楚地看到通知回调被注册DBA_CHANGE_NOTIFICATION_REGSnet8://(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.0.226)(PORT=64268))?PR=0

连接保持在Oracle服务器上打开30分钟,直到超时:

SELECT USERNAME, PROGRAM, BLOCKING_SESSION_STATUS, BLOCKING_INSTANCE, BLOCKING_SESSION, EVENT FROM V$SESSION 
WHERE USERNAME = 'STVM' 

USERNAME PROGRAM       BLOCKING_SESSION_STATUS BLOCKING_INSTANCE BLOCKING_SESSION EVENT 
STVM  SQL Developer     NO HOLDER    (null)    (null)    SQL*Net message from client 
STVM  OracleDependencyTest.vshost.exe VALID     1     50     enq: TM - contention 

每当发生这种情况时,唯一的解决方案是杀死会话,REVOKE CHANGE NOTIFICATION并再次授予它。在此之后,我的应用程序将再次运行,直到另一个进程执行插入。

我唯一的线索是事件enq:TM - 争用,但大多数人将此称为表中非索引外键的指示符。考虑到我目前只有一张表用于测试目的,这里没有大量的外键。

有没有人对的相关性有任何意见enq:TM - 争用

我使用:

(服务器端)

Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production 
PL/SQL Release 11.2.0.2.0 - Production 
"CORE 11.2.0.2.0 Production" 
TNS for Linux: Version 11.2.0.2.0 - Production 
NLSRTL Version 11.2.0.2.0 - Production 
Oracle.DataAccess 

(客户端)

Oracle Call Interface (OCI)           11.2.0.1.0 
Oracle Client              11.2.0.1.0 
Oracle Data Provider for .NET          11.2.0.1.0 
Oracle JDBC/OCI Instant Client          11.2.0.1.0 
Oracle JDBC/THIN Interfaces           11.2.0.1.0 
Oracle SQL Developer             11.2.0.1.0 
SQL*Plus                11.2.0.1.0 
SQL*Plus Files for Instant Client         11.2.0.1.0 

UPDATE:经过摸索天什么问题是,我没有找到问题,我决定继续前进并寻找不同的技术。基督徒的伟大建议并没有产生任何结果,解决像贾斯汀这样的无疑的交易,不幸的是没有让我更进一步。我知道有几个Oracle DBA在工作中最初愿意提供帮助,但是当我提到.NET时,他们很快就把我赶了出去。

+0

正在执行'insert'提交更改的进程? – 2014-09-02 18:39:50

+0

@JustinCave我刚刚检查过,V $ TRANSACTION中确实还有一个活动记录。我会看看如果我删除它会发生什么。 – 2014-09-02 19:11:23

+0

通过我强烈希望你并不意味着你打算修改'v $ transaction' ......我希望你的意思是你要在执行'insert'语句的会话中输入'commit'。 – 2014-09-02 19:12:44

回答

0

您正在使用的数据库版本中存在一个可能相关的错误。您可以通过执行以下内容作为SYSDBA来检查是否属于这种情况: alter system set events'10867 trace name context forever,level 1';

这将持续到关机。如果问题消失,您正在碰到错误。

您不应该将其打开,而应该升级数据库并修补ODP.NET。

+0

我会确保尽快检查。感谢您的建议。 – 2014-09-03 09:54:31

+0

编辑 - 我看到你确实尝试过...... – 2014-09-20 21:14:05

相关问题