我正在尝试压缩Microsoft Access数据库,但下面显示的代码不起作用。
procedure TForm1.Disconnect1Click(Sender: TObject);
begin
ADODataSet1.Active := False;
ADOTable1.Active := False;
ADODataSet1.Connection := nil;
DataSource1.Enabled := False;
ADOConnection1.Connected := False;
JetEngine1.Disconnect;
end;
function DatabaseCompact(const sdbName: WideString): boolean;
{ Compact ADO mdb disconnected database. }
var
iJetEngine: TJetEngine; { Jet Engine }
iTempDatabase: WideString; { TEMP database }
iTempConn: WideString; { Connection string }
const
iProvider = 'Provider=Microsoft.Jet.OLEDB.4.0; Data Source=';
begin
Result := False;
iTempDatabase := ExtractFileDir(sdbName) + 'TEMP' + ExtractFileName(sdbName);
iTempConn := iProvider + iTempDatabase;
if FileExists(iTempDatabase) then
DeleteFile(iTempDatabase);
iJetEngine := TJetEngine.Create(Application);
try
try
iJetEngine.CompactDatabase(iProvider + sdbName, iTempConn);
DeleteFile(sdbName);
RenameFile(iTempDatabase, sdbName);
except
on E: Exception do
ShowMessage(E.Message);
end;
finally
iJetEngine.FreeOnRelease;
Result := True;
end;
end;
procedure TForm1.Compact1Click(Sender: TObject);
var
iResult: Integer;
begin
AdvTaskDialog1.Clear;
AdvTaskDialog1.Title := 'Compact Database';
AdvTaskDialog1.Instruction := 'Compact Database';
AdvTaskDialog1.Content := 'Compact the database?';
AdvTaskDialog1.Icon := tiQuestion;
AdvTaskDialog1.CommonButtons := [cbYes, cbNo];
iResult := AdvTaskDialog1.Execute;
if iResult = mrYes then
begin
Screen.Cursor := crHourglass;
try
DatabaseCompact('D:\RadProjects10\EBook Database\EBook Database.mdb');
ADODataSet1.Connection := ADOConnection1;
ADOConnection1.Connected := True;
finally
Screen.Cursor := crDefault;
end;
end;
end;
procedure TForm1.Connect1Click(Sender: TObject);
begin
ADOConnection1.ConnectionString := 'Provider=Microsoft.Jet.OLEDB.4.0;' +
'User ID=Admin;' +
'Data Source=D:\RadProjects10\EBook Database\EBook Database.mdb;' +
'Mode=Share Deny None;' + 'Jet OLEDB:System database="";' +
'Jet OLEDB:Registry Path="";' + 'Jet OLEDB:Database Password="";' +
'Jet OLEDB:Engine Type=5;' + 'Jet OLEDB:Database Locking Mode=1;' +
'Jet OLEDB:Global Partial Bulk Ops=2;' +
'Jet OLEDB:Global Bulk Transactions=1;' +
'Jet OLEDB:New Database Password="";' +
'Jet OLEDB:Create System Database=False;' +
'Jet OLEDB:Encrypt Database=False;' +
'Jet OLEDB:Don''t Copy Locale on Compact=False;' +
'Jet OLEDB:Compact Without Replica Repair=False;' + 'Jet OLEDB:SFP=False;';
ADODataSet1.Connection := ADOConnection1;
ADOConnection1.Connected := True;
ADODataSet1.Active := True;
ADOTable1.Active := True;
DataSource1.Enabled := True;
end;
即使我在压缩之前断开了数据库,我收到一条错误消息:
您试图打开已由计算机'xxxx'上的用户'Admin'专门打开的数据库。数据库可用时再试一次。
我断开然后紧凑但是出了点问题。我知道压缩Access数据库是好的,所以我试图用我编写的一个小应用程序来存储联系信息。
显然我用来与数据库断开连接的代码不起作用。我在哪里失败了?
答案 0 :(得分:8)
关闭与其关联的TADOConnection
和所有数据集后,您需要确保数据库已解锁。请记住,其他用户可能连接到数据库,在这种情况下,您无法压缩它。
在实际压缩数据库之前,您必须给喷气引擎一点时间来实际关闭连接,刷新和解锁数据库。然后测试db是否被锁定(尝试打开以供独占使用)。
这是我使用的方法,它总是对我有用:
uses ComObj;
procedure JroRefreshCache(ADOConnection: TADOConnection);
var
JetEngine: OleVariant;
begin
if not ADOConnection.Connected then Exit;
JetEngine := CreateOleObject('jro.JetEngine');
JetEngine.RefreshCache(ADOConnection.ConnectionObject);
end;
procedure JroCompactDatabase(const Source, Destination: string);
var
JetEngine: OleVariant;
begin
JetEngine := CreateOleObject('jro.JetEngine');
JetEngine.CompactDatabase(
'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' + Source,
'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' + Destination + ';Jet OLEDB:Engine Type=5');
end;
procedure CompactDatabase(const MdbFileName: string;
ADOConnection: TADOConnection=nil;
const ReopenConnection: Boolean=True);
var
LdbFileName, TempFileName: string;
FailCount: Integer;
FileHandle: Integer;
begin
TempFileName := ChangeFileExt(MdbFileName, '.temp.mdb');
if Assigned(ADOConnection) then
begin
// force the database engine to write data to disk, releasing locks on memory
JroRefreshCache(ADOConnection);
// close the connection - this will also close all associated datasets
ADOConnection.Close;
end;
// ADOConnection.Close SHOULD delete the ldb
// force delete of ldb lock file just in case if we don't have an active ADOConnection
LdbFileName := ChangeFileExt(MdbFileName, '.ldb');
if FileExists(LdbFileName) then
DeleteFile(LdbFileName); // could fail because data is still locked - we ignore this
// delete temp file if any
if FileExists(TempFileName) then
if not DeleteFile(TempFileName) then
RaiseLastOSError;
// try to open for exclusive use
FailCount := 0;
repeat
FileHandle := FileOpen(MdbFileName, fmShareExclusive);
try
if FileHandle = -1 then // error
begin
Inc(FailCount);
Sleep(100); // give the database engine time to close completely and unlock
end
else
begin
FailCount := 0;
Break; // success
end;
finally
FileClose(FileHandle);
end;
until FailCount = 10; // maximum 1 second of attempts
if FailCount <> 0 then // file is probably locked by another user/process
raise Exception.Create(Format('Error opening %s for exclusive use.', [MdbFileName]));
// compact the db
JroCompactDatabase(MdbFileName, TempFileName);
// copy temp file to original mdb and delete temp file on success
if Windows.CopyFile(PChar(TempFileName), PChar(MdbFileName), False) then
DeleteFile(TempFileName)
else
RaiseLastOSError;
// reopen ADOConnection
if Assigned(ADOConnection) and ReopenConnection then
ADOConnection.Open;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
CompactDatabase('F:\Projects\DB\mydb.mdb', ADOConnection1, True);
// reopen DataSets
ADODataSet1.Open;
end;
确保在IDE(设计模式)中将TADOConnection
不设置为Connected
。
因为如果有,则与db的另一个活动连接。
答案 1 :(得分:-2)
uses ComObj;
// with or without password
procedure CompactDatabasev2(const MdbFileName: string; const PW:string='');
var
LdbFileName, TempFileName: string;
FailCount: Integer;
FileHandle: Integer;
JetEngine: OleVariant;
begin
TempFileName := ChangeFileExt(MdbFileName, '.temp.mdb');
LdbFileName := ChangeFileExt(MdbFileName, '.ldb');
if FileExists(LdbFileName) then
DeleteFile(LdbFileName); // could fail because data is still locked - we ignore this
if FileExists(TempFileName) then // delete temp file if any
if not DeleteFile(TempFileName) then
RaiseLastOSError;
// try to open for exclusive use
FailCount := 0;
repeat
FileHandle := FileOpen(MdbFileName, fmShareExclusive);
try
if FileHandle = -1 then // error
begin
Inc(FailCount);
Sleep(100); // give the database engine time to close completely and unlock
end
else
begin
FailCount := 0;
Break; // success
end;
finally
FileClose(FileHandle);
end;
until FailCount = 10; // maximum 1 second of attempts
if FailCount <> 0 then // file is probably locked by another user/process
raise Exception.Create(Format('Error opening %s for exclusive use.', [MdbFileName]));
if PW='' then
// DB DE PAROLA YOKSA
begin
JetEngine := CreateOleObject('jro.JetEngine');
JetEngine.CompactDatabase(
'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' + MdbFileName
, 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' + TempFileName + ';Jet OLEDB:Engine Type=5'
);
end
else
// DB PAROLA VARSA
begin
JetEngine := CreateOleObject('jro.JetEngine');
JetEngine.CompactDatabase(
'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' + MdbFileName + ';Jet OLEDB:Database Password='+PW
, 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' + TempFileName +';Jet OLEDB:Database Password='+PW+';Jet OLEDB:Engine Type=5') ;
end;
// copy temp file to original mdb and delete temp file on success
if CopyFile(PChar(TempFileName), PChar(MdbFileName), False) then
DeleteFile(TempFileName)
else
RaiseLastOSError;
end;