2

谁能提供有关如何从 SSIS 参加 MVCC 会话的建议?

从 Ingres DB 中读取数据,我们需要启用 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 中,我们可以使用IsolationLevel任务/序列的属性来设置会话隔离级别。但我找不到直接发出 MVCC 命令的方法。

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

第 1 行的语法错误。读取的最后一个符号是:'SET LOCKMODE'

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

  • 有或没有终止;
  • 执行放置在序列内或序列外的步骤
  • DelayValidation在序列和步骤级别启用该属性
  • TransactionOption序列和任务级别的各种设置(以防万一!)
  • 通过 windows 环境变量设置锁定模式ING_SET = "SET LOCKMODE SESSION WHERE LEVEL = MVCC"。但是我的测试表明,我们在 SSIS 中使用的 ADO.NET 驱动程序支持这一点(顺便说一下,我们用于 SQL Squirrel 或 Tibco 的 JDBC 驱动程序也不支持它)。我相信这可能是一个 ODBC 功能。
  • 从数据流中的 ADO.NET 源步骤中发出命令。相同的语法错误。
  • [更新] 还尝试将SET ...命令包装在 Ingres 过程中,但这会导致语法错误,表明该SET ...命令在过程中的任何位置均无效。

谁能提供有关如何从 SSIS 参加 MVCC 会话的建议?

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

4

2 回答 2

0

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

设想了两种可能的方法。

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

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

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

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

所以最终我还必须从这个组件中发出源选择,即使这样也不太理想,因为随后的目标插入操作可能不会与源选择在同一个事务中登记。

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

代码看起来像这样(NB 必须显式添加对 Ingres .NET Data 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);
        }
    }
}
于 2015-08-06T05:37:43.143 回答
0

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

设想了两种可能的方法。

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

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

于 2015-08-06T05:39:45.200 回答