`
阿尔萨斯
  • 浏览: 4472089 次
社区版块
存档分类
最新评论

高性能Web Service数据库编程

 
阅读更多

简介:... 1

启用ATL ServerData Source Cache支持... 1

实现数据库的交互... 2

创建ATL OLEDB使用者类... 2

提供插入记录的能力... 2

创建数据源连接对象... 3

使用UDL文件代替连接字符串... 4

Web Service调试... 4

性能评测... 5

简介:

ATL Server是性能很高的Web ApplicationWeb Service的开发类库。到目前为止,我认为如果应用程序要和数据库交互,性能最高的办法是使用OLE DB,同时要启用ATL ServerData Source Cache

启用ATL ServerData Source Cache支持

先来创建一个名为HighPerformance的工程,该工程将访问SQL Server数据库。在服务器选项中,选择“数据源缓存”。向导为我们创建了两个工程,一个是HighPerformance,一个是HighPerformanceIsapiHighPerformance是我们的应用程序逻辑所在之处,我们所有的Web Service的可公开函数都在这里。HighPerformanceIsapi是我们的ISAP扩展服务工程,IIS将在第一次Web Service被调用期间加载它,并且一直缓存,直到很长一段时间没有人使用我们的Web Service才释放。因此我们可以利用这个特性将需要缓存的全局变量保存到HighPerformanceIsapi工程中,然后每个应用程序线程(HighPerformance工程)可以通过调用QueryService来获得缓存的全局变量,并且调用全局变量的成员函数。

HighPerformanceIsapi工程内部维护了一个线程池,每个线程对象内部都拥有自己的数据源缓存对象,请看代码:

// 逐线程数据源缓存

typedef CDataSourceCache<> ds_cache_type;

CComObjectGlobal<ds_cache_type> m_dsCache;

CComObjectGlobal用于保存在m_dsCache对象的生存期内,HighPerformanceIsapi服务器不会被卸载掉。CDataSourceCache类实现了IDataSourceCache接口。

HighPerformance工程中的应用程序逻辑通过QueryService请求全局对象时,只要传递

__uuidof(IDataSourceCache)即可。QueryService的实现代码如下:

HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService,

REFIID riid, void** ppvObject)

{

if (InlineIsEqualGUID(guidService, __uuidof(IDataSourceCache)))

{

CIsapiWorker *pWorker = GetThreadWorker();

if (pWorker)

{

CDataSourceCache<> *pCache = NULL;

if (pWorker->GetWorkerData(_DATASOURCE_CACHE, (void **)&pCache))

{

*ppvObject = static_cast<IDataSourceCache *>(pCache);

return S_OK;

}

}

}

return baseISAPI::QueryService(guidService, riid, ppvObject);

}

实现数据库的交互

创建ATL OLEDB使用者类

我们使用向导连接SQL SERVER (服务器名为GAO、用户名和密码为sa、数据库名为测试数据库、数据表为学生表),并支持属性化,生成支持写操作的OLE DB命令类。具体向导使用这里不叙述,请参考MSDN

我们的OLE DB类名为CDataRowset。属性db_source是代表了连接信息,后面我将通过udl文件替代之。db_command属性中的SQL语句代表了查询表的操作,我们也可以使用Update或者insert语句代替之。

注意,我们的CDataRowset类创建在HighPerformance工程中,HighPerformanceIsapi工程中应该保存我们的全局数据源对象。

提供插入记录的能力

我们需要修改db_command属性中绑定的SQL语句,以便我们插入一条语句。db_command(L"INSERT INTO [学生表] ([姓名],[年龄],[性别],[地址]) VALUES (?,?,?,?)")

db_column属性修改为db_param属性,顺序请对应INSERT语句的四个?号。

为了使我们的Web Service有更好的性能,我在工程中设置了使用UNICODE编码。

[

db_command(L"INSERT INTO [学生表] ([姓名],[年龄],[性别],[地址]) VALUES (?,?,?,?)")

]

class CDataRowset

{

public:

[ db_param(1,DBPARAMIO_INPUT)] TCHAR m_column0[20];

[ db_param(2,DBPARAMIO_INPUT)] TCHAR m_column1[20];

[ db_param(3,DBPARAMIO_INPUT)] TCHAR m_column2[20];

[ db_param(4,DBPARAMIO_INPUT)] TCHAR m_column3[20];

void GetRowsetProperties(CDBPropSet* pPropSet)

{

pPropSet->AddProperty(DBPROP_CANFETCHBACKWARDS, true, DBPROPOPTIONS_OPTIONAL);

pPropSet->AddProperty(DBPROP_CANSCROLLBACKWARDS, true, DBPROPOPTIONS_OPTIONAL);

pPropSet->AddProperty(DBPROP_IRowsetChange, true, DBPROPOPTIONS_OPTIONAL);

pPropSet->AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE);

}

};

编写CAddRecord类,该类从CDataRowset类派生,这里只能使用继承而不是直接修改CDataRowset类,是因为db_command属性导致了CDataRowset类引入了一些隐藏类,这些隐藏类会导致一些意外行为。

CAddRecord类将提供设置成员变量和清除成员变量的方法。代码如下:

void CAddRecord::Clear(void)

{

//set member to zero

m_column0[0]=0;

m_column1[0]=0;

m_column2[0]=0;

m_column3[0]=0;

}

void CAddRecord::SetStudentInfo(BSTR Name,BSTR Age,BSTR Gender,BSTR Address)

{

wcscpy(m_column0,Name);

wcscpy(m_column1,Age);

wcscpy(m_column2,Gender);

wcscpy(m_column3,Address);

}

创建数据源连接对象

删除CDataRowset类的db_source属性,该属性帮助我们创建CDataSource对象,我们这里不需要。

定义连接字符串宏

#define CONN_STRINGW L"Provider=SQLOLEDB.1;Password=sa;Persist Security Info=True;User ID=sa;Initial Catalog=/x6d4b/x8bd5/x6570/x636e/x5e93;Data Source=GAO;Use Procedure for Prepare=1;Auto Translate=True;Packet Size=4096;Workstation ID=FREEBIRD;Use Encryption for Data=False;Tag with column collation when possible=False"

修改CHighPerformance类的代码:

HTTP_CODE InitializeHandler(AtlServerRequest *pRequestInfo, IServiceProvider *pProvider)

{

if (HTTP_SUCCESS != CSoapHandler<CHighPerformanceService>::InitializeHandler(pRequestInfo, pProvider))

return HTTP_FAIL;

if (S_OK != GetDataSource( pProvider,

CONN_STRINGW,

CONN_STRINGW,

&m_dc ))

return HTTP_FAIL;

return HTTP_SUCCESS;

}

m_dc是该类的私有成员变量,类型为CDataConnection

[ soap_method ]

HRESULT AddNewStudent(BSTR Name,BSTR Age,BSTR Gender,BSTR Address)

{

m_rec.SetStudentInfo(Name,Age,Gender,Address);

HRESULT hr=m_rec.OpenRowset(m_dc);

return hr;

}

m_rec定义为CAddRecord m_rec;

使用UDL文件代替连接字符串

UDL文件中获取连接字符串,需要创建MSDAINITIALIZE对象,并调用IDataInitialize接口的LoadStringFromStorage方法才行。这种动作我并不想放到InitializeHandler函数中反复做。唯一的办法是放到ISAPI扩展DLL中。

我们应该在类CHighPerformanceExtension中维护一个成员变量,当我们在应用程序DLL中通过QueryService查询某个接口(这里名叫IUdl)时,我们可以获得该变量的实现的IUdl接口,通过IUdl的方法GetConnectString获取连接字符串。这样我们就可以将该连接字符串作为参数传递给GetDataSource函数,从而取代宏。

实现IUdl接口的对象将在创建时读取c:/gao.udl文件,并将连接字符串保存,IUdl::GetConnectString方法将返回连接字符串。

这里涉及到几个知识点,如何在ATL SERVER中开发一个COM-LIKE 接口,并且将接口暴露为服务;如通过OLE DB组件读取UDL文件。源代码如下,请参考:

#pragma once

//interface IUdl

__interface __declspec(uuid("F4FA35D6-D26D-4b5a-9544-A69F66E927B8"))

IUdl:public IUnknown

{

HRESULT GetConnectString(BSTR* pConString);

};

#pragma once

//#include <stdafx.h>

#include "../CommonServiceDefinition.h"

#include <fstream>

using namespace std;

class CUdl :

public IUdl

{

public:

CUdl()

{

CComPtr<IDataInitialize> spDataInitialize;

HRESULT hr = spDataInitialize.CoCreateInstance( __uuidof(MSDAINITIALIZE));

if (SUCCEEDED(hr))

hr=spDataInitialize->LoadStringFromStorage(CComBSTR("c://gao.udl"), &m_ConnString);

}

ULONG STDMETHODCALLTYPE AddRef() {return 1;}

ULONG STDMETHODCALLTYPE Release() {return 1;}

HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject)

{

if( !ppvObject )

return E_POINTER;

if( IsEqualIID( riid, IID_IUnknown))

*ppvObject = static_cast<IUnknown*>(this);

else if( IsEqualIID( riid, __uuidof(IUdl)))

*ppvObject = static_cast<IUdl*>(this);

else

return E_NOINTERFACE;

AddRef();

return S_OK;

}

HRESULT GetConnectString(BSTR* pConString)

{

if( pConString==NULL)

{

return E_INVALIDARG;

}

CComBSTR bstr(m_ConnString);

*pConString=bstr.Detach();

return S_OK;

}

private:

CComHeapPtr<OLECHAR> m_ConnString;

};

CHighPerformanceExtension中声明变量CUdl m_udl;并且改写QueryService方法

HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService,

REFIID riid, void** ppvObject)

{

if (InlineIsEqualGUID(guidService, __uuidof(IDataSourceCache)))

{

CIsapiWorker *pWorker = GetThreadWorker();

if (pWorker)

{

CDataSourceCache<> *pCache = NULL;

if (pWorker->GetWorkerData(_DATASOURCE_CACHE, (void **)&pCache))

{

*ppvObject = static_cast<IDataSourceCache *>(pCache);

return S_OK;

}

}

}

if(InlineIsEqualGUID(guidService,__uuidof(IUdl)) &&

InlineIsEqualGUID(riid,__uuidof(IUdl)) )

{

return m_udl.QueryInterface(riid,ppvObject);

}

return baseISAPI::QueryService(guidService, riid, ppvObject);

}

我们的应用程序dll中的代码如下:

// HighPerformance.h : 定义 ATL Server 请求处理程序类

//

#pragma once

#include "addrecord.h"

#include "../CommonServiceDefinition.h"

namespace HighPerformanceService

{

// webservice 的所有 structenum typedefs 应进入命名空间

// IHighPerformanceService - Web 服务接口声明

//

[

uuid("EECB2E3E-9CA8-4E07-8DE9-81A21E99E707"),

object

]

__interface IHighPerformanceService

{

[id(1)] HRESULT AddNewStudent([in]BSTR Name,[in]BSTR Age,[in]BSTR Gender,[in]BSTR Address);

};

// HighPerformanceService - Web 服务实现

//

[

request_handler(name="Default", sdl="GenHighPerformanceWSDL"),

soap_handler(

name="HighPerformanceService",

namespace="urn:HighPerformanceService",

protocol="soap"

)

]

class CHighPerformanceService :

public IHighPerformanceService

{

public:

HTTP_CODE InitializeHandler(AtlServerRequest *pRequestInfo, IServiceProvider *pProvider)

{

if (HTTP_SUCCESS != CSoapHandler<CHighPerformanceService>::InitializeHandler(pRequestInfo, pProvider))

return HTTP_FAIL;

CComPtr<IUdl> spUdl;

HRESULT hr=pProvider->QueryService(__uuidof(IUdl),&spUdl);

if(hr!=S_OK)

return HTTP_FAIL;

CComBSTR connectstring;

hr=spUdl->GetConnectString(&connectstring);

if(hr!=S_OK)

{

return HTTP_FAIL;

}

if (S_OK != GetDataSource( pProvider,

connectstring,

connectstring,

&m_dc ))

{

return HTTP_FAIL;

}

return HTTP_SUCCESS;

}

[ soap_method ]

HRESULT AddNewStudent(BSTR Name,BSTR Age,BSTR Gender,BSTR Address)

{

m_rec.SetStudentInfo(Name,Age,Gender,Address);

HRESULT hr=m_rec.OpenRowset(m_dc);

return hr;

}

private:

CDataConnection m_dc;

CAddRecord m_rec;

// TODO: 在此添加其他 Web 服务方法

}; // CHighPerformanceService

} // 命名空间 HighPerformanceService

Web Service调试

MSDN提供一个例子---SOAPDebugApp 示例:在客户端内存空间中调试 XML Web services

地址:ms-help://MS.MSDNQTR.2003FEB.2052/vcsample/html/vcsamsoapdebugappsample.htm

这种方式不同真正的WEB调用,而是通过直接调用应用程序DLL,这种方式很好,但是有局限性,由于我们的InitializeHandler要在每次调用WEB方法之前执行,并且每次都要从ISAPI扩展DLL线程池中打交道,而这种模拟调用不会导致IIS加载ISAPI扩展DLL。所以,InitializeHandler会失败,我们就没有办法对WEB 方法进行断点跟踪。解决之道有两种,一是用文件输出的方式,而是先不用扩展DLL缓存,当确信应用程序DLL已经没有问题后,再进行修改。但这两种方法都比较麻烦,不知道还有没有跟好的办法?

另外,调试的时候IIS容易出现不正常,请用iisreset命令重启。

性能评测

我编写客户端调用AddNewSutdent方法,一切成功。三个客户端同时各自写入2万笔纪录,总数6万,好极了。性能感觉非常好。

分享到:
评论

相关推荐

    开发高性能的Web Service应用

    ### 开发高性能的Web Service应用 #### WebService性能概述 在开发高性能的Web Service应用时,首先需要理解WebService性能的基本概念及其重要性。性能不仅关乎用户体验,还直接影响到系统的稳定性和资源消耗。...

    PB11开发Web Service应用

    理解Web Service的基本原理,熟悉PB11的API和工具,以及遵循良好的编程和设计原则,将有助于提升开发效率和应用质量。 总结,PB11提供了强大的Web Service开发功能,让开发者能够轻松地构建和整合分布式系统。通过...

    Java web Service性能监视

    Java Web Service性能监视是针对基于Java的Web服务应用程序的性能监控...通过这些工具,可以有效地监控Java Web Service的性能,从而提高整体服务质量,减少响应时间,避免资源浪费,并确保系统的高可用性和稳定性。

    WebService客户端调用服务器数据库

    【WebService客户端调用服务器数据库】是一个关键的IT技术主题,主要涉及如何通过Web服务接口与远程服务器数据库进行交互。在互联网应用中,这种技术经常用于实现不同系统间的数据共享和功能整合。以下是对这一主题...

    JSP数据库编程指南(PDF)

    最后,考虑到实际应用中的安全性问题,书中还会涵盖如何处理SQL注入、事务管理、连接池配置以及错误处理等内容,这些都是开发安全、高性能的JSP数据库应用不可或缺的部分。 总之,《JSP数据库编程指南》将深入探讨...

    实战Delphi6.Kylix2.SOAP.Web Service程序设计篇李维著

    - **Chap12**:可能探讨了更高级的Web Service话题,如安全性、事务处理和性能优化。 - **Chap09**:可能涵盖了Delphi6和Kylix2中的SOAP客户端开发。 - **Chap10**:可能详细介绍了如何创建和部署SOAP服务器端...

    ASP.NET与Web Service实例剖析

    6. **ASP.NET Cache Service**:缓存服务提高了应用程序性能,通过存储常用数据,减少对数据库或其他资源的重复访问。 7. **ASP.NET Deployment**:ASP.NET简化了部署流程,例如使用XCOPY部署,使得只需复制文件...

    基于.NET的Web Service与SQL Server 2000交互通信的研究.pdf

    SQL Server 2000是一个功能强大、可扩展、高性能的关系型数据库管理系统,它被广泛应用于公司和企业中。通过存储技术,SQL Server 2000能够提供稳定、高效的数据存储解决方案。 3. Web Service技术: Web Service是...

    Web service开发指南

    XFire(后来被Apache CXF吸收)是另一个强大的Web服务框架,以其高性能和轻量级特性受到欢迎。XFire支持多种协议和数据格式,包括RESTful服务、JAXB数据绑定以及MTOM(消息传输优化机制)。其API简洁易用,使得开发...

    高性能网站建设进阶指南:WEB开发者性能优化最佳PDF

    《高性能网站建设进阶指南》是一本专为WEB开发者设计的性能优化手册,旨在帮助开发者们构建更快、更稳定、更高效的网站。这本书深入探讨了JavaWeb和Java在网站开发中的应用,结合实际案例,提供了丰富的优化策略和...

    Delphi WEB SERVICE12

    Delphi Web Service是一种在Delphi开发环境中创建网络服务的技术,它允许...通过掌握Delphi Web Service技术,开发者可以充分利用Delphi的强大编程能力,构建高效、可扩展的网络服务,满足现代企业对跨平台通信的需求。

    使用XFire+Spring构建Web Service

    6. **高性能SOAP栈**:XFire设计了高效的SOAP栈,进一步优化了Web Service的通信效率。 #### 三、XFire与Spring的协同效应 XFire与Spring的结合,为开发者提供了更为强大的工具集,特别是在以下方面展现出巨大潜力...

    XML WEB Service开发

    尽管XML Web服务通常用于跨网络的松耦合通信,但.NET Remoting可以提供更高的性能和更低的延迟,适用于内部企业应用间的通信。 **08 使用ADO.NET .ppt** ADO.NET是.NET框架中的数据访问组件,可以用来连接数据库并...

    JAVA WEB 项目 Oracle数据库技术

    8. **Oracle连接池**:在JAVA WEB应用中,连接池如C3P0、HikariCP或Apache DBCP,用于管理和复用数据库连接,减少资源消耗并提高性能。 9. **JPA和Hibernate**:对于更高级别的数据访问,可以使用Java Persistence ...

    Web_Service开发

    ### Web Service开发知识点详解 ...通过掌握关键技术、工具和技术,开发者可以有效地构建出高性能、安全可靠的Web Service应用。无论是企业内部还是不同企业间的集成场景,Web Service都是不可或缺的一部分。

    20120102 ServiceMobileQuery net web service 手机号归属地查询

    20120102 ServiceMobileQuery net web service 是一个专为实现这一功能而设计的.NET Web服务,它集成了C#编程语言、ASP.NET技术、SQL数据库以及DBA数据库管理技能,为开发者提供了一个高效、稳定的解决方案。...

    深入浅出web+service

    ### 深入浅出 Web Service #### 一、什么是 Web Service? Web Service 是一种通信方式,它允许两个电子设备在网络之间进行数据交换。根据维基百科定义:“Web Service 是一种通过网络,遵循 Web 协议来提供服务的...

    基于J2EE的Web Service分布式应用研究.pdf

    Web Service 使用标准的HTTP和XML协议,允许来自不同平台和编程语言的应用程序相互操作。JAX-RPC(Java API for XML-based RPC)是Java中用于实现Web Service的一种技术,它提供了基于XML的远程过程调用机制。JAXR...

    ASP.NET与Web Service实例剖析中文版.ppt

    【ASP.NET与Web Service实例剖析】是一份关于...总的来说,这份PPT是针对ASP.NET和Web Service的一份深度学习资源,涵盖了从基础知识到实践应用的多个层面,对于想深入了解这两种技术的开发者来说具有很高的参考价值。

    Java Web编程技术

    以上只是Java Web编程技术的一小部分,实际开发中还需要了解版本控制(如Git)、持续集成/持续部署(CI/CD)工具、性能调优、安全性以及Web标准等。随着技术的发展,Java Web开发不断演变,例如Spring Boot的出现...

Global site tag (gtag.js) - Google Analytics