如何在MTS中实现这样的缓冲池?(200分)

  • 主题发起人 主题发起人 wen
  • 开始时间 开始时间
W

wen

Unregistered / Unconfirmed
GUEST, unregistred user!
同一APP SERVER 有几间公司同时使用,每个公司有不同的DataBase(相同结构),
每个MTS事务就与不同的DataBase有关.
想建立一个ADOConnection的缓冲池来节省连接DataBase的次数.
在Mts中应该如何实现这样的缓冲池??
即可保存已有连接,在有需要时直接取出使用.
 
李维的MTS那本书上有提到这个东西
你去看一下吧
 
以下有一個Connection pool的範例供參考
主要有兩個函式
//依ConnectionString來取得對應的Connection
//GetNewConn -> False;
在同一thread下, 多次的GetConnection會取到相同的Connection
// True, 在同一thread下, 會取到不同的Connection
function GetConnection(const ConnectStr: string;
GetNewConn: boolean = False): TADOConnection;
//釋放由GetConnection取得的Connection
procedure ReleaseConnection(Conn: TADOConnection);
unit Unit2;
interface
uses Windows, ADODB, Classes, SysUtils, ComObj, ActiveX, CHISysUtils;
function GetConnection(const ConnectStr: string;
GetNewConn: boolean = False): TADOConnection;
procedure ReleaseConnection(Conn: TADOConnection);
implementation
type
TMyConnection = class(TADOConnection)
private
FActiveThread: THandle;
FRefCount: integer;
public
constructor Create(AOwner: TComponent);
override;
destructor Destroy;
override;
procedure AddRef;
procedure Release;
end;

TCreateThread = class(TThread)
private
FConnStr: string;
FNewConn: TMyConnection;
FErrObj: TObject;
procedure CatchError;
protected
procedure Execute;
override;
end;

PRaiseFrame = ^TRaiseFrame;
TRaiseFrame = record
NextRaise: PRaiseFrame;
ExceptAddr: Pointer;
ExceptObject: TObject;
ExceptionRecord: PExceptionRecord;
end;

var
FConnections: TThreadList;
FCreateThread: TCreateThread;
function GetNewConnection(const ConnectStr: string): TADOConnection;
begin
Result := nil;
with FCreateThreaddo
begin
FConnStr := ConnectStr;
FNewConn := nil;
Resume;
try
while FConnStr <> ''do
SwitchToThread;
finally
Suspend;
end;
if FNewConn = nil then
begin
if FErrObj <> nil then
raise FErrObj
else
Abort;
end
else
Result := FNewConn;
end;
end;

function GetConnection(const ConnectStr: string;
GetNewConn: boolean): TADOConnection;
var
I: integer;
CurThread: THandle;
begin
with FConnections.LockListdo
try
CurThread := GetCurrentThreadID;
for I := 0 to Count - 1do
with TMyConnection(List)do
if ((FActiveThread = 0) or ((FActiveThread = CurThread) and not GetNewConn)) and
(CompareText(ConnectionString, ConnectStr) = 0) then
begin
FActiveThread := CurThread;
AddRef;
Result := TMyConnection(List);
exit;
end;
Result := GetNewConnection(ConnectStr);
with TMyConnection(Result)do
begin
FActiveThread := CurThread;
AddRef;
end;
finally
FConnections.UnlockList;
end;
end;

procedure ReleaseConnection(Conn: TADOConnection);
begin
if Conn is TMyConnection then
TMyConnection(Conn).Release
else
Conn.Free;
end;

procedure ReleaseConnections;
var I: integer;
begin
with FConnections.LockListdo
try
for I := 0 to Count - 1do
TObject(List).Free;
finally
FConnections.UnlockList;
end;
FreeAndNil(FConnections);
end;

{ TMyConnection }
procedure TMyConnection.AddRef;
begin
InterlockedIncrement(FRefCount);
end;

constructor TMyConnection.Create(AOwner: TComponent);
begin
inherited;
FConnections.Add(Self);
end;

destructor TMyConnection.Destroy;
begin
FConnections.Remove(Self);
inherited;
end;

procedure TMyConnection.Release;
begin
InterlockedDecrement(FRefCount);
if FRefCount = 0 then
FActiveThread := 0;
end;

{ TCreateThread }
procedure TCreateThread.CatchError;
begin
if RaiseList <> nil then
begin
FErrObj := PRaiseFrame(RaiseList)^.ExceptObject;
PRaiseFrame(RaiseList)^.ExceptObject := nil
end else
FErrObj := nil;
end;

procedure TCreateThread.Execute;
begin
CoInitializeEx(nil, COINIT_MULTITHREADED);
try
while not Terminateddo
begin
if FConnStr <> '' then
begin
FNewConn := TMyConnection.Create(nil);
try
FNewConn.ConnectionString := FConnStr;
FNewConn.Open;
except
FreeAndNil(FNewConn);
CatchError;
end;
FConnStr := '';
end;
end;
ReleaseConnections;
finally
CoUninitialize;
end;
end;

initialization
FConnections := TThreadList.Create;
FCreateThread := TCreateThread.Create(True);
FCreateThread.FreeOnTerminate := False;
finalization
FreeAndNil(FCreateThread);
end.
 
