第十四章访问关系数据库.docx
《第十四章访问关系数据库.docx》由会员分享,可在线阅读,更多相关《第十四章访问关系数据库.docx(30页珍藏版)》请在冰豆网上搜索。
![第十四章访问关系数据库.docx](https://file1.bdocx.com/fileroot1/2023-2/6/cdcb3006-ed3d-4103-9271-2097898a61a5/cdcb3006-ed3d-4103-9271-2097898a61a51.gif)
第十四章访问关系数据库
访问关系数据库
虽然Zope自带的ZODB对象数据库在Zope中的应用是最合适的,但很明显,关系数据库仍然在这个世界中占据着统治地位。
可能你所在的IT环境中早已部署了关系数据库,在这个现有的环境中部署Zope/Plone时,你需要让它们可以协同工作,让Zope/Plone可以读取现有的关系数据库中的数据,让Zope/Plone把数据写入到关系数据库中以便其它支持数据库的程序也能读到这些数据,这一章正是针对系统管理员和网站管理员会遇到的这种集成需求而编写的。
为了在Zope中使用关系数据,必须建立两种不同的Zope对象:
一个是“数据库连接对象”,另一个是“ZSQL方法”。
前者告诉Zope如何连接一个关系数据库;后者使用前者去连接一个数据库,对数据库的进行SQL访问。
本章学习重点是:
∙了解Zope与各种关系数据库连接的原理,并掌握连接的方法
∙熟练使用ZSQL方法进行以关系数据库为存储方案的应用开发
∙掌握在脚本或模板中等各种调用ZSQL的方法
14.1 关系数据库连接
一般应用程序使用关系数据库,比如需要以关系数据库作为数据存储等,它们需要使用关系数据库所提供的相应编程语言的开发接口。
Zope也不例外,在连接关系库时它就是一个关系数据库的访问客户端,因此需要相应关系数据库的开发接口。
所不同的是Zope是以Python为编程语言写出的应用程序,所需连接数据库的接口也必须是Python的。
除了访问接口,还必须学习的一件事就是连接字符串,不管你使用哪种编程语言来访问关系数据库,都需要一种方法来描述所连接的关系数据库的信息,如连接哪一台机器上的关系数据库中的哪一个数据库,使用什么用户名和密码等,这在Zope中称为"连接字符串"。
14.1.1 数据库适配器(DA)
Zope支持现有的很多种关系数据库,如商业的Oracle、DB2、SQLSever、InterBase等,还有开源实现的PostgreSQL、MySQL等,还有一种是Zope自带的以Python语言实现的Gadfly关系数据库。
Zope使用称为数据库适配器(DatabaseAdapter)的对象作为与实际的关系数据库的接口,不同的关系数据库有不同的连接适配器,为了从Zope中访问关系数据库,你需要下载安装相应的数据库连接适配器产品。
同时还因为连接适配器产品就是给关系数据库和Zope之间建立一座桥梁,它的内部是直接使用这个关系数据库的Python编程访问接口,你还需要给Python安装与你要连接的数据库相应的Python访问接口。
一般在数据库软件供应商的网站上可以下载到相应的Python访问接口软件包。
【表14.1】常用的关系数据库所需的连接适配器产品
关系数据库名称
可用的适配器产品说明
Oracle
由Zope公司提供的DCOracle2包包含了ZoracleDA
DB2
由BlueDynamics提供的ZDB2DA
PostgreSQL
最新的数据库连接适配器是包含于psycopg包中的ZPsycopgDA,原来的ZpopyDA也可以使用
MySQL
使用ZMySQLDA,源代码形式和linux二进制包形式都可用
SAPDB
由UlrichEck提供的ZsapdbDA
Sybase
由Zope公司编写并提供商业支持的SybaseDA
SQLServer
由Zope公司编写并提供商业支持的ZODBCDA,只有Windows平台可用。
这个数据库适配器也支持其它的ODBC兼容的数据库。
Interbase/Firebird
有多个数据库适配器可用,包括isectZope,kinterbasdbDA和gvibDA
Informix
有ZinformixDA产品,这个产品依赖于informixdb产品也需要安装
Gadfly
Gadfly数据库适配器已内置于Zope中
上表中所列出的只是一些最常用的关系数据库,并且在Zope网站上已有很多人贡献的数据库连接适配器产品。
即使某种数据库尚没有相应的数据库连接适配器,只要它有相应的Python语言编程接口也很容易将这种适配器写出来。
提示
(在http:
//www.zope.org上可以看到Download下面有ZopeProducts,这里可以下载各种形式的Zope扩展产品,所有数据库操纵方面的产品都在称为"外部访问(ExternalAccess)"的类型中,你也可以直接访问这个地址:
http:
//www.zope.org/Products/external_access。
)
另一方面,还有像ODBC这样的由众多商业、开源数据库支持的跨平台的数据库工业标准协议也被Zope所支持,也就是说即使你使用的数据库没有相应的Zope上的连接适配器,但只要它是支持ODBC标准的,那么也可以使用ODBC连接适配器来连接你的关系数据库。
值得一提的是这个Gadfly关系数据库是用Python编写的。
它内置在Zope中,用来做演示或处理小批量的数据。
它很快,但是不适用于处理大量数据,因为它把所有的数据都读入内存来处理。
关于Gadfly本身可以在Chordate的网站上获得更多的情况。
14.1.2 连接到MySQL数据库
连接关系数据库的另一个概念是连接字符串。
除了Gadfly,其它关系数据库都是Zope的外部扩展。
连接外部的关系数据库都需要使用连接字符串。
下面以常见的MySQL为例说明连接字符串。
在给Python安装好python-mysqldb并给Zope安装了ZMySQLDA这个Zope产品之后,启动至Zope管理界面上在添加下拉列表中可以看到ZMySQLDatabaseConnection这一项,选择这个项后会出现如图14.1的界面:
【图14.1】MySQL数据库连接
图中可以看到MySQL数据库使用的连接字符串格式是:
[+/-]database[@host[:
port]][user[password[unix_socket]]]
这个字符串格式中以[]引用的部分表示是可选的部分。
如最典型的情况是:
databaseuserpassword
这指定了数据库名称和连接所使用的用户名密码信息,对应着在本地运行的Mysql数据库,并且运行在Mysql的标准端口上。
其它可选的参数分别用于不同的目的:
【表14.2】连接字符串
可选部分
意义
+/-
指定打开或关闭事务支持功能
@host
指定数据库运行所在主机,这对应于数据库不是运行在本地主机上的情况
:
port
指定数据库运行的端口,这对应于数据库运行于非标准端口的情况
user
指定连接数据库的用户名
password
连接数据库的密码
unix_socket
使用UNIX域套接字来连接,在UNIX上主机上运行的Mysql可以使用UNIX特有域套接字来访问
连接字符串是与关系数据库连接的一个必需的信息,其它关系数据库也使用与MySQL类似的连接字符串。
这里使用到MySQL的例子只是为了说明在Zope中配置连接一个关系数据库是很简单的。
在这个界面上单击Add按钮就是添加了连接对象,这是一个Zope中的对象,本章稍后会详细介绍它的用途。
14.1.3 Gadfly数据库连接对象
本章后面的例子将以Gadfly配置为例,因为这种关系数据库配置起来最为简单,在你没有部署关系数据库的情况下也可以试验Zope支持关系数据库的强大功能。
同时因为Gadfly数据库是内置于Zope运行的,它是不需要连接字符串的,这样也给本章讲述的重点是操纵数据库简化了许多操作,避免因为数据库本身可能存在的问题影响了运行本章示例的结果。
从Zope根目录的添加列表中选择ZGadflyDatabaseConnection来添加一个Gadfly数据库连接。
这会进入到一个与上面的添加MySQL适配器类似的表单页面中。
在这里输入id为Gadfly_database_connection,并选择DataSource为demo,点击Add按钮。
这样就增加了一个Gadfly数据库连接。
单击新建的数据库连接对象,看到的是它的状态页。
从本页可以知道你是否连接到了数据库(有一个按钮控制数据库的连接和断开)。
一般情况下,Zope会自动连接到数据源。
某些情况下,你可能想到手工控制数据库的连接。
对Gadfly来说,它是把所有数据都加载到内存中,断开连接没有什麽意义,但是对于外部的数据库,就有必要手工控制它们的连接。
提示
如果你使用不同类型的数据库来进行这些示例的话,会发现只有很少的不同,但它们有一个共同点就是都有一个Test标签页用于测试SQL查询,并且都有Browser标签页来显示表结构。
下一页是属性页,如图14.2。
该页显示数据源和连接对象的其他一些属性。
"Title"属性是一般Zope对象都有的,可以保持为空,这里比较有用的是数据源属性和是否立即连接属性。
当你想把数据源换成另外一个时,就会用到数据源属性,下面的"ConnectImmediately"属性控制了是否立即连上数据库。
【图14.2】属性页
14.1.4 测试数据库连接
在测试页可以测试你的数据库连接。
在该页,你可以直接输入SQL语句操作你的数据库。
该页用来测试数据库,同时运行SQL语句(比如创建一个表)。
此处不宜输入过多的SQL语句。
SQL语句要放在ZSQL方法中,本章后面将作讲解。
让我们在数据库中创建一个表以便展示本章的例子。
测试页允许直接输入SQL语句操作数据库。
你可以在测试页输入SQL创建数据表,创建名为employees的表使用如下SQL语句:
CREATETABLEemployees
(
emp_idINTEGER,
firstVARCHAR,
lastVARCHAR,
salaryFLOAT
)
单击提交按钮运行这条SQL语句。
Zope会返回一个验证页告诉你什么SQL在运行和可能的结果。
此处创建表的SQL会因你的数据库不同而各异。
数据库建表的确切语句,请参考你的具体的数据库提供商的文档。
还需要注意的是有些数据库如MySQL在客户端操作时需要一个分号结尾,但是这里在测试标签页中不需要分号。
这个SQL语句将在Gadfly数据库中新建一个名为employees的表。
该表有四列:
emp_di,first,last,salary。
一列是员工的id,这是标志员工的唯一号码。
接着的两列类型是VARCHAR,该类型和字符串类似。
salary列的类型是FLOAT,即浮点数。
不同的数据库提供不同的数据类型,参考相关文档查看你的数据库支持的数据类型。
为了保证员工号是唯一的,需要为表创建一个索引。
在测试页输入下面的SQL语句:
CREATEUNIQUEINDEXemp_idONemployees
(
emp_id
)
现在你有了一个表并且创建了一个索引,要验证你的表,转到浏览页。
该页显示了数据库的表和它们的模式。
在这里,你可以看到一个employees表。
假如点击了前边的“加号”,该表会展开,显示出四列:
emp_id,first,last,salary。
如图14.3所示:
【图14.3】浏览数据连接
当创建多表复杂SQL应用时,这是非常有用的,各表的结构一目了然。
但不是所有的数据库都支持表的浏览。
注意,一个Zope连接对象只对应一个用户连接关系数据库,如果你想要连接多个数据库,或者使用不同用户连接到一个数据库,都需要使用多个数据库连接对象。
14.2 ZSQL方法
ZSQL方法用于执行具体的关系数据库SQL语言。
所有的ZSQL方法都必须和一个数据库连接对象关联。
在数据库连接对象的Test标签页只能作一些简单的SQL查询语句作为测试,但程序中常常需要动态地生成SQL语句去执行,这就需要一种动态生成文本的技术,ZSQL方法正是为了这个目的而创造的技术。
它在Zope中通过数据库连接对象去执行SQL语句,因此所有的ZSQL方法都必须关联一个数据库连接对象。
14.2.1 DTML简介
ZSQL的目的是为了创建动态的SQL语句,在Zope中,ZSQL的这种动态特性是使用DTML技术来实现的。
因此这一节先对DTML技术作一个简单介绍。
DTML全称为动态模板标记语言(DynamicTemplateMarkupLanguage),它适合于生成各种类型的文本结构。
但DTML技术现在已经过时了,在生成xhtml结构化文本的领域已经由页面模板(zpt)技术所取代,只在少数需要生成非xhtml文本的领域,如动态生成css文件,动态生成SQL语句等,仍然在使用着DTML技术。
在Zope的添加选择框中,可添加两种DTML对象,分别是DTMLMethod和DTMLDocument,但DTMLDocument已经过时,我们一般使用DTMLMethod对象。
如图所示是一个DTML方法(DTMLMethod)的编辑表单:
【图14.4】DTML方法
在DTML中包含两种标签:
单一标签与区块标签。
单一标签由一个标签及小于(<)、大于(>)符号组成,例如var标签就是一种单一标签:
单一标签不需要替var作结束的动作。
这一句的意思是替换成parrot变量的内容。
上面的语句,还可以简化如下书写:
&dtml-cockatiel;
区块标签则由两个标签组成,其中一个开启此区块,另一个用以关闭区块,而内容夹在二者之间。
“开启标签”启动这个区块,而“结束标签”将之结束。
“结束标签”与“开启标签”的名字相同,但是“结束标签”的前面会加一个斜线(/),这跟HTML、XML的习惯相同。
background:
url("");
width:
px;
height:
px;
这里引入了dtml-with这个区块标记。
dtml-with用于指定一个新的名字空间,表示优先从with所指明的对象(happy_logo.jpeg)上读取属性。
后面的几个dtml-var标记中,id、width、height都是对象"happy_logo.jpeg"的属性,因此直接从"happy_logo.jpeg"对象上读取。
其他Plone会使用的DTML标记,还包括dmtl-in。
dmtl-in表示循环,和tal:
repeat的功效类似,这里就不多介绍了。
14.2.2 添加ZSQL方法对象
下面创建一个名为hire_employee的ZSQL方法用来给employees表添加一条新纪录。
当雇佣新员工时调用这个方法在employees表中插入新员工的记录。
同样是从ZMI管理界面的添加列表中选择"ZSQLMethod"转到ZSQL方法的添加表单页,如图14.5所示:
【图14.5】ZSQL方法的添加页
同新建其它对象一样,你要为ZSQL方法指定id和title,只有id是必需的。
另外,需要为ZSQL方法指定一个数据库连接对象。
因为这里只创建了一个Gadfly连接对象,因此在ConnectionId中只一个可选项。
以hire_employee为id,以Gadfly_database_connection为连接对象新建一个ZSQL方法。
接下来你可以给ZSQL方法指定参数。
就像脚本一样,ZSQL方法能接受参数。
参数用来构造SQL语句。
本例中要指定四个参数:
员工号,名字,姓氏和员工的薪水。
在参数框中输入emp_idfirstlastsalary,参数可以各自写在一行上,也可以都写在一行中,中间用空格分开。
参数也可以像Script(Python)一样使用默认参数值。
例如:
emp_id=100表示emp_id的缺省值是100。
最后的文本框里输入查询模板。
此处包含的是调用ZSQL时执行的SQL语句。
在此处输入下面的SQL语句:
INSERTINTOemployees(emp_id,first,last,salary)VALUES
(
,
,
,
)
注意到这里就使用了DTML语句,使用设置了type属性的dtml-sqlvar来引用emp_id等变量。
这里的dtml-sqlvar的作用与dtml-var类似,但提供了更多SQL功能特性,下文会详细解释。
这里对ZSQL的语法作简单介绍就是:
∙它是一种生成的SQL语句的语言,因此其主体结构是以SQL为基础
∙执行参数放在DTML标记中:
∙
其中的parameter就是在ZSQL的参数上声明的参数,dtml的部分有dtml-sqlvar,dtml-sqltest,dtml-sqlgroup几种形式,针对这几种形式有不同的属性="属性值",本章后面会分别介绍。
因此,假如emp_id=42,first='Bob',last='Uncle',salary=50000.00,这里生成的SQL将会是:
INSERTINTOemployees(emp_id,first,last,salary)VALUES
(42,'Bob','Uncle',50000.00)
新建ZSQL方法有三个按钮选择。
Add按钮将新建ZSQL方法并返回该对象的文件夹。
AddandEdit按钮将新建ZSQL方法并进入此方法的编辑页。
AddandTest按钮新建ZSQL方法后会自动转到测试页,可以在这里测试新建的ZSQL方法。
现在单击添加按钮新建一个ZSQL方法。
现在你创建了插入新员工记录的ZSQL方法,还需要一个ZSQL方法来查询员工。
以list_all_employees为id新建一个ZSQL方法。
不需要参数,SQL语句如下:
SELECT*FROMemployees
这条简单的SQL语句会返回employees表中的所有记录。
14.2.3 测试ZSQL方法
现在你有了两个ZSQL方法:
一个用来插入新员工,另一个用来显示数据库中所有的员工。
让我们测试一下这两个方法:
先插入一些新员工,然后罗列出他们。
进入hire_employee方法的测试页,如图14.6所示:
【图14.6】hire_employee的测试页
在这里可以看到一个有四个输入框的表单,对应ZSQL方法的四个参数。
Zope根据ZSQL方法的四个参数自动生成了这个表单。
hire_employee方法有四个参数,所以Zope生成了一个四个输入框的表单。
输入一个员工号42,名字Bob,姓氏McBob和薪水50000.00测试这个方法。
单击SubmitQuery按钮,你将看到测试的结果。
结果显示本语句不返回任何对象。
这是因为hire_employee方法只是插入记录,不进行任何选择,不返回任何记录。
同时你可以看到查询模板生成的SQL语句。
同期望的一样,sqlvarDTML将四个参数插入了要执行的SQL语句。
反复测试这个SQL方法可以将多个员工的信息插入数据库中。
为了验证数据是否插入到表中,选择list_all_employeesZSQL方法并进入它的测试页。
测试这个方法不需要输入,因为它没有参数。
直接点击SubmitQuery提交查询:
【图14.7】list_all_employees的测试页
这个方法返回employees表的内容。
虽然你添加的记录或许与这不一样,但可以看到一个类似的结果。
你加入的新员工都被显示出来了。
14.2.4 使用ZSQL方法的更多SQL功能
ZSQL是一种DTML扩展而来的技术,它在DTML的基础上扩展了一些专用于构造复杂SQL查询的标记,有sqlvar,sqltest,sqlgroup这三个,下面我们将分别学习。
14.2.4.1 使用sqlvar引用参数
上面的例子中已经看到,sqlvar是用来引用参数。
使用sqlvar可以对传入的参数生成正确的SQL类型,并且对用户可能输入的非法SQL数据作合适的引用。
因为插入数据时使用正确的数据类型非常重要。
如果你使用字符串“12”而要求的数据类型是整型,数据库就会报错。
更糟糕的是:
不同的数据库支持的数据类型不尽相同。
使用sqlvar可以自动生成这些数据库中所需要的正确的类型,这在Zope这一层上统一了不同关系数据库所支持的SQL语法的差异。
而且类型验证不只是为了避免出错,而且也是处于安全考虑。
一种常见的SQL注入式攻击(SQLInjection)就可以使用sqlvar来防范。
假如你有一个查询语句如下所示,这里使用dtml-var来引用可变的部分:
SELECT*FROMemployeesWHEREemp_id=
这个查询是不安全的。
因为如果有人输入下面的语句:
"12;DROPTABLEemployees"
这将生成如下SQL语句:
SELECT*FROMemployeesWHEREemp_id=12;DROPTABLEemployees
执行这条语句后表employees将被删除!
为了避免这些问题,就必须进行类型检查。
ZSQL方法提供了sqlvar就是用来做这件事的。
上面例子安全的写法应是:
SELECT*FROMemployeesWHEREemp_id=
sqlvar和DTML的var用法相似。
但sqlvar会对SQL类型进行检查,当没有输入时默认值设为NULL。
每个DTML标记都有一些可选的属性集,在sqlvar标记上有这些属性可用:
【表14.3】sqlvar所支持的属性
名称
是否必须
说明
name
是
指定名称,一般对应一个ZSQL的参数。
其中name部分可以省略,如也就是
type
是
这个属性是将要使用在SQL中的值的类型,type的值有string,int,float,nb(非空字符串)
optional
否
这个属性用来说明sqlvar可以省略或可以是个空值。
假如变量不存在或为空,sqlvar将不会提交这个变量。
这些属性中type属性是sqlvar语句的关键属性。
它负责插入变量类型的正确性。
处理SQL时你总是应该使用sqlvar代替var来保证SQL的安全。
14.2.4.2 使用sqltest进行条件测试
许多SQL查询语句都要用到条件比较。
它们遍历表中记录,查找符合输入条件的记录。
但在不同的关系数据库中的比较查询语法可能会有着轻微的不同,使用sqltest可以在Zope这一层上统一这些差异。
例如:
你可能想查询所有薪水