C# 此共享DbCommand对象是线程安全的吗?

C# 此共享DbCommand对象是线程安全的吗?,c#,asp.net,multithreading,thread-safety,data-access-layer,C#,Asp.net,Multithreading,Thread Safety,Data Access Layer,我不明白为什么每次需要调用存储过程时都必须创建DbCommand对象。所以我正试图想出一个方法来做到这一点。我已经测试了我的代码(见下文)。但我想和社区核实一下,以防我遗漏了什么。我会在ASP.NET应用程序中使用它。这段代码是线程安全的吗 SharedDbCommand—包装DbCommand对象的创建和存储 Db—数据库的包装器,通过静态字段和ThreadStatic属性使用SharedDbCommand Program-启动线程并使用Db对象的控制台应用程序 // SharedDbComm

我不明白为什么每次需要调用存储过程时都必须创建DbCommand对象。所以我正试图想出一个方法来做到这一点。我已经测试了我的代码(见下文)。但我想和社区核实一下,以防我遗漏了什么。我会在ASP.NET应用程序中使用它。这段代码是线程安全的吗

SharedDbCommand—包装DbCommand对象的创建和存储

Db—数据库的包装器,通过静态字段和ThreadStatic属性使用SharedDbCommand

Program-启动线程并使用Db对象的控制台应用程序

// SharedDbCommand.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Data.Common;
using System.Data.SqlClient;
using System.Data;

namespace TestCmdPrepare {
    public class SharedDbCommand {
        [ThreadStatic]
        static DbCommand cmd;

        public SharedDbCommand(string procedureName, ConnectionStringSettings dbConfig) {
            var factory = DbProviderFactories.GetFactory(dbConfig.ProviderName);
            cmd = factory.CreateCommand();
            cmd.Connection = factory.CreateConnection();
            cmd.Connection.ConnectionString = dbConfig.ConnectionString;
            cmd.CommandText = procedureName;
            cmd.CommandType = System.Data.CommandType.StoredProcedure;
            if (cmd is SqlCommand) {
                try {
                    cmd.Connection.Open();
                    SqlCommandBuilder.DeriveParameters(cmd as SqlCommand);
                } finally {
                    if (cmd != null && cmd.Connection != null) 
                        cmd.Connection.Close();
                }
            }
        }

        public DbParameter this[string name] {
            get {
                return cmd.Parameters[name];
            }
        }

        public IDataReader ExecuteReader() {
            try {
                cmd.Connection.Open();
                return cmd.ExecuteReader(CommandBehavior.CloseConnection);
            } finally {
                cmd.Connection.Close();
            }
        }

        public void ExecuteNonQuery() {
            try {
                cmd.Connection.Open();
                cmd.ExecuteNonQuery();
            } finally {
                cmd.Connection.Close();
            }
        }
    }
}

// Db.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Data.Common;
using System.Data;
using System.Data.SqlClient;
using System.Threading;
using System.Diagnostics;

namespace TestCmdPrepare {
    public class Db {
        ConnectionStringSettings dbSettings;
        DbProviderFactory factory;
        public Db() {
            dbSettings = ConfigurationManager.ConnectionStrings["db"];
            factory = DbProviderFactories.GetFactory(dbSettings.ProviderName);
        }
        IDataReader ExecuteReader(DbCommand cmd) {
            cmd.Connection.Open();
            return cmd.ExecuteReader(CommandBehavior.CloseConnection);
        }

        private DbConnection CreateConnection() {
            var c = factory.CreateConnection();
            c.ConnectionString = dbSettings.ConnectionString;
            return c;
        }

        DbCommand CreateCommand(string procedureName) {
            var cmd = factory.CreateCommand();
            cmd.Connection = CreateConnection();
            cmd.CommandText = "get_stuff";
            cmd.CommandType = CommandType.StoredProcedure;
            if (cmd is SqlCommand) {
                try {
                    cmd.Connection.Open();
                    SqlCommandBuilder.DeriveParameters(cmd as SqlCommand);
                } finally {
                    cmd.Connection.Close();
                }
            }
            return cmd;
        }


        [ThreadStatic]
        static DbCommand get_stuff;

        DbCommand GetStuffCmd {
            get {
                if (get_stuff == null)
                    get_stuff = CreateCommand("get_stuff");
                return get_stuff;
            }
        }

        public string GetStuff(int id) {
            GetStuffCmd.Parameters["@id"].Value = id;
            using (var reader = ExecuteReader(GetStuffCmd)) {
                if (reader.Read()) {
                    return reader.GetString(reader.GetOrdinal("bar"));
                }
            }
            return null;
        }

        [ThreadStatic]
        static SharedDbCommand get_stuff2;
        public string GetStuff2(int id) {
            if (get_stuff2 == null)
                get_stuff2 = new SharedDbCommand("get_stuff", dbSettings);
            get_stuff2["@id"].Value = id;
            using (var reader = get_stuff2.ExecuteReader()) {
                if (reader.Read()) {
                    Thread.Sleep(1000);
                    return reader.GetString(reader.GetOrdinal("bar"));
                }
            }
            return null;
        }
    }
}


// Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Common;
using System.Configuration;
using System.Data.SqlClient;
using System.Threading;

