日期:2014-05-16  浏览次数:21233 次

发现ACCESS的BUG
先创建一个表,
然后启用事务,
接着删除一个不存在的记录,
再删除表,
最后结束事务,
运行时在删除表时出错,
ADO的报错信息是:
由于表 'ssss' 正被别的用户或进程使用,数据库引擎无法锁定它。
以上代码在使用Oracle时顺利运行通过,
唯独ACCESS不行,
如果去掉事务的代码就没问题,
如果只去掉删除记录的代码也没问题,
如果把删除记录的代码更换成检索记录也没问题,
但事务和删除记录的代码同时存在就有问题,
我是在VS2008上使用ADO,
Microsoft.Jet.OLEDB.4.0和Microsoft.ACE.OLEDB.12.0都试过,
都有这个问题,
怎么看都像是ACCESS的BUG。

代码如下:
#include <locale.h>
#include <atlstr.h>
#include <atlcom.h>
#import "c:\Program Files\Common Files\System\ado\msado15.dll" rename_namespace("ADO_ns") rename("EOF","ADO_EOF")
#import "c:\Program Files\Common Files\system\ado\msadox.dll" rename_namespace("ADO_EX_ns")


void Init(ADO_ns::_ConnectionPtr& clConnection)
{
  if (FAILED(clConnection.CreateInstance(__uuidof(ADO_ns::Connection))))
  {
  throw 0;
  }
  try
  {
  ADO_EX_ns::_CatalogPtr clLocal = NULL;
  if (FAILED(clLocal.CreateInstance((__uuidof(ADO_EX_ns::Catalog)))))
  {
  throw 0;
  }
  clLocal->Create(_bstr_t(_T("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=e:\\AAAA.accdb;")));
  clConnection->Open(_bstr_t(_T("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=e:\\AAAA.accdb;")), _bstr_t(), _bstr_t(), ADO_ns::adModeUnknown);
  }
  catch (const _com_error& clErr)
  {
  wprintf(LPCTSTR(clErr.Description()));
  throw 0;
  }
}
void Execute(ADO_ns::_ConnectionPtr& clConnection, const CString& clSQL)
{
  _variant_t clRecordsAffected;
  try
  {
  clConnection->Execute(_bstr_t(clSQL), &clRecordsAffected, ADO_ns::adCmdText | ADO_ns::adExecuteNoRecords);
  }
  catch (const _com_error& clErr)
  {
  wprintf(LPCTSTR(clErr.Description()));
  throw 0;
  }
}
int _tmain(int argc, _TCHAR* argv[])
{
  setlocale(LC_ALL, "chs");
  CoInitialize(NULL);
  ADO_ns::_ConnectionPtr clConnection;
  Init(clConnection);
  Execute(clConnection, _T("create table ssss(ss integer)"));
  clConnection->BeginTrans();
  Execute(clConnection, _T("delete from ssss where ss=11"));
  Execute(clConnection, _T("drop table ssss"));
  clConnection->CommitTrans();
  clConnection.Release();
  CoUninitialize();
  return 0;
}



------解决方案--------------------
应该不是BUG,各个数据库对同一个标准的解释和理解不同。

delete from table1 where id<0 
drop table table1;

打开事务后,理论上,DDL语句应该自动提交一个commit; 但ACCESS中显然先做了检查。
------解决方案--------------------
在ACCESS中用VBA测试:
CurrentProject.Connection.Execute "begin TRANSACTION"
CurrentProject.Connection.Execute "create table try1(id int,bh varchar(10))"
CurrentProject.Connection.Execute "create table try2(id int,bh varchar(10))"
CurrentProject.Connection.Execute "insert into try1 values(1,'2')"
CurrentProject.Connection.Execute "delete from try1 where id=5"
CurrentProject.Connection.Execute "drop table try1"
CurrentProject.Connection.Execute "COMMIT TRANSACTION"

没有问题啊,DDL可以回滚