多个语句Delphi TZquery(Zeos)错误

时间:2013-05-26 12:45:59

标签: mysql delphi delphi-xe3 zeos

我试图像这样做一个多语句查询:

// 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命令来阻止此自动提交,直到您明确地称之为提交。

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

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

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

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

4 个答案:

答案 0 :(得分: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注入风险,并且多个语句不再需要的。

答案 1 :(得分:3)

尝试使用此代码,如果出现同样的问题,请告诉我们:

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

通过这种方式,您还可以加快对这个INSERT查询的MySQL处理速度,就像它在一个批处理中一样,而不是两次。

编辑#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 交易

One question on Stackoverflow有许多关于在MySQL中使用事务的好例子。虽然这些例子是为PHP编写的,但我相信你可以在那里找到一些好的指针。确保MySQL服务器上的表格为InnoDB而不是MyISAM

答案 2 :(得分:1)

我也不是ZEOS的专家,但是看the source,您是否将MultiStatements的{​​{1}}属性设置为true?

答案 3 :(得分:0)

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

{**
  Implements a unidatabase component which parses and executes SQL Scripts.
}