我试图像这样做一个多语句查询:
// 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完成当前事务,如果有的话。如果您不想丢失您的声明,则应使用提交程序。
答案 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.
}