通过传递数据库句柄(TDatabase::Handle)给dll,以及在dll中多线程访问的问题?

时间:2021-01-16 18:32:47
一个主窗口,连接数据库。有一个TSession对象MSession,以及所属的TDatabase对象MDatabase。想通过参数传递将数据库的句柄 MDatabase->Handle 传递给dll,以实现数据库连接的共享,并且每个dll中的访问是线程独立的,也就是说与主窗口不在一个线程中。遇到如下问题:

1、dll中数据库句柄的使用,动态创建一个数据库对象,然后将句柄赋值。而创建的记录集(TTable, TQuery)找不到动态创建的数据库名称。不过我创建了一个窗口,然后添加将数据库组件。dll初始化的时侯就创建窗口,将数据库句柄赋值后打开(TDatabase::Open()),可以正常通过数据库名(TDatabase::DatabaseName)访问。是否有更好的办法?

2、多线程对数据库经行查询的时侯(不同的线程不会访问同一个表,也就是说每个线程有单独的表数据,只是要共享连接而已),有不确定的时侯查询不出数据,时而对时而错。但是在查询(TQuery::Open())和判断(TQuery::RecordCount == 0)之间对数据库进行任何操作(如调用主窗口函数插入数据,或者加两句:MQuery->Database->StartTransaction(); MQuery->Database->Commit();)以后正常(得到正常的记录数)。请问如何解决?

多写高手不吝赐教!

15 个解决方案

#1


还有,我用的是 SQL Server 配置的 ODBC, BCB 5.5 和 BCB 6.0 的句柄会不会冲突?

对写 ==> 多谢 !

#2


还有:

我用的是 MS SQL Server,配置 ODBC
BCB 5.5 和 BCB 6.0 的句柄会不会冲突?

对写 ==> 多谢 !

#3


人呢?

#4


我不知道 帮你顶一下

#5


唉!帮你up吧,我还没有用BC连接过数据库

#6


期待

#7


为什么要传递将数据库的句柄 MDatabase->Handle 呢?我实在想不通.

若没有实在意思,建议传递将数据库的指针,

如:DLL库的函数:
MyFunction(TDatabase *Database)
{
    Query1->DataBase = Database;
    ......
}


调用时:

MyFunction(Database1);

#8


楼上的兄弟,这样好像不行吧。TQuery::DabaBase 属性是不可用的。而且我的BDE句柄留出来可以供 BCB 6.0 使用,要是不传句柄你让我传什么?

#9


关注一下

#10


哪位大哥帮帮忙!拜托。

#11


的确. __property TDatabase Database = {read=FDatabase}; Database属性是不可写的.

你可以试试改成将
  Query1->DatabaseName = Database->DatabaseName;

如果还不行,还可试试复制一个控件.

  TDatabase *MyDatabase = new TDatabase(this);
  MyDatabase->DatabaseName = "h11111111111";  // 不要重复.
  MyDatabase->DriverName = Database->DriverName;
  MyDatabase->Params = Database->Params;
  MyDatabase->LoginPrompt = false;
  Query1->DatabaseName = MyDatabase->DatabaseName;
  ....
  delete MyDatabase;

#12


为什么不用数据模块呢?用数据模块不就可以实现连接共享?

#13


我的程序之所以要传递数据库的句柄,就是为了实现
  动态创建数据库实例
  将数据库的名字(DatabaseName)给记录集(TTable, TQuery)
然后,访问记录集。
  直接传递进来的数据库对象的名字、或者指针都是不好用的。

并且我创建的数据库不需要再次连接,只是共享句柄,然后“广播”他的“数据库名字”罢了。

那么我用数据库模块,在我这种情况之下又该如何实现共享呢?

#14


经过测试,是可以的.

//--- 以下是EXE文件的调用: -----------------------------
void __fastcall TMainForm::Button1Click(TObject *Sender)
{
    if (Edit1->Text.ToIntDef(0) < 1) return;
    if (!Database1->Connected)
        Database1->Open();
    if (Database1->Connected)
    {
        HINSTANCE Installed;
        AnsiString (__stdcall *GetItemCaption)(TDatabase *, int) = NULL;
        Installed = LoadLibrary("NormalDLL.dll");
        if (Installed)
        {
            (FARPROC) GetItemCaption = GetProcAddress(Installed,"TestDb");
             if (GetItemCaption)
                Edit2->Text = GetItemCaption(Database1, Edit1->Text.ToIntDef(0));
        }
        FreeLibrary(Installed);
    }
}

