在Delphi中使用SQLite附加-分离时出错
我在使用Delphi(Firedac)的SQLite中遇到了一个无法解决的附加和分离问题 我连接了一个数据库文件,并附加了第二个数据库文件:在Delphi中使用SQLite附加-分离时出错,sqlite,delphi,delphi-10-seattle,Sqlite,Delphi,Delphi 10 Seattle,我在使用Delphi(Firedac)的SQLite中遇到了一个无法解决的附加和分离问题 我连接了一个数据库文件,并附加了第二个数据库文件: FDConnection1.ExecSQL('ATTACH DATABASE "' + Import_DB_filename + '" AS IMPORTDB;'); 其中,变量“Import_DB_filename”包含数据库文件的完整路径和文件名 这工作正常,我可以通过FireDac查询访问连接中的两个数据库,并且可以毫无问题地进行编码。 但是,分离
FDConnection1.ExecSQL('ATTACH DATABASE "' + Import_DB_filename + '" AS IMPORTDB;');
其中,变量“Import_DB_filename”包含数据库文件的完整路径和文件名
这工作正常,我可以通过FireDac查询访问连接中的两个数据库,并且可以毫无问题地进行编码。
但是,分离时会出现问题:
FDConnection1.ExecSQL('DETACH DATABASE IMPORTDB;');
在调试模式下,我总是得到错误:
调试器异常通知E Project My_Program.EXE引发异常类$C0000005,消息为“0x00405d7b处的访问冲突:读取地址0x00000000” 显然内存分配出了问题,因为调试器在(汇编)函数
sysfreemm(p:Pointer):Integer中停止代码>在GETMEM.INC
中
无论我尝试什么,错误都会持续存在,并导致内存泄漏,最终导致编译器崩溃(Delphi Seattle Enterprise)
即使在不传递任何代码的情况下附加和随后分离数据库,也会导致相同的错误
(FD连接:锁定模式=lmNormal;
JournalMode=jmOff或jmWALL或jmdelete)
我真的希望你能帮我解决这个持久的问题。如果你运行下面的项目,你会发现:
- 您可以使用单独的FDConnections和FDTables非常愉快地访问两个Sqlite数据库
- 可以使用FireDAC FDDataMove组件将数据从一个db中的表移动到另一个db中同名的表
代码:
可以肯定的是:您已经有了一个正确的连接,现在您想使用添加另一个数据库文件到当前连接?请将您的问题包括在Delphi版本中。为什么需要对两个数据库文件使用相同的FD连接?为什么不为它们各自建立一个单独的连接呢?老实说,我不确定我是否已经尝试过了。我会检查的。谢谢你的建议。我想使用一个FDConnection,因为我使用“insert…select”语句将数据从第二个数据库复制到现有数据库中。不管怎样,如果你在代码中生成Sql语句,你都可以这样做。谢谢MartynA,谢谢MartynA,您让我相信,使用两个FDConnection组件是避免使用ATTACH和DETACH的好方法。我已经相应地更改了代码。但是,错误仍然存在。显然,它和连接关系不大,而是和记忆分配有关。我一定是在什么地方搞砸了。也许你能提示我如何解决这些错误。我安装了MadExcept,但它没有给我任何线索。不幸的是,十六进制地址对我来说就像中文一样。好吧,“读取地址0x00000000”表明有些东西没有正确初始化,可能是一个Delphi对象,它以前被访问过。Create()被调用过。确保在项目选项中启用了“使用调试DCU”,然后进行项目构建并运行。当错误发生时,在IDE中转到查看|调试窗口|调用堆栈,然后您应该能够向下查看堆栈并查看异常发生的位置。
unit BatchMoveu;
interface
[...]
type
TForm3 = class(TForm)
FDConnection1: TFDConnection;
DBGrid1: TDBGrid;
DataSource1: TDataSource;
DBNavigator1: TDBNavigator;
FDGUIxWaitCursor1: TFDGUIxWaitCursor;
FDPhysSQLiteDriverLink1: TFDPhysSQLiteDriverLink;
Button1: TButton;
FDTable1: TFDTable;
FDConnection2: TFDConnection;
DataSource2: TDataSource;
DBGrid2: TDBGrid;
btnBatchMove: TButton;
FDDataMove1: TFDDataMove;
FDTable2: TFDTable;
procedure btnBatchMoveClick(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
procedure PopulateTable1;
procedure TestDataMove;
public
procedure CreateDatabase(DBName : String; FDConnection : TFDConnection;
FDTable : TFDTable);
end;
var
Form3: TForm3;
implementation
{$R *.dfm}
const
DBName1 = 'd:\delphi\code\sqlite\db1.sqlite';
DBName2 = 'd:\delphi\code\sqlite\db2.sqlite';
procedure TForm3.Button1Click(Sender: TObject);
begin
CreateDatabase(DBName1, FDConnection1, FDTable1);
CreateDatabase(DBName2, FDConnection2, FDTable2);
PopulateTable1;
FDTable2.Open;
end;
procedure TForm3.CreateDatabase(DBName : String; FDConnection : TFDConnection;
FDTable : TFDTable);
var
AField : TField;
i : Integer;
begin
if FileExists(DBName) then
DeleteFile(DBName);
AField := TLargeIntField.Create(Self);
AField.FieldName := 'ID';
AField.DataSet := FDTable;
AField.Name := AField.DataSet.Name + 'IDField';
AField := TWideStringField.Create(Self);
AField.Size := 80;
AField.FieldName := 'Name';
AField.DataSet := FDTable;
AField.Name := AField.DataSet.Name + 'NameField';
FDConnection.Params.Values['database'] := DBName;
FDConnection.Connected:= True;
FDTable.CreateTable(False, [tpTable]);
end;
procedure TForm3.PopulateTable1;
var
i : Integer;
begin
FDTable1.Open;
for i:= 1 to 1000 do begin
FDTable1.InsertRecord([i, 'Row ' + IntToStr(i)]);
end;
FDTable1.Close;
//FDConnection1.Commit;
FDTable1.Open;
end;
procedure TForm3.TestDataMove;
var
Item : TFdMappingItem;
begin
Item := FDDataMove1.Mappings.Add;
Item.SourceFieldName := 'ID';
Item.DestinationFieldName := 'ID';
Item := FDDataMove1.Mappings.Add;
Item.SourceFieldName := 'Name';
Item.DestinationFieldName := 'Name';
FDDataMove1.Source := FDTable1;
FDDataMove1.Destination := FDTable2;
FDDataMove1.Options := FDDataMove1.Options - [poOptimiseSrc];
FDDataMove1.Execute;
FDConnection2.Connected := False;
FDTable2.Open;
end;
procedure TForm3.btnBatchMoveClick(Sender: TObject);
begin
TestDataMove;
end;
procedure TForm3.FormDestroy(Sender: TObject);
begin
FDConnection1.Close;
end;
end.