如何通过 SSIS 在 Ingres 连接上设置 LOCKMODE SESSION WHERE LEVEL = MVCC

How to SET LOCKMODE SESSION WHERE LEVEL = MVCC on Ingres connection via SSIS

任何人都可以提供有关如何从 SSIS 加入 MVCC 会话的建议吗?

从 Ingres 数据库中读取,我们需要启用 MVCC 并在 SSIS 2008 R2 包中指定隔离级别。

此数据库上存在一个不使用 MVCC 的现有应用程序,因此不适合在现有 DBMS 上简单地启用 MVCC。我们希望我们的读取在 MVCC 中登记的原因是确保我们不会导致锁定并破坏这个现有的应用程序(当我们不使用 MVCC 执行这些读取时,当前会定期发生)。

数据库版本为Ingres II 10.0.0 (su9.us5/132)

ADO.NET驱动版本为Ingres.Client.IngresConnection, Ingres.Client, Version=2.1.0.0驱动,

我们有一个类似的要求,即从 Tibco BusinessWorks 中以编程方式执行此操作,并通过例如 SQL Squirrel 以交互方式执行此操作,并通过直接 SQL 执行(通过 JDBC):

SET LOCKMODE SESSION WHERE LEVEL = MVCC;
SET SESSION ISOLATION LEVEL READ COMMITTED;    

在SSIS中我们可以使用task/sequence的IsolationLevel属性设置会话隔离级别。但是我找不到直接发出MVCC命令的方法。

我试图通过 Exceute SQL Task 步骤发出命令,但遇到以下错误:

Syntax error on line 1. Last symbol read was: 'SET LOCKMODE'

我已经尝试过,但无济于事:

任何人都可以提供有关如何从 SSIS 加入 MVCC 会话的建议吗?

在这个阶段(我相信)我们受限于 ADO.NET 驱动程序,但如果没有其他选项可以与 ODBC 一起使用,那就这样吧。

在这里回答我自己的问题。

设想了两种可能的方法。

1.使用脚本组件(在数据流步骤中)

在脚本组件中,我能够通过 ADO.NET 直接发出 SET ... 命令。

这种方法的问题是我无法为后续(或并行,在同一数据流中)ADO.NET 保留这些命令所在的连接 运行组件。

尝试通过事务通过特定连接工作是不好的,因为这些命令必须在正在进行的事务之外发出。

所以最终我还必须从该组件中发出源 select,即使这样也不太理想,因为随后的目标插入操作无法在与源相同的事务中登记 select.

使用这种方法的解决方案最终是: - 使用 MVCC,将数据从源视图复制到源系统上的临时暂存区 table。 - 然后使用事务,从源分段 table 读取到目标系统。

代码看起来像这样(NB 必须显式添加对 Ingres .NET 数据的引用 Provider\v2.1\Ingres.Client.dll

/* Microsoft SQL Server Integration Services Script Component
*  Write scripts using Microsoft Visual C# 2008.
*  ScriptMain is the entry point class of the script.*/

using System;
using System.Data;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
using Ingres.Client;
using System.Collections.Generic;

[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{
    private bool debug = true;

    private IDTSConnectionManager100 cm;
    private IngresConnection conn;


    public override void AcquireConnections(object Transaction)
    {
        // The connection manager used here must be configured in the Script Component editor's "Connection Managers" page.
        // "Connection" is the (default) strongly typed name for the first connection added.
        // In this case, it needs to be a reference to the xxxxx connection manager (by convention it should be "xxxxx_ADONET").
        cm = this.Connections.Connection;
        conn = (IngresConnection)cm.AcquireConnection(Transaction);
    }

    public override void PreExecute()
    {
        debugMessage("PreExecute", "Started");
        base.PreExecute();

        string viewName = Variables.vViewName;

        IngresCommand cmdSetSessionLockMode         = conn.CreateCommand();
        IngresCommand cmdSetSessionIsolationLevel   = conn.CreateCommand();
        IngresCommand cmdReaderQuery                = conn.CreateCommand();

        List<string> sqlCommandStrings = new List<string>();
        if (Variables.vUseIngresMVCC)
        {
            sqlCommandStrings.Add("SET LOCKMODE SESSION WHERE LEVEL = MVCC");
        }
        sqlCommandStrings.Add("SET SESSION ISOLATION LEVEL READ COMMITTED");
        sqlCommandStrings.Add(String.Format("MODIFY {0}_STAGING TO TRUNCATED", viewName));
        sqlCommandStrings.Add(String.Format("INSERT INTO {0}_STAGING SELECT * FROM {0}", viewName));

        foreach (string sqlCommandString in sqlCommandStrings)
        {
            debugMessage("PreExecute", "Executing: '{0}'", sqlCommandString);

            IngresCommand command = conn.CreateCommand();
            command.CommandText = sqlCommandString;
            int rowsAffected = command.ExecuteNonQuery();

            string rowsAffectedString = rowsAffected >= 0 ? rowsAffected.ToString() : "No";
            debugMessage("PreExecute", "Command executed OK, {0} rows affected.", rowsAffectedString);
        }

        debugMessage("PreExecute", "Finished");
    }

    public override void CreateNewOutputRows()
    {
        // SSIS requires that we output at least one row from this source script.
        Output0Buffer.AddRow();
        Output0Buffer.CompletedOK = true;
    }

    public override void PostExecute()
    {
        base.PostExecute();

        // NB While it is "best practice" to release the connection here,  doing so with an Ingres connection will cause a COM exception.
        // This exception kills the SSIS BIDS designer such that you'll be unable to edit this code through that tool.
        // Re-enable the following line at your own peril.
        //cm.ReleaseConnection(conn);
    }

    private void debugMessage(string method, string messageFormat, params object[] messageArgs)
    {
        if (this.debug)
        {
            string message = string.Format(messageFormat, messageArgs);
            string description = string.Format("{0}: {1}", method, message);
            bool fireAgain = true;
            this.ComponentMetaData.FireInformation(0, this.ComponentMetaData.Name, description, "", 0, ref fireAgain);
        }
    }
}

在这里回答我自己的问题。

设想了两种可能的方法。

2。在现有数据库上设置 Ingres DBMS 的启用 MVCC 的专用进程,并通过此连接

这是我们目前正在采用的方法(因为它受到支持,并且理想情况下是透明的)。一旦他们知道我会更新细节。