Delphi:数据库被锁定(SQLite)

Alv*_*Lin 1 database delphi sqlite database-locking

我面临两个问题......

(1)当我尝试使用Delphi XE6写入数据库(SQLite)时,我总是得到数据库被锁定的错误消息.我确信每次使用FDConnection1.Close命令访问数据库时都会关闭数据库.

(2)如何从传入参数中插入表格?我有以下传入参数

procedure TStock_Bookkeeping.Write_To_DB(const Stock_Code, Stock_Name,
Tran_Date, Buy_Sell, Price_Per_Share, Num_Shares, Trans_Fee: string);
Run Code Online (Sandbox Code Playgroud)

并尝试使用以下SQL命令写入表:

sSQL := 'INSERT INTO Each_Stock_Owned(Stock_Code, Stock_Name, Tran_Date, Buy_Sell,
         Price_Per_Share, Num_Shares, Trans_Fee) 
         VALUES (Stock_Code, Stock_Name, Tran_Date, Buy_Sell, Price_Per_Share,  
         Num_Shares, Trans_Fee)';
Run Code Online (Sandbox Code Playgroud)

但它似乎不起作用......

以下是我遇到问题的完整程序

procedure TStock_Bookkeeping.Write_To_DB(const Stock_Code, Stock_Name,
  Tran_Date, Buy_Sell, Price_Per_Share, Num_Shares, Trans_Fee: string);
var
  query : TFDQuery;
  sSQL: string;
begin
    query := TFDQuery.Create(nil);
  try
    ConnectToSQLite;
    query.Connection := FDConnection1;
  if Stock_Code.IsEmpty then
    ShowMessage('Stock Code Cannot Be Empty')
    else
      if Stock_Name.IsEmpty then
        ShowMessage('Stock Name Cannot Be Empty')
        else
          if Tran_Date.IsEmpty then
            ShowMessage('Transaction Date Cannot Be Empty')
            else
            begin
//              sSQL := 'INSERT INTO Each_Stock_Owned(Stock_Code, Stock_Name, Tran_Date, Buy_Sell, Price_Per_Share, Num_Shares, Trans_Fee) VALUES (Stock_Code, Stock_Name, Tran_Date, Buy_Sell, Price_Per_Share, Num_Shares, Trans_Fee)';
              sSQL := 'INSERT INTO Each_Stock_Owned(Stock_Code, Stock_Name, Tran_Date, Buy_Sell, Price_Per_Share, Num_Shares, Trans_Fee) VALUES (1,2,3,4,5,6,7)';
              query.sql.Text := sSQL;
              query.ExecSQL;
              query.Open();
        end;
  finally
    query.Close;
    query.DisposeOf;
    DisconnectFromSQLite;
  end;

end;
Run Code Online (Sandbox Code Playgroud)

任何提示将非常感激.提前致谢.

Fra*_*azz 6

执行动态SQL语句有两种方法.但我会使用更短的SQL,专注于逻辑:

纯粹的方式(使用参数)

q.SQL.Text:=
  'INSERT INTO Each_Stock_Owned (Stock_Code, Stock_Name) '+
  'VALUES (:Stock_Code, :Stock_Name)';
q.Prepare; //Optional
q.ParamsByName('Stock_Code').AsString := Stock_Code;
q.ParamsByName('Stock_Name').AsString := Stock_Name;
q.ExecSQL;
Run Code Online (Sandbox Code Playgroud)

肮脏的方式(构建SQL)

q.SQL.Text:=
  'INSERT INTO Each_Stock_Owned (Stock_Code, Stock_Name) VALUES ('+
  QuotedStr(Stock_Code) + ', '+
  QuotedStr(Stock_Name) + ')';
q.ExecSQL;
Run Code Online (Sandbox Code Playgroud)

差异很大.肮脏的方式会让您暴露于SQL注入问题(就像在大多数其他语言中,当您以语音方式构建SQL但没有参数时).这对您来说可能是一个问题,也可能不是问题.如果您知道该过程仅由您自己的代码私有调用,并且那些过程参数值只能包含好的值...或者如果您在构建和执行SQL之前进行了一些好的参数检查...那么您就是安全的.

但是如果使用参数(纯方式)执行此操作,则会自动保护SQL注入,因为引擎会验证SQL语句,而不知道参数值.因此,引用已知SQL语句结构,并且不能通过实际值更改.

另一个考虑因素是执行INSERT语句的频率.纯方法允许您准备查询ONCE,并使用不同的参数值执行多次(您不能销毁查询对象,也不能更改SQL属性,并且必须调用一次Prepare方法).如果你在一个循环中经常运行它,那么它比以脏方式多次构建SQL更有效.OTOH如果你只需要插入一行,它可能会带来更多的开销.

=================

旁白...... CL是对的......这些值不应该是字符串.请记住,Parameter对象具有许多属性来处理不同的数据类型:

  q.ParamsByName('somedate').AsDateTime := Date;
  q.ParamsByName('somenumeric').AsFloat := 3/4;
Run Code Online (Sandbox Code Playgroud)

... 等等.

如果你不使用参数,那么事情就变得困难了.QuoteStr函数适用于字符串,但如果要直接在SQL中刻录日期和货币以及其他值类型,则必须知道自己在做什么.您可能会遇到许多不同的问题...特定于区域设置或格式设置不利于与您的服务器通信,这可能位于世界的另一端,或者可能无法读取以这种方式格式化的值.您可能必须处理特定于引擎的格式和转换问题.

如果您使用参数,那么FireDAC应该为您处理所有这些;)