樓上幾位,可能是我沒有表達清楚.我要的不是如何做一個緩沖池(也叫對象池),我要知道的
是在mts中實現共享.假設A是對象池.MTS B可以取,MTS C也可以取得.我想知道的是A應該
在mts環境如何實現,B,C才能取得??
ISharedProperty可實現oleVariant類型的共享.不會要我把"AdoConnection池類型"也轉換成
olevariant,再存入ISharedProperty,用時再取出轉換....
不會吧?
那位有這方面經驗,多謝了!
 
如果是如此MTS本身即Connection pooling的功能, 而ADO有支持此項功能;
雖然在程式中是不斷建立新的Connection,但其實這些Connection是由MTS的
Connection pool中取出, 並不會一直不斷的連接及Disconnect;
而且真正使用
的connection數量, 也會比客戶端數要來的少;
但就我個人應用 MTS (COM+), 到目前覺得有一個很大的缺點:
在同一個Activity下, 不同 COM 之間所使用 Connection 都是不一樣的,
可以這樣說明:
1. 客戶端創建 A, 並呼叫 A1方法
2. 在A1方法中取得Connection, 對數據庫存取
3. 在A1方法中建立B, 並呼叫B1方法
4. 在B1方法中取得Connection, 對數據庫存取
在這樣一連串動作(同一個Activity中), 2, 4所使用Connection並不相同, 此時最後的
Transaction要透過另一個服務 DTC (Distributed Transaction Coordinator)來完成
在兩層式的架構中, 這樣一個動作, 只要同一個Connection, 就可以做完了, 但在三
層中, 卻隨著呼叫COM的次數, 所使用Connection數量就會一直增加, 也會導致效率的下
降;
當然要解決以上問題, 也可在規劃COM的接口, 多個參數將connection傳入, 不過這
樣呼叫起來, 總覺得怪怪的;
另外MTS (COM+), 還有另兩個問題
1. 同一時間下, 最多只允許16個Transaction Context存在, 也就是說, 在同時間下,
最多只允許16台客戶機呼叫 MTS(COM+) 的COM方法
2. Connection pool及DTC的設計, 不知道ADO以外的數據庫存取工具的相容性高不高?
目前我Try最多的還是ADO, 除了16個Transaction Context的限制之外, 其它的運用
到是沒有發現什麼問題;
但其它如 BDE、DBExpress, 可就不知道了
 
lorderic:
Mts及ado的pooling應該不能解決我的問題?
如下應用過程:
公司corp_A對應數據庫DB_A.
公司corp_B對應數據庫DB_B.
同一MTS_B,根據客戶端的公司選擇情況,動態產生ADO connectionstring.
你說這時能自動實現緩衝嗎??我想不行吧.
有沒有辦法在MTS維護這樣一個對象池呢?每個公司甚至每個客戶端,維護有限的資源.
<<同一時間下, 最多只允許16個Transaction Context存在...>>
我未詳細考究過,是否是指同一mts的方法不能超過16個?看看先.

 
即使用動態產生Connection string, MTS的 connection pooling還是work的, 我公司
所開發三層式架構的產品也是如此;
以上我是經由SQL server的Profiler, 監控對SQL
Server狀態所歸納的結果;
而且它不儘能實現緩衝, 經由 DTC, 如果同一個Activity中
對不同的數據庫存取, 也能控管Transaction, 即同時針對不同數據庫(不管在不在同一個
Server, 或性質不同的Database)的異動, 能同時Commit或 Rollback;
即使此功能我覺得
用途不大, 但還是覺得很神奇;
 
//最多只允許16台客戶機呼叫 MTS(COM+) 的COM方法
这种情况下会出现什么错误呢?超过16应该很容易啊。
 
按lorderic的說法,
除設定Mts具有pooling功能外,寫代碼時根本不用考慮緩衝情況,讓它自生自滅就行了.
不知那位還有高見?
如果想用程序實現對象池的,有沒有辦法啊??

 
那位再說點,我還沒得到我要答案,不想結束.
 
你相要什麼答案呢?
MTS (COM+) 的Connection Pooling 在ADO+SQLServer是沒有問題的, 在要使用時
建立Connection,用完時就將其Free即可;
想要程序實現對象池, 可以參照我之前貼上的Source即可
 
lorderic老兄,
你的这对象池我知道,但在不同mts组件间怎样共享,其实我要的就是这个"怎样共享"?
 
D6的DEMO目录里有个MTS POOLING的例子,可以参考一下
 
你可以將以上的Pooling程式做成一個Package,並加入到Delphi IDE中
而將你的Dll project Options 中Build with Runtime packages的Check打勾, 即可;
不過你在使用時就必需將VCL50.bpl, VCLDB50.bpl...等用的到package散發到使用該
dll的機器上!
 
lorderic,別逗啦,我是在mts間共享啊!
 
如果是在不同Mts的Application, 根本無法共享, 不同Application, 在執行時就會有
不同的進程(process), 彼此的定址同間也不同;
可以利用COM物件來達到Connection的分
享, 但因為在不同的行程中, 其實資源不一定省了, 而效率反而下降了!!
 
再沒人答,我可要結束了.
 
后退
顶部