在MYSQL中将参数化命令拼凑在一起

时间:2010-11-18 19:32:52

标签: c# mysql

在C#中使用MYSQL:

我有一组我想要执行的参数化IDbCommands。这是更新,插入和删除的混合,现在我正在做:


using (IDbConnection connection = Connecter.CreateConnection())
{
   foreach(IDBCommand command in m_commands)
   {
     command.Connection = connection;
     command.ExecuteNonQuery();
   }
}

命令大量使用参数,所以我不能只将每个命令的命令文本组合在一起。表现非常糟糕,我知道必须有更好的方法。

使用MYSql Bulk更新可以接受,但我不清楚如何将参数值转换为文件而不会有SQL注入攻击的风险。

有人有任何建议吗?

(我把所有命令都绑定在事务中,这有助于一些但不够)

2 个答案:

答案 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();
            }
        }