最近我写了一个.net环境下的C#动态链接库xmldb.dll。它仅包括一个XMLDBComponent类,这个类大大简化了数据库编程的工作量。举例来说,它可以执行一个sql查询,并以一个简单的调用方法把得到的数据转化成xml文档。
源代码包中包含三个工程文件。
● xmldblib建立库,xmldb.dll;
● xmldbtest是一个asp.net的测试程序;
● xmldbservice是一个web服务,它令使用不同机器和平台的用户都可以访问xmldb.dll;
除非特殊情况,样例代码都是用c#写的。
xmldbcomponent是用System.Data.OleDb 名字空间的类实现的。现在你仅使用一个类就可以在.net中完成所有的基本数据库工作,无需使用5个或更多的类。代价就是,你不能完全拥有.net框架类可给与的力量和控制。我不想要适应SQL sever而限制我的数据库,所以我不用System.Data.SqlClient 名字空间的类来构建自己的类,而宁愿用MS Access。System.Data.OleDb类不支持ODBC数据源是最糟糕的了。
代码仅在win2000,sql7和sql2000,以及MS Access数据库的环境中测试过。
简单的数据库访问
首先,我们得创建一个XMLDBComponent对象的实例。这是通过调用静态的方法CreateObject(),如下:
XMLDBLib.XMLDBComponent obj = XMLDBLib.XMLDBComponent.CreateObject(
"Provider=myProvider;Database=myDB;Server=myServer;" +
"User ID=me;Password=");
上面代码中的参数是连接字符串。对象创建之后,下面的代码会执行一个sql查询,然后将返回的数据存成一个文件。
System.Xml.XmlDocument doc = obj.GetXmlDocument(
"select ID, firstname, lastname, hiringdate " +
"from employee");
obj.Close();
// or call Release instead of Close:
// obj.Release();
if(doc==null)
{
String strError = obj.GetLastError();
// more error handling code
}
else
doc.Save("c:\temp\employee.xml");
}
Close()方法会关闭数据库连接,释放所有内部资源。如果你稍后还要用到XMLDBComponent对象就无需调用这个方法。即使你调用了Close(),在下一次使用对象的时候,它就知道如何自动的连接数据库。事实上,每次由于数据库出现错误而刷新数据库连接时,内部都会调用Close()方法。稍后我们会谈到Release()方法。
下面是展现上面代码返回数据的xml文件。
<XMLData>
<Record>
<ID>334</ID>
<firstname>Albert</firstname>
<lastname>Einstein</lastname>
<hiringdate>3/12/1999</hiringdate>
</Record>
<Record>
<ID>404</ID>
<firstname>Clint</firstname>
<lastname>Eastwood</lastname>
<hiringdate>12/21/2000</hiringdate>
</Record>
<Record>
<ID>536</ID>
<firstname>James</firstname>
<lastname>Bond</lastname>
<hiringdate>10/23/2002</hiringdate>
</Record>
<RecordCount>3</RecordCount>
<FieldCount>4</FieldCount>
</XMLData>
GetXmlDocument()方法从数据库中取得数据,并且创建输出文档对象。它出错时返回null。在输出的xml文档中,每一个记录都被<Record>元素所包含,记录的每一字段都是子元素。如果一个字段值是null,那么相应的子元素不会出现在输出文档中。sql查询中使用的字段名会作为字段元素的名字使用。如果其字段没有指明(比如select * from..),数据库中相应的字段名会被用为元素名。sql查询时,计数字段必须给出名字,比如select count(*) as total from employee。在xml文档的末尾,有两个元素<RecordCount> 和 <FieldCount> 显示了输出纪录集的大小。
GetXmlString()和GetXmlDocument() 除了输出的是字符串而不是文档对象外基本一样。这种方法在出错时其返回空字符串。而且,不会有由XMLDBComponent的问题引起的异常。你可以通过返回值来查错,GetLastError()返回最近错误的描述性信息。
线程安全性和对象池
所有在XMLDBComponent类中使用的静态方法都具有线程安全性,但类在对象级别不是线程安全的,这意味着你不能使用多线程同时访问对象。在多线程应用(如web服务器)中,有很多同时运行的线程。我们能在每一个新线程中创建一个单独的XMLDBComponent对象。但是,这并不是最有效的方法,因为并非所有的线程都在做与数据库有关的工作,我们要最大限度的利用已经存在的对象。
XMLDBComponent维护全局对象池,这令共享对象变得很容易。当你调用CreateObject方法时,它先查看全局对象池,看是否已有一个使用同样的连接字符串但未使用的对象。如果找到,就将它会被返回,无需再创建新的。如果你不再需要某个对象,就调用Release(),这样其他线程就可以重新使用它。注意,在对象的Release()被调用后,你不能再用它。
另外,在释放对象到对象池以前,你根本无需调用Close(),因为同样一个对象稍候就可能被再用。在程序末尾,你应调用静态方法CloseAll(),它将对全局对象池中全部未使用的对象调用Close方法。因此,只要你记得在使用一个对象之后释放它,CloseAll()会替你清除一切。
你不必和你创建的XMLDBComponent对象一直保持联系,只需调用GetID()就可以获得它的ID字符串。在程序的后部,你可以ID字符串为参数调用GetObject来获取你以前用过的那个对象。但如果你已经调用了Release(),就不能这样了。这个特性在你实现基于XMLDBComponent的WEB服务时非常有帮助,稍候你就会看到。
现在,.net框架类已支持数据库连接池。
在sql查询和存储过程中使用参数
除了从数据库中取得数据以外,你还可修改数据库中的纪录(插入,更新,或删除)。假设你有一个存储过程UpdateTotal,它有两个参数:字符串参数ID和整数型参数total,下面是一个调用这个过程的VB子程序。
Public Sub CallProcUpdateTotal( _
ByVal strConnect as String, ByVal strID as String, _
ByVal nTotal as Integer)
Dim obj as XMLDBLib.XMLDBComponent = _
XMLDBLib.XMLDBComponent.CreateObject(strConnect)
obj.AddParameter(strID)
obj.AddParameter(nTotal)
If obj.Execute("exec UpdateTotal @ID=?, @total=?") Then
' Success
Else
Dim strError as String = obj.GetLastError()
' more error handling code
End If
obj.Release()
End Sub
使用AddParameter()时,添加参数的顺序要和它们出现在sql文档中的一致。Execute()会运行一个sql命令来更新数据库。你也可以用GetXmlDocument()或GetXmlString()的参数来获取数据。在XMLDBComponent对象执行sql或查询命令后,添加的参数就被自动清除了。下次做同样的调用时,你需要再次添加参数。
简单事务
XMLDBComponent支持简单事务。现在就调用BeginTransaction()来开始一个新的事务。接下来做一些数据库工作。最后调用Commit()来完成事务。如果出现任何的数据库错误,事务会自动回滚,因此没有记住要回滚的必要。从开始事务之后,如果要改变已完成的工作,你随时都可以手工调用Rollback。
在你的应用中使用多个事务是没有任何问题(就像是用多个XMLDBComponent对象)的。但是,不允许使用嵌套。如果对一个对象两次调用BeginTransaction(),前一个事务在下一个开始前会回滚。
这里有一个比较复杂的例子。假设你有一个由多页面构成的.net的web应用。用户一个接一个的浏览页面,并把数据存到数据库中。在末页面中,所有从用户收集来的数据必须被确认或是重新更改。在首页中,你的程序会调用CreateObject() 然后是BeginTransaction()开始数据库工作。当用户移至下个页面,ID字串被传递,新的页面会调用CreateObject(),并以ID为参数获取在前一个页面中创建的对象。在最后一页,应用程序会调用Commit()来完成工作,并由Release()将对象返回池中。我从未在实际的应用中实践过这个方法,真正实现时可能会出现很多问题。
web服务
XMLDBService工程是一个用vb写的简单的web服务。它对所有的web潜在客户开发XMLDBComponent方法。这意味着,你的客户程序不用在它自己的地址空间中创建一个新的XMLDBComponent对象,而且不用把XMLDB.dll拷贝到客户程序运行的那个机器上。实际上,你都无需在客户机上安装.net框架和windows操作系统。(至少在理论上是这样的)。
除了一个额外的对象ID参数,web服务使用和XMLDBComponent类中几乎一样的方法。使用WEB服务的典型做法是首先调用CreateObject(),返回一个ID字符串,而非XMLDBComponent对象,来确认在远端WEB服务进程的对象池中未用的对象。
稍候,如果你需要调用
查看本文来源