namespace TestCmdPrepare {
    class Program {
        static void Main(string[] args) {
            var db = new Db();
            var threads = new List<Thread>();
            for (int i = 0; i < 4; i++) {
                var one = new Thread(Run2);
                var two = new Thread(Run1);

                threads.Add(one);
                threads.Add(two);
                one.Start();
                two.Start();

                Write(db, 1);
                Write(db, 2);
            }
            Console.WriteLine("Joining");
            foreach (var thread in threads) {
                thread.Join();
            }
            Console.WriteLine();
            Console.WriteLine("DONE");
            Console.ReadLine();
            return;
        }

        static void Write(Db db, int id) {


       Console.WriteLine("2:{0}:{1}", Thread.CurrentThread.ManagedThreadId, db.GetStuff2(id));
        Console.WriteLine("1:{0}:{1}", Thread.CurrentThread.ManagedThreadId, db.GetStuff(id));
    }

    static void Run1() {
        var db = new Db();
        Write(db, 1);
    }

    static void Run2() {
        var db = new Db();
        Write(db, 2);
    }

    }
}
//SharedDbCommand.cs
使用制度;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用系统配置;
使用System.Data.Common;
使用System.Data.SqlClient;
使用系统数据;
命名空间TestCmdPrepare{
公共类SharedDbCommand{
[线程静态]
静态dbcmd命令;
公共共享DDBCommand(字符串过程重命名,连接字符串设置dbConfig){
var factory=dbProviderFactorys.GetFactory(dbConfig.ProviderName);
cmd=factory.CreateCommand();
cmd.Connection=factory.CreateConnection();
cmd.Connection.ConnectionString=dbConfig.ConnectionString;
cmd.CommandText=procedureName;
cmd.CommandType=System.Data.CommandType.StoredProcess;
if(cmd是SqlCommand){
试一试{
cmd.Connection.Open();
派生参数(cmd作为SqlCommand);
}最后{
if(cmd!=null&&cmd.Connection!=null)
cmd.Connection.Close();
}
}
}
公共DbParameter此[字符串名称]{
得到{
返回cmd.Parameters[name];
}
}
公共IDataReader ExecuteReader(){
试一试{
cmd.Connection.Open();
返回cmd.ExecuteReader(CommandBehavior.CloseConnection);
}最后{
cmd.Connection.Close();
}
}
public void ExecuteNonQuery(){
试一试{
cmd.Connection.Open();
cmd.ExecuteNonQuery();
}最后{
cmd.Connection.Close();
}
}
}
}
//Db.cs
使用制度;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用系统配置;
使用System.Data.Common;
使用系统数据;
使用System.Data.SqlClient;
使用系统线程;
使用系统诊断;
命名空间TestCmdPrepare{
公共类数据库{
连接字符串设置dbSettings;
DBProvider工厂;
公共数据库(){
dbSettings=ConfigurationManager.ConnectionString[“db”];
factory=dbProviderFactorys.GetFactory(dbSettings.ProviderName);
}
IDataReader ExecuteReader(DbCommand cmd){
cmd.Connection.Open();
返回cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
专用数据库连接CreateConnection(){
var c=factory.CreateConnection();
c、 ConnectionString=dbSettings.ConnectionString;
返回c;
}
DbCommand CreateCommand(字符串过程重命名){
var cmd=factory.CreateCommand();
cmd.Connection=CreateConnection();
cmd.CommandText=“获取内容”;
cmd.CommandType=CommandType.storedProcess;
if(cmd是SqlCommand){
试一试{
cmd.Connection.Open();
派生参数(cmd作为SqlCommand);
}最后{
cmd.Connection.Close();
}
}
返回cmd;
}
[线程静态]
静态DbCommand get_stuff;
DbCommand GetStuffCmd{
得到{
if(get_stuff==null)
get_stuff=CreateCommand(“get_stuff”);
返回得到你的东西;
}
}
公共字符串GetStuff(int-id){
GetStuffCmd.Parameters[“@id”].Value=id;
使用(var reader=ExecuteReader(GetStuffCmd)){
if(reader.Read()){
返回reader.GetString(reader.GetOrdinal(“bar”));
}
}
返回null;
}
[线程静态]
静态SharedDbCommand get_stuff2;
公共字符串GetStuff2(int-id){
if(get_stuff2==null)
get_stuff 2=新的SharedDbCommand(“get_stuff”,dbSettings);
get_stuff2[“@id”]。Value=id;
使用(var reader=get_stuff2.ExecuteReader()){
if(reader.Read()){
睡眠(1000);
返回reader.GetString(reader.GetOrdinal(“bar”));
}
}
返回null;
}
}
}
//Program.cs
使用制度;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Data.Common;
使用系统配置;
使用System.Data.SqlClient;
使用系统线程;
命名空间TestCmdPrepare{
班级计划{
静态void Main(字符串[]参数){
var db=新的db();
var threads=newlist();
对于(int i=0;i<4;i++){
var one=新线程(Run2);
var two=新线程(Run1);
线程。添加(一个);
线程。添加(两个);
一、启动();
二、启动();
写入(db,1);
写入(db,2);
}
控制台。写入线(“加入”);
foreach(线程中的var线程){
thread.Join();
}
Console.WriteLine();
控制台。写入线(“完成”);
孔索