//--- 以下是DLL文件的函数: -----------------------------

extern "C" __declspec(dllexport)
    AnsiString __stdcall TestDb(TDatabase *Database, int Id);
AnsiString __stdcall TestDb(TDatabase *Database, int Id)
{
    AnsiString Result;
    TQuery *Query = new TQuery(NULL);
    Query->DatabaseName = Database->DatabaseName;
    Query->SQL->Add("SELECT Caption FROM Items Where Id=" + IntToStr(Id));
    Query->Open();
    if (!Query->Eof)
        Result = Query->FieldByName("Caption")->AsString;
    Query->Close();
    delete Query;
    return Result;
}

#15


我用该相同的方法,但是说是找不到数据库名。
不过,还是谢谢各位了。

#1


还有,我用的是 SQL Server 配置的 ODBC, BCB 5.5 和 BCB 6.0 的句柄会不会冲突?

对写 ==> 多谢 !

#2


还有:

我用的是 MS SQL Server,配置 ODBC
BCB 5.5 和 BCB 6.0 的句柄会不会冲突?

对写 ==> 多谢 !

#3


人呢?

#4


我不知道 帮你顶一下

#5


唉!帮你up吧,我还没有用BC连接过数据库

#6


期待

#7


为什么要传递将数据库的句柄 MDatabase->Handle 呢?我实在想不通.

若没有实在意思,建议传递将数据库的指针,

如:DLL库的函数:
MyFunction(TDatabase *Database)
{
    Query1->DataBase = Database;
    ......
}


调用时:

MyFunction(Database1);

#8


楼上的兄弟,这样好像不行吧。TQuery::DabaBase 属性是不可用的。而且我的BDE句柄留出来可以供 BCB 6.0 使用,要是不传句柄你让我传什么?

#9


关注一下

#10


哪位大哥帮帮忙!拜托。

#11


的确. __property TDatabase Database = {read=FDatabase}; Database属性是不可写的.

你可以试试改成将
  Query1->DatabaseName = Database->DatabaseName;

如果还不行,还可试试复制一个控件.

  TDatabase *MyDatabase = new TDatabase(this);
  MyDatabase->DatabaseName = "h11111111111";  // 不要重复.
  MyDatabase->DriverName = Database->DriverName;
  MyDatabase->Params = Database->Params;
  MyDatabase->LoginPrompt = false;
  Query1->DatabaseName = MyDatabase->DatabaseName;
  ....
  delete MyDatabase;

#12


为什么不用数据模块呢?用数据模块不就可以实现连接共享?

#13


我的程序之所以要传递数据库的句柄,就是为了实现
  动态创建数据库实例
  将数据库的名字(DatabaseName)给记录集(TTable, TQuery)
然后,访问记录集。
  直接传递进来的数据库对象的名字、或者指针都是不好用的。

并且我创建的数据库不需要再次连接,只是共享句柄,然后“广播”他的“数据库名字”罢了。

那么我用数据库模块,在我这种情况之下又该如何实现共享呢?

#14


经过测试,是可以的.

//--- 以下是EXE文件的调用: -----------------------------
void __fastcall TMainForm::Button1Click(TObject *Sender)
{
    if (Edit1->Text.ToIntDef(0) < 1) return;
    if (!Database1->Connected)
        Database1->Open();
    if (Database1->Connected)
    {
        HINSTANCE Installed;
        AnsiString (__stdcall *GetItemCaption)(TDatabase *, int) = NULL;
        Installed = LoadLibrary("NormalDLL.dll");
        if (Installed)
        {
            (FARPROC) GetItemCaption = GetProcAddress(Installed,"TestDb");
             if (GetItemCaption)
                Edit2->Text = GetItemCaption(Database1, Edit1->Text.ToIntDef(0));
        }
        FreeLibrary(Installed);
    }
}

//--- 以下是DLL文件的函数: -----------------------------

extern "C" __declspec(dllexport)
    AnsiString __stdcall TestDb(TDatabase *Database, int Id);
AnsiString __stdcall TestDb(TDatabase *Database, int Id)
{
    AnsiString Result;
    TQuery *Query = new TQuery(NULL);
    Query->DatabaseName = Database->DatabaseName;
    Query->SQL->Add("SELECT Caption FROM Items Where Id=" + IntToStr(Id));
    Query->Open();
    if (!Query->Eof)
        Result = Query->FieldByName("Caption")->AsString;
    Query->Close();
    delete Query;
    return Result;
}

#15


我用该相同的方法,但是说是找不到数据库名。
不过,还是谢谢各位了。