0

我必须将一些使用 ADO.NET 的现有代码转换为并行处理方案。原始代码使用静态连接对象和事务,因此需要进行一些相当大的重组。

作为概念证明,我一直在尝试使用任务并行库让一些简单的插入以稳定的方式工作。我发现我必须编写一些奇怪的代码才能做到这一点。首先,我的控制台应用程序中的 Main 方法:

class Program
{
    private static Db db1;
    private static Db db2;

    static void Main(string[] args)
    {
        db1 = new Db();
        db2 = new Db();

        Task task1 = Task.Factory.StartNew(() =>
           {
               db1.BeginTransaction("Transaction1");
               decimal p = AddNewProject(db1, "Project 1");
               AddNewTask(db1, p, "Task1");
           });


        Task task2 = Task.Factory.StartNew(() =>
            {
                db2.BeginTransaction("Transaction1");
                decimal p = AddNewProject(db2, "Project 2");
                AddNewTask(db2, p, "Task1");
            });

        db1.Dispose();
        db2.Dispose();

        Console.ReadLine();
    }

    static decimal AddNewProject(Db db, string name)
    {
        return db.InsertNewProject(name);
    }

    static void AddNewTask(Db db, decimal project, string name)
    {
        db.InsertNewTask(project, name);
    }
}

重要的是,带有奇怪代码的 Db 类:

public class Db : IDisposable
{
    private SqlConnection connection;
    private String connString;
    private SqlTransaction transaction;

    public Db()
    {
        connString = ConfigurationManager.ConnectionStrings["MyConn"].ConnectionString;
        this.connection = new SqlConnection();
        this.connection.StateChange += new StateChangeEventHandler(connection_StateChange);
        this.connection.ConnectionString = connString;
        this.connection.Open();
    }

    void connection_StateChange(object sender, StateChangeEventArgs e)
    {
        if (e.CurrentState != ConnectionState.Open)
        {
            this.connection.ConnectionString = this.connString;
            this.connection.Open();
        }
    }

    public void BeginTransaction(string vendorName)
    {
        while (this.connection.State != ConnectionState.Open)
        {
            Thread.Sleep(10);
        }

        this.transaction = this.connection.BeginTransaction(IsolationLevel.ReadUncommitted, vendorName);
    }

    public decimal InsertNewProject(string name)
    {
        SqlCommand command = new SqlCommand();
        command.Connection = this.connection;
        command.CommandType = CommandType.Text;

        if (this.connection.State != ConnectionState.Open)
        {
            this.connection.ConnectionString = this.connString;
            this.connection.Open();
        }

        command.CommandText = "INSERT INTO Project VALUES('" + name + "', 'true');SELECT SCOPE_IDENTITY();";
        command.Transaction = this.transaction;

        Object pk = command.ExecuteScalar();

        return (decimal)pk;
    }

    public int InsertNewTask(decimal project, string name)
    {
        SqlCommand command = new SqlCommand();
        command.Connection = this.connection;
        command.CommandType = CommandType.Text;

        if (this.connection.State != ConnectionState.Open)
        {
            this.connection.ConnectionString = this.connString;
            this.connection.Open();
        }

        command.CommandText = "INSERT INTO Task([TaskName], [Project], [Visible], [Estimate]) VALUES('" + name + "', '" + (int)project + "', 'true', 0);SELECT SCOPE_IDENTITY();";
        command.Transaction = this.transaction;

        Object pk = command.ExecuteScalar();
        this.transaction.Commit();
        //this.transaction.Rollback();
        return Convert.ToInt32((decimal)pk);
    }

    public void Dispose()
    {
        this.connection.Close();
        //this.transaction.Dispose();
        this.connection.Dispose();
    }
}

完成这项工作所需的两个奇怪的位是:

  1. StateChange 处理程序(以及为什么我必须处理这个?!)
  2. BeginTransaction 方法,以及该类的方法中对连接的不断检查和打开

为什么连接不保持打开状态?曾经那么奇怪。这段代码让我很紧张,我并不急于将它放入 UAT(然后是生产)。

连接字符串是:

<connectionStrings>
    <add name="MyConn" connectionString="Data Source=PLAGUIS;Initial Catalog=TimeTracker;Pooling=false;MultipleActiveResultSets=True;Integrated Security=True"
        providerName="System.Data.SqlClient" />
</connectionStrings>

我发现我必须关闭连接池。

如果有人可以解释使用连接和不同线程(任务)的最佳方式,我将非常感激。

4

0 回答 0