5

我试图像这样进行多语句查询:

// without the second insert the query works fine.
// i need 2 querys to work because later, i'll do inserts on different kind of tables.
// that's why i need 2 querys, not a single query which insert 2 records.   

with ZQuery1 do
    begin
        SQL.Clear;
        SQL.Add('insert into client (name,age) values ('+QuotedStr('john')+','+QuotedStr('20')+');');
        SQL.Add('insert into client (name,age) values ('+QuotedStr('doe')+','+QuotedStr('21')+');');
        ExecSQL;
    end;

我收到此错误消息: SQL 错误:您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以在第 2 行的“插入客户端(名称,年龄)值('doe','21')'附近使用正确的语法;

我已经检查了手册,组件 TZQuery 和 TZUpdateSql (来自 zeos lib )提供了在内部执行多个语句的可能性。

编辑[已解决]

谢谢 GregD,在运行了几次测试后,交易对我来说很好!这就是我如何使用,在未来帮助他人。

try
    ZConnection.AutoCommit := True;
    ZConnection.StartTransaction;
    
    With ZQuery Do
    begin
        SQL.Clear;
        SQL.Add('insert into clients (name,age) values ('+QuotedStr('john')+','+QuotedStr('20')+')');
        ExecSQL;
        SQL.Clear;
        SQL.Add('insert into clients (name,age) values ('+QuotedStr('doe')+','+QuotedStr('21')+')');
        ExecSQL;
    end;
    
    ZConnection.Commit; 
except
    ZConnection.Rollback
end;

这就是 AutoCommit 属性在 Zeos 中的实际工作方式:

AutoCommit为 True 时,事务会在每条 SQL 语句执行后自动提交,但您可以显式使用 StartTransaction 命令来防止这种自动提交,直到您显式调用 Commit。

AutoCommit为 False 时,您不应调用 StartTransaction。然后事务会自动启动,但不会在每条执行语句后自动提交。

过程StartTransaction StartTransaction 过程在连接的数据库中启动一个新事务。它应该只在 AutoCommit 属性为 TRUE 时使用。每当您尝试在 AutoCommit 设置为 false 的情况下调用它时,都会引发 SInvalidOpInNonAutoCommit。这种行为是意料之中的,因为 StartTransaction 应该用作对 AutoCommit 模式的转义。当您调用 StartTransaction 时,AutoCommit 将“关闭”,然后,当您调用 Commit 或 Rollback 时,AutoCommit 再次“打开”。如果您将 AutoCommit 设置为 false,则会自动创建新事务并选择关闭它们的方式(提交或回滚)。

过程Commit将当前语句提交到数据库。仅应在非 AutoCommit 模式下使用(其中每个语句都是自动提交的,使此过程无用)或当您处于 AutoCommit 模式并希望完成由 StartTransaction 过程打开的事务时。提交完成当前事务,如果有的话。如果您不想将您的数据保存到数据库中,您应该使用回滚过程。

过程回滚 回滚当前事务中所有先前的语句。仅应在非 AutoCommit 模式下使用(其中每个语句都是自动提交的,使此过程无用)或当您处于 AutoCommit 模式并希望完成由 StartTransaction 过程打开的事务时。回滚完成当前事务,如果有的话。如果您不想丢失您的状态,您应该使用 Commit 过程。

4

4 回答 4

5

我对 Zeos 和多个语句一无所知,但这并不是真正的问题。您的查询(SQL 注入)和执行它们的方法很慢(无法缓存和重用的连接字符串)导致了一个主要的安全问题。

如果您正确地停止使用字符串连接来形成查询,而是使用参数化语句,则根本不需要担心多个语句:

with ZQuery1 do
begin
  SQL.Clear;
  SQL.Add('insert into client (name,age)');
  SQL.Add('values (:Name, :Age);'
  ParamByName('Name').AsString := 'John';
  ParamByName('Age').AsInteger := 20;
  ExecSQL;
  ParamByName('Name').AsString := 'Doe';
  ParamByName('Age').AsInteger :- 21;
  ExecSQL;
end;

查询现在将运行得更快(因为 DBMS 可以编译一次并多次重用它(我提到的“缓存”),您不再有 SQL 注入风险,并且不再需要多个语句。

于 2013-05-26T16:34:48.923 回答
2

试试这段代码,如果出现同样的问题,请告诉我们:

with ZQuery1 do
begin
    SQL.Clear;
    SQL.Add('insert into client (name,age) values ('+QuotedStr('john')+','+QuotedStr('20')+'),('+QuotedStr('doe')+','+QuotedStr('21')+');');
    ExecSQL;
end;

这样,您还可以加快 MySQL 处理此INSERT查询的速度,就像它在一批中而不是两次中那样。

编辑#1:

我不是 Zeos 方面的专家,但是对于其他语言,您可以尝试一一执行查询:

with ZQuery1 do
    begin
        SQL.Clear;
        SQL.Add('insert into client (name,age) values ('+QuotedStr('john')+','+QuotedStr('20')+');');
        ExecSQL;
        SQL.Clear;
        SQL.Add('insert into client (name,age) values ('+QuotedStr('doe')+','+QuotedStr('21')+');');
        ExecSQL;
    end;

编辑#2交易

Stackoverflow 上的一个问题有很多关于在 MySQL 中使用事务的好例子。虽然这些示例是为 PHP 编写的,但我相信您可以在那里找到一些好的指针。确保 MySQL 服务器上的表InnoDB不是MyISAM.

于 2013-05-26T12:59:13.907 回答
1

我也不是 ZEOS 方面的专家,但是查看源代码,您是否将MultiStatements属性设置TZUpdateSQL为 true?

于 2013-05-26T13:43:57.133 回答
1

你试过 TZSQLProcessor 吗?说该组件是为这样的需求而制作的(如在 ZSqlProcessor.pas 单元中):

{**
  Implements a unidatabase component which parses and executes SQL Scripts.
}
于 2015-05-16T15:39:53.603 回答