database - Delphi:数据库被锁定(SQLite)

标签 database sqlite delphi database-locking

我面临两个问题...

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

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

procedure TStock_Bookkeeping.Write_To_DB(const Stock_Code, Stock_Name,
Tran_Date, Buy_Sell, Price_Per_Share, Num_Shares, Trans_Fee: string);

并尝试使用以下 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)';

但是好像不行...

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

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;

任何提示将不胜感激。提前致谢。

最佳答案

执行动态 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;

肮脏的方式(构建 SQL)

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

差异显着。肮脏的方式使您面临 SQL 注入(inject)问题(与大多数其他语言一样,当您动态构建 SQL 但没有参数时)。这对您来说可能是问题,也可能不是问题。如果您知道该过程仅由您自己的代码私下调用,并且那些过程参数值只能包含良好的值……或者如果您在构建和执行 SQL 之前进行了一些良好的参数检查……那么您就安全了.

但是,如果您使用参数(纯粹的方式)执行此操作,您将自动受到 SQL 注入(inject)的保护,因为引擎会验证 SQL 语句,而无需知道参数值。所以SQL语句结构是引擎已知的,不能被实际值改变。

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

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

顺便说一句……CL 是对的……那些值不应该是字符串。请记住,Parameter 对象有许多属性来处理不同的数据类型:

  q.ParamsByName('somedate').AsDateTime := Date;
  q.ParamsByName('somenumeric').AsFloat := 3/4;

...等等。

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

如果您确实使用了参数,那么 FireDAC 应该会为您处理所有这一切 ;)

关于database - Delphi:数据库被锁定(SQLite),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25052400/

相关文章:

Delphi DBGrid 项目中所有 DBGrid 的备用行颜色

delphi - Shell 函数的失败返回值

c# - 为 Localhost c# 使用 Oledb 连接字符串

java - 应用程序安装时用户指定的应用程序路径

java - Java 中 PHP PDO 的等价物

SQLite CASE/WHEN 语句

Java Servlet 插入 MySQL

node.js - 在 OSX 上安装和运行 MongoDB

android - 查找 sqlite 表的缺失行

delphi - 如何消除TPaintBox右边缘的闪烁(例如调整大小时)