我正在使用C#和SqlServer创建WinForm应用程序。我必须处理许多数据库CRUD查询。而且形式也很多,控制器也很多。
现在我想知道的是,如果我使用许多用于打开连接,关闭连接,执行Sql命令或执行任何其他数据检索的方法来创建用于处理数据库连接的公共类。这种方法是好是坏?
或以下运行每个查询的方法是好是坏?
request
哪种方法对性能和安全性更好?
答案 0 :(得分:4)
在使用连接时,有几点需要考虑。
1)使用using语句,在不再需要连接对象时将其丢弃:
using (var conn = new SqlConnection(connectionstring))
{
// your sql magic goes here
}
2)如果您不立即处置对象,则可以使用try-finally语句确保连接已关闭:
var conn = new SqlConnection(connectionstring);
try
{
// do sql shizzle
}
finally
{
conn.Close();
}
3)为防止SQL注入,请使用参数化查询,切勿串联字符串
using (var conn = new SqlConnection(connectionstring))
{
conn.Open();
using(var comm = new SqlCommand("select * from FooBar where foo = @foo", conn))
{
comm.Parameters.Add(new SqlParameter("@foo", "bar"));
// also possible:
// comm.Parameters.AddWithValue("@foo", "bar");
using(var reader = comm.ExecuteReader())
{
// Do stuff with the reader;
}
}
}
4)如果要执行多个更新,插入或删除语句,并且它们都需要一次成功,则使用事务:
using (var conn = new SqlConnection(connectionstring))
{
conn.Open();
using(var trans = conn.BeginTransaction())
{
try
{
using(var comm = new SqlCommand("delete from FooBar where fooId = @foo", conn, trans))
{
comm.Parameters.Add(new SqlParameter { ParameterName = "@foo", DbType = System.Data.DbType.Int32 });
for(int i = 0; i < 10 ; i++)
{
comm.Parameters["@foo"].Value = i;
comm.ExecuteNonQuery();
}
}
trans.Commit();
}
catch (Exception exe)
{
trans.Rollback();
// do some logging
}
}
}
5)存储过程的用法类似:
using (var conn = new SqlConnection(connectionstring))
{
conn.Open();
using (var comm = new SqlCommand("FooBarProcedure", conn) { CommandType = CommandType.StoredProcedure })
{
comm.Parameters.Add(new SqlParameter("@FooBar", "shizzle"));
comm.ExecuteNonQuery();
}
}
(源存储过程:this Answer)
多线程:使用多线程和SQL连接的最安全方法是始终关闭并释放连接对象。这是SqlConnection设计的目的。 (来源:Answer John Skeet)
答案 1 :(得分:1)
最佳实践是创建一个通用的DBHelper类,并在该类中创建CRUD方法。 我正在添加代码段。这可能会对您有所帮助。
web.config
<connectionStrings>
<add name="mssqltips"
connectionString="data source=localhost;initial catalog=mssqltips;Integrated Security=SSPI;"
providerName="System.Data.SqlClient" />
</connectionStrings>
DBHelper.cs
//Opening Connection
public SqlConnection GetConnection(string connectionName)
{
string cnstr = ConfigurationManager.ConnectionStrings[connectionName].ConnectionString;
SqlConnection cn = new SqlConnection(cnstr);
cn.Open();
return cn;
}
//for select
public DataSet ExecuteQuery(
string connectionName,
string storedProcName,
Dictionary<string, sqlparameter=""> procParameters
)
{
DataSet ds = new DataSet();
using(SqlConnection cn = GetConnection(connectionName))
{
using(SqlCommand cmd = cn.CreateCommand())
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = storedProcName;
// assign parameters passed in to the command
foreach (var procParameter in procParameters)
{
cmd.Parameters.Add(procParameter.Value);
}
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
da.Fill(ds);
}
}
}
return ds;
}
//for insert,update,delete
public int ExecuteCommand(
string connectionName,
string storedProcName,
Dictionary<string, SqlParameter> procParameters
)
{
int rc;
using (SqlConnection cn = GetConnection(connectionName))
{
// create a SQL command to execute the stored procedure
using (SqlCommand cmd = cn.CreateCommand())
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = storedProcName;
// assign parameters passed in to the command
foreach (var procParameter in procParameters)
{
cmd.Parameters.Add(procParameter.Value);
}
rc = cmd.ExecuteNonQuery();
}
}
return rc;
}
答案 2 :(得分:0)
如果您不想每次都丢弃上下文,则可以创建存储库类并将SqlConnection注入其中。
using (SqlConnection connection = new SqlConnection("Integrated Security=SSPI;Initial Catalog=MYDB"))
{
repository.SetConnection(connection);
var values = repository.GetSomething();
}
并创建类:
public Class Repository
{
private SqlConnection _connection {get; set;}
public void SetConnection(SetConnection connection)
{
_connection = connection;
}
public string GetSomething()
{
_connection.Open();
//do stuff with _connection
_connection.Close();
}
}
无论如何,我建议您阅读有关ORM(实体框架或Dapper)和SQL注入攻击的信息。