在C#中使用MYSQL:
我有一组我想要执行的参数化IDbCommands。这是更新,插入和删除的混合,现在我正在做:
using (IDbConnection connection = Connecter.CreateConnection())
{
foreach(IDBCommand command in m_commands)
{
command.Connection = connection;
command.ExecuteNonQuery();
}
}
命令大量使用参数,所以我不能只将每个命令的命令文本组合在一起。表现非常糟糕,我知道必须有更好的方法。
使用MYSql Bulk更新可以接受,但我不清楚如何将参数值转换为文件而不会有SQL注入攻击的风险。
有人有任何建议吗?
(我把所有命令都绑定在事务中,这有助于一些但不够)
答案 0 :(得分:1)
如果要对同一个表应用多个插入/更新/删除,请考虑使用MySqlDataAdapter / DataTable组合来批处理语句。设置MySqlDataAdapter的UpdateBatchSize属性将启用/禁用批处理支持。因此,可以在一次旅行中将同一表上的插入/更新/删除发送到DB。
我已经完成了OracleDataAdapter和SqlDataAdapter,性能显着提升。 MySqlDataAdapter似乎也实现了基本的批处理(虽然没有实际测试过它)。
一个建议是创建自己的包装类,它以某种形式的DbCommandBatch类隐藏底层的DbDataAdapter / DataTable类。然后,该类可以从IDbCommand模板构建所需的DataTable支持,并最终像命令一样组合在一起。
public interface IDbBatchCommandFactory
{
IDbCommandBatch Create(IDbCommand templateCommand);
}
因此,如果需要,Create方法实际上可以从模板命令构建所需的DataTable(通过迭代现有的参数集合,可以使生活更轻松,具体取决于您已有的代码)。然后,这可以创建一个实现类似接口的类:
public interface IDbBatchCommand : IDisposable
{
void AddToBatch(ParameterCollection parameters);
void ExecuteBatch(IDbTransaction transaction);
}
如果这是您需要的正确轨道,我可以提供示例代码。如果每个命令彼此不同(即,总是不同的表等),那么这将不提供任何值。
注意:在一个完美的世界中,像SqlCommandSet等类可以公开使用,以避免不必这样做。
答案 1 :(得分:0)
我没有太多使用MySQL的经验,因此我不熟悉它拥有的批量更新功能。对于您想要做的事情来说,这听起来很有希望,但在使用批量更新之前,您是否有必要首先将数据保存为文件。
我不确定MySQL是否有类似的东西,但是ADO.NET provides a SqlBulkCopy command与SQL Server一起使用。这基本上允许您直接从代码提供的数据读取器将数据插入数据库,从而无需创建文件,因此无需担心与字符串相关的问题。
MySQL 4.1 has prepared statements。除参数值外,这些命令是否完全相同?我想知道如果你试图利用IDbCommand.Prepare方法,你是否会看到更好的性能:
using (IDbConnection connection = Connector.CreateConnection())
{
var command = connection.CreateCommand();
command.CommandText = "<command text>";
var paramA = command.CreateParameter();
paramA.ParameterName = "ParameterA";
paramA.DbType = DbType.Int32;
command.Parameters.Add(paramA);
var paramB = command.CreateParameter();
paramB.ParameterName = "ParameterB";
paramB.DbType = DbType.String;
command.Parameters.Add(paramB);
var paramC = command.CreateParameter();
paramC.ParameterName = "ParameterC";
paramC.DbType = DbType.Decimal;
command.Parameters.Add(paramC);
command.Prepare();
foreach (ProcedureArgs args in m_procedureArgs)
{
paramA.Value = args.ParamA;
paramB.Value = args.ParamB;
paramC.Value = args.ParamC;
command.ExecuteNonQuery();
}
}