📄 在电子商务环境中通过使用对象池获得可伸缩性.htm
字号:
}
. . .
}
</PRE>
<H3>将对象池与构造函数字符串结合使用</H3>
<P>您可以将池与对象构造函数字符串结合使用,以获得池化和重用资源更细致的粒度。例如,您可以创建几个不同的组件,除了构造函数字符串和 CLSID
之外完全相同,以维护存放着不同组客户端可以使用的连接的不同对象池。这在连接是以某种方式打开的时候非常有用,如将它们与特定的安全角色绑定;这样的例子包括采用某种特定的身份验证打开的数据库连接,这使它们无法在一般情况下重用。
</P>
<P>为此,您可以使用 <B>IObjectConstruct</B>
编写一个通用的组件,依赖对象的构造函数字符串,然后重新编译它,以生成几个可以自定义的组件,每个都有不同的
CLSID。然后您可以管理性地调整每个组件,打开一个与构造函数字符串相应的连接,配置它们使之可池化,它们将按 CLSID 在不同的池中维护。 </P>
<DIV style="MARGIN-BOTTOM: 10px; MARGIN-TOP: 3px"><A
href="http://www.microsoft.com/china/msdn/library/windev/componentdev/CDscalobjpool.mspx#top"><IMG
alt=返回页首 border=0 height=9 src="在电子商务环境中通过使用对象池获得可伸缩性.files/arrow_px_up.gif"
width=7></A><A class=topOfPage
href="http://www.microsoft.com/china/msdn/library/windev/componentdev/CDscalobjpool.mspx#top">返回页首</A></DIV><A
name=XSLTsection128121120120></A>
<H2>池化事务性对象</H2>
<P>我们已经研究过了对象池如何用作连接池的替代。对于连接池,事务登记是自动的。要池化的事务性组件必须: </P>
<TABLE border=0 cellPadding=0 cellSpacing=0>
<TBODY>
<TR>
<TD class=listBullet vAlign=top>•</TD>
<TD class=listItem>
<P>手动登记资源 </P></TD></TR>
<TR>
<TD class=listBullet vAlign=top>•</TD>
<TD class=listItem>
<P>关闭自动登记 </P></TD></TR>
<TR>
<TD class=listBullet vAlign=top>•</TD>
<TD class=listItem>
<P>禁用自动连接池 </P></TD></TR>
<TR>
<TD class=listBullet vAlign=top>•</TD>
<TD class=listItem>
<P>实现 IObjectControl </P></TD></TR>
<TR>
<TD class=listBullet vAlign=top>•</TD>
<TD class=listItem>
<P>维护事务特定的池 </P></TD></TR></TBODY></TABLE>
<P>我们现在更详细地讨论这些方面。</P>
<DIV style="MARGIN-BOTTOM: 10px; MARGIN-TOP: 3px"><A
href="http://www.microsoft.com/china/msdn/library/windev/componentdev/CDscalobjpool.mspx#top"><IMG
alt=返回页首 border=0 height=9 src="在电子商务环境中通过使用对象池获得可伸缩性.files/arrow_px_up.gif"
width=7></A><A class=topOfPage
href="http://www.microsoft.com/china/msdn/library/windev/componentdev/CDscalobjpool.mspx#top">返回页首</A></DIV><A
name=XSLTsection129121120120></A>
<H2>手动登记资源</H2>
<P>参与事务的可池化对象必须手动登记托管资源。如果对象拥有客户端之间的托管资源,对象在给定上下文中激活时,资源管理器没有办法在事务中自动登记。 </P>
<P>对象本身必须处理检测事务、关闭资源管理器的自动登记和手动登记其拥有的任何资源的逻辑。 </P>
<P>实现的步骤特定于所用的资源管理器。下一节将说明如何显式地在事务中登记。</P>
<P>请注意,正如下面将谈到的,当事务活动时,对象可以用事务关系池化(换言之,也就是参与到一个事务中),而且如果被与事务相关联的客户端调用,将使用事务关系激活。在登记资源之前,您应该首先检查事务关系。如果对象从特定于该事务的池中获得,它就已经完成了事务中的工作,而且登记了其资源。
</P>
<DIV style="MARGIN-BOTTOM: 10px; MARGIN-TOP: 3px"><A
href="http://www.microsoft.com/china/msdn/library/windev/componentdev/CDscalobjpool.mspx#top"><IMG
alt=返回页首 border=0 height=9 src="在电子商务环境中通过使用对象池获得可伸缩性.files/arrow_px_up.gif"
width=7></A><A class=topOfPage
href="http://www.microsoft.com/china/msdn/library/windev/componentdev/CDscalobjpool.mspx#top">返回页首</A></DIV><A
name=XSLTsection130121120120></A>
<H2>IObjectContextInfo 和事务</H2>
<P><B>IObjectContextInfo</B> 接口可以用于测试对象是否目前在事务中或者参加了事务这样的操作。这个接口如表 3 所示。</P>
<P><B>表</B><B> 3. IObjectContextInfo </B><B>接口</B></P>
<TABLE cellPadding=0 cellSpacing=0 class=dataTable
id=XSLTdataTable123130121120120>
<THEAD>
<TR class=stdHeader vAlign=top>
<TD id=colXSLTfield120120123130121120120>方法</TD>
<TD id=colXSLTfield121120123130121120120
style="BORDER-RIGHT: #cccccc 1px solid">说明</TD></TR></THEAD>
<TBODY>
<TR class=record vAlign=top>
<TD>
<P class=lastInCell><B>IsInTransaction</B></P></TD>
<TD style="BORDER-RIGHT: #cccccc 1px solid">
<P class=lastInCell>指示当前对象是否在事务中执行。</P></TD></TR>
<TR class=evenRecord vAlign=top>
<TD>
<P class=lastInCell><B>GetTransaction</B></P></TD>
<TD style="BORDER-RIGHT: #cccccc 1px solid">
<P class=lastInCell>返回当前事务的 ITransaction 接口的指针。</P></TD></TR>
<TR class=record vAlign=top>
<TD>
<P class=lastInCell><B>GetTransactionId</B></P></TD>
<TD style="BORDER-RIGHT: #cccccc 1px solid">
<P class=lastInCell>返回当前事务的标识符。</P></TD></TR>
<TR class=evenRecord vAlign=top>
<TD>
<P class=lastInCell><B>GetActivityId</B></P></TD>
<TD style="BORDER-RIGHT: #cccccc 1px solid">
<P class=lastInCell>返回当前操作的标识符。</P></TD></TR>
<TR class=record vAlign=top>
<TD>
<P class=lastInCell><B>GetContextId</B></P></TD>
<TD style="BORDER-RIGHT: #cccccc 1px solid">
<P class=lastInCell>返回当前上下文的标识符。</P></TD></TR></TBODY></TABLE>
<DIV class=dataTableBottomMargin></DIV>
<P>如下代码示例说明了如何使用 <B>IObjectContextInfo</B> 接口存储事务 ID。这将用来确定是否对象在事务中。</P><PRE class=codeSample>STDMETHODIMP CMyObject::Activate()
{
// should only do this when we are being activated in
// different tx units of work
m_bShouldEnlist = FALSE;
if (!m_bObjectPooled)
return S_OK;
HRESULT hr;
IObjectContext * pObjectContext = NULL;
hr = CoGetObjectContext(IID_IObjectContext,
(void**)&pObjectContext);
_ASSERTE(pObjectContext);
GUID txUOW = GUID_NULL;
IObjectContextInfo* pObjTx = NULL;
pObjectContext->QueryInterface(
IID_IObjectContextInfo, (void **)&pObjTx);
if (pObjTx)
{ // Store transaction ID for later
pObjTx->GetTransactionId (&txUOW);
pObjTx->Release();
}
pObjectContext->Release();
if (txUOW != m_txuow)
{
m_bShouldEnlist = TRUE;
m_txuow = txUOW;
}
return S_OK;
}
</PRE>
<P>如下代码示例说明了使用 ODBC 时如何在事务中登记。</P><PRE class=codeSample>HRESULT CMyObject::DoSomething()
{
if (m_bShouldEnlist)
{
HRESULT hr;
IObjectContext* pObjectContext = NULL;
hr = CoGetObjectContext(IID_IObjectContext,
(void**) &pObjectContext);
_ASSERTE(pObjectContext);
IObjectContextInfo* pObjTx = NULL;
pObjectContext->QueryInterface(IID_IObjectContextInfo,
(void **) &pObjTx);
pObjectContext->Release();
if (pObjTx)
{
ITransaction* pTx = NULL;
pObjTx->GetTransaction((IUnknown **) &pTx);
RETCODE rc ;
if (pTx)
{ // Enlist in transaction
rc = SQLSetConnectOption(m_hdbc,
SQL_ATTR_ENLIST_IN_DTC,
(UDWORD)pTx);
if (SQL_FAILED(rc))
{
hr = E_FAIL;
}
pTx->Release();
}
pObjTx->Release();
}
return hr;
}
. . .
}
</PRE>
<P>最后,这段代码示例说明了使用 ADO/OLEDB 时如何在事务中登记。</P><PRE class=codeSample>HRESULT CMyObject::DoSomething()
{
if (m_bShouldEnlist)
{
HRESULT hr;
IObjectContext* pObjectContext = NULL;
hr = CoGetObjectContext(IID_IObjectContext,
(void**) &pObjectContext);
_ASSERTE(pObjectContext);
IObjectContextInfo* pObjTx = NULL;
pObjectContext->QueryInterface(IID_IObjectContextInfo,
(void **) &pObjTx);
pObjectContext->Release();
if (pObjTx)
{
ITransaction* pTx = NULL;
pObjTx->GetTransaction((IUnknown **) &pTx);
RETCODE rc ;
if (pTx) // Enlist in transaction
{ // m_pADOConnection holds the connection
// between activations
IADOConnectionConstruction *pADOConnConst;
ITransactionJoin *pITransactionJoin;
m_pADOConnection->
QueryInterface(IID_IADOConnectionConstruction,
(void **) &pADOConnConst)))
pADOConnConst->get_Session((IUnknown **) &pSession));
pSession->QueryInterface(IID_ITransactionJoin,
(void **) &pITransactionJoin);
pITransactionJoin->JoinTransaction((IUnknown *) pTx,
ISOLATIONLEVEL_SERIALIZABLE, 0, NULL));
pSession->Release();
pADOConnConst->Release();
pITransactionJoin->Release();
pTx->Release();
}
pObjTx->Release();
}
return hr;
}
. . .
}
</PRE>
<P><B>关闭自动登记</B></P>
<P>这应该在获取资源的时候执行,通常在对象的构造函数中执行。也就是说,您应该禁用自动登记,然后再连接。</P>
<P>禁用自动登记有时候可能是一种很微妙的过程,尤其是在分层的数据访问提供程序中更是如此。自动登记有时要与连接池耦合,如在 ODBC 中,有时则不然,如在
OLE DB 中。您可能需要确保自动登记在几个层次的提供程序中都关闭。在 ODBC 的情况下,您可以使用 DBPROP_INIT_OLEDBSERVICES
或者在注册表中关闭它。</P>
<P><B>禁用自动连接池</B></P>
<P>在使用池化对象替代连接池的时候,您希望确保关闭了连接池。如果您正在使用 ADO/OLEDB,首先禁用 OLEDB 会话池,然后禁用 ODBC
连接池。如果您只使用 ODBC,那么就只禁用 ODBC 连接池。为了完成这些任务,您可以使用 ODBC 中的 SQLSetEnvAttr 和 OLEDB 中的
DBPROSET_DBINIT。有关更多信息,请参阅 MSDN Library 中的知识
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -