四、更复杂的DB-API脚本
前面的示例脚本Server_version.py有许多缺点,比如,它没有捕捉异常,也不能在出错时指出到底是什么样的错误,此外,它也不允许执行语句时不返回任何结果。下面通过一个更加“高级”的脚本animal.py来演示如何解决这些问题,这里给出完整的animal.py代码。
Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ –> #animal.py:创建动物表并从中检索信息 import sys import MySQLdb #连接到MySQL服务器 try: conn = MySQLdb.connect (host = “localhost”, user = “testuser”, passwd = “testpass”, db = “test”) except MySQLdb.Error, e: print “Error %d: %s” % (e.args[0], e.args[1]) sys.exit (1) #创建动物表并填充内容 try: cursor = conn.cursor () cursor.execute (“DROP TABLE IF EXISTS animal”) cursor.execute (“”” CREATE TABLE animal ( name CHAR(40), category CHAR(40) ) ”””) cursor.execute (“”” INSERT INTO animal (name, category) VALUES (‘snake’, ‘reptile’), (‘frog’, ‘amphibian’), (‘tuna’, ‘fish’), (‘racoon’, ‘mammal’) ”””) print “Number of rows inserted: %d” % cursor.rowcount #使用fetchone()进行循环提取 cursor.execute (“SELECT name, category FROM animal”) while (1): row = cursor.fetchone () if row == None: break print “%s, %s” % (row[0], row[1]) print “Number of rows returned: %d” % cursor.rowcount #使用fetchall()进行循环提取 cursor.execute (“SELECT name, category FROM animal”) rows = cursor.fetchall () for row in rows: print “%s, %s” % (row[0], row[1]) print “Number of rows returned: %d” % cursor.rowcount #发出修改名称的语句,共两种方式,第一种是在语句字符串 #中使用数据值的字面值,第二种是使用位置标识符 cursor.execute (“”” UPDATE animal SET name = ‘turtle’ WHERE name = ‘snake’ ”””) print “Number of rows updated: %d” % cursor.rowcount cursor.execute (“”” UPDATE animal SET name = %s WHERE name = %s ”””, (“snake”, “turtle”)) print “Number of rows updated: %d” % cursor.rowcount #创建一个字典游标,这样就可以使用位置而非名称来访问数据列中的值了。 cursor.close () cursor = conn.cursor (MySQLdb.cursors.DictCursor) cursor.execute (“SELECT name, category FROM animal”) result_set = cursor.fetchall () for row in result_set: print “%s, %s” % (row[“name”], row[“category”]) print “Number of rows returned: %d” % cursor.rowcount cursor.close () except MySQLdb.Error, e: print “Error %d: %s” % (e.args[0], e.args[1]) sys.exit (1) conn.commit () conn.close () |
Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ –> CREATE TABLE animal ( name CHAR(40), category CHAR(40) ) |
本例中的表和一些语句取自于PEAR DB的说明文档。脚本animal.py的开头部分如下所示,从#!行可以看出它是打算运行于UNIX系统的:
Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ –> #!/usr/bin/python # animal.py – 创建动物表并从中检索信息 import sys import MySQLdb |
如同Server_version.py一样,这个脚本也导入了MySQLdb,此外,它还导入了sys模块以供错误处理之用。如果发生错误,animal.py就会利用sys.exit()返回1来表明脚本异常结束。
下面介绍错误处理。导入必要的模块之后,animal.py使用connect()调用建立到服务器的连接。为了处理连接故障,比如,显示故障的原因,该脚本必须捕捉异常。在Python语言中,为了处理异常,必须把代码放到try语句中,并且包括一个except子句来包含错误处理代码。生成的连接的代码如下所示:
Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ –> try: conn = MySQLdb.connect (host = “localhost”, user = “testuser”, passwd = “testpass”, db = “test”) except MySQLdb.Error, e: print “Error %d: %s” % (e.args[0], e.args[1]) sys.exit (1) |
Except子句中的异常类MySQLdb.Error用于取得MySQLdb可以提供的具体数据库错误信息,而变量e则用来存放错误信息。如果出现异常,MySQLdb会把有关信息存入e.args——这是一个包含错误代码和描述该错误的字符串组成的双元素元组。在本例中,except子句会打印这些值,然后退出。
任何数据库有关的语句都可以放入类似的try/except结构中来收集和报告错误,为了简便起见,后面的讨论中不再显示异常处理代码。
接下来介绍用于发送语句的方法。Animal.py接下来的代码将创建一个游标对象,并利用它发送设置和填充动物表的语句。这部分代码如下所示:
Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ –> cursor = conn.cursor () cursor.execute (“DROP TABLE IF EXISTS animal”) cursor.execute (“”” CREATE TABLE animal ( name CHAR(40), category CHAR(40) ) ”””) cursor.execute (“”” INSERT INTO animal (name, category) VALUES (‘snake’, ‘reptile’), (‘frog’, ‘amphibian’), (‘tuna’, ‘fish’), (‘racoon’, ‘mammal’) ”””) print “Number of rows inserted: %d” % cursor.rowcount |
需要注意的是,这里的代码没有包含错误检查。请记住,它们可以放入try语句,这样一旦出错就会触发异常,继而被except子句所捕获并处理。但是考虑到代码的可读性,我们这里只给出了代码的主干部分。上面的语句将完成以下动作:
l 动物表已经存在,则丢弃它。
l 创建动物表。
l 向表中插入一些数据,并报告添加的行数。
这些语句都是通过调用游标对象的execute()方法发出的。其中前两个execute()语句不会生成数据,但是第三个语句将生成一个表示已经插入行数的统计量。这个统计数字存放在游标的rowcount属性中。有些数据库接口是通过execution运行调用的返回值来提供这个统计数字的,但是DB-API却不是这样。
此动物表已经建好,所以我们可以发出选择指令来从中检索信息了。如同前面的语句一样,SELECT语句也要使用execute()方法发出。然而,与DROP或者INSERT语句不同的是,SELECT语句会生成一个结果集合,也就是说,execute()仅仅发出语句,但是却没有返回结果集合。我们可以使用fetchone()方法每次返回一行数据,或者使用fetchall()方法一次全部搞定。在animal.py中,这两者方法都用到了。下面是如何使用fetchone()每次检索一行数据的方法:
Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ –> cursor.execute (“SELECT name, category FROM animal”) while (1): row = cursor.fetchone () if row == None: break print “%s, %s” % (row[0], row[1]) print “Number of rows returned: %d” % cursor.rowcount |
方法fetchone()会把结果集合的下一行作为一个元组返回,如果已经到了结果集合的末尾的话,就返回值None。这里的循环会进行相应的检查,并在取尽结果集合的时候退出。对于返回的每一行,元组包含了两个值,Print语句会打印输出每个元组元素。然而,因为它们是安装在元组中的顺序使用的,所以Print语句正好可以如下编写:
Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ –> print “%s, %s” % row |
显示此语句结果之后,脚本还会显示返回的行数,即rowcount属性的值。
Fetchall()可以把整个结果集合作为以元组为元素的元组一次返回,或者,如果结果集合为空则会返回一个空的元组。为了访问个别数据行,可以枚举fetchall()返回的行集合,具体代码如下所示:
Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ –> cursor.execute (“SELECT name, category FROM animal”) rows = cursor.fetchall () for row in rows: print “%s, %s” % (row[0], row[1]) print “Number of rows returned: %d” % cursor.rowcount |
上面通过访问rowcount来打印行数。当fetchall()的时候,另一种确定行数的方法是使用它返回的值的长度,如下所示:
Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ –>print “%d rows were returned” % len (rows) |
前面的循环语句中是把数据行作为元组看待的,如果我们将其作为字典处理的话,就可以通过名字来访问各列的值了。以下代码展示了这一过程。需要注意的是,访问字典需要一种不同的游标,所以这里关闭了原来的游标,并利用一个不同的游标类获得了一个新游标,如下所示:
Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ –>print “%d rows were returned” % len (rows) |
结果集合中的空值将作为None返回。MySQLdb支持位置标识符功能,利用它可以在语句字符串之内为数据值绑定特殊标记。这就为直接向语句中嵌入值提供了替代方法。位置标识符机制会给数据值添加引号,并逸出出现在这些值内的所有的特殊字符。下面的示例演示了一个把蛇改成海龟的UPDATE语句,首先使用的是字面值,然后使用的是位置标识符。其中使用字面值的语句看上去是这样的:
Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ –> cursor.execute (“”” UPDATE animal SET name = ‘turtle’ WHERE name = ‘snake’ ”””) print “Number of rows updated: %d” % cursor.rowcount |
另外,我们还可以使用位置标识符标记%s,并为其捆绑相应的值的方式来发送这个语句,代码如下所示:
Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ –> cursor.execute (“”” UPDATE animal SET name = %s WHERE name = %s ”””, (“snake”, “turtle”)) print “Number of rows updated: %d” % cursor.rowcount |
这里是上面的execute()调用方式的注意事项:
l 每个位置标识符%s对应于一个插入该语句字符串的值。
l 指示符%s不应该用引号括住,MySQLdb会根据需要添加引号。
l 绑定给位置标识符的值放在一个元组中,它们在元组中的顺序就是出现在语句中的顺序。如果只有一个值x的话,可以写作(x,),表示这是个单元素元组。
l 可以给位置标识符绑定一个None值,这表示向该语句中插入一个SQL空值。
发出有关语句之后,animal.py将关闭此游标,确认修改,并断开跟服务器的连接,如下所示:
Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ –> cursor.execute (“”” UPDATE animal SET name = %s WHERE name = %s ”””, (“snake”, “turtle”)) print “Number of rows updated: %d” % cursor.rowcount |
连接对象的commit()方法确保当前事务中的修改已经在数据库中完成。在DB-API中,autocommit模式被禁用了,所以在断开连接之前必须调用commit(),否则所作修改可能会丢失。
如果动物表是一个MyISAM表,commit()就不起作用了:MyISAM是一种非事务性存储引擎,所以对MyISAM表的修改会立即生效,与autocommit模式无关。如果使用了事务性存储引擎,当断开连接的时候如果不调用commit()会导致一个隐式的事务回滚。举例来说,如果我们在CREATE TABLE语句后面加上ENGINE = InnoDB,并删除脚本末尾处的commit()调用,就会发现脚本运行后animal为空。
对于仅仅检索数据的脚本,由于不用对修改进行确认,所以commit()对它们来说也是不需要的。
五、关于移植事项
如果希望把基于MySQLdb的DB-API脚本移植到不同的数据库,则要需要修改的地方主要是出现驱动程序名称的地方:
1. 用于导入驱动模块的import语句,必须进行修改以便导入相应的驱动程序。
2. 连接数据库服务器的connect()调用。此connect()方法是通过驱动模块的名称进行访问的,所以驱动程序名称需要更改。此外,connect()参数语法也会随着驱动程序的不同而变化。
3. 异常处理。在except子句中的异常类也是通过驱动程序名称引用的,所以也要根据需要进行相应的修改。
进行移植时,除了驱动程序名称之外还有一些地方要注意,那就是位置标识符。DB-API规范允许使用某些位置标识符语法,但是一些驱动程序使用的语法确不同于MySQLdb支持的语法。
六、小结
本文向读者详细介绍如何利用DB-API模块方便地开发MySQL脚本。我们首先介绍了有关软件的安装方法,随后分别用两个实例对DB-API模块做了深入的介绍,最后讨论了用Python DB-API编写的MySQL脚本的移植注意事项。希望本文能够对您有所帮助。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
![TechTarget微信公众号二维码](/wp-content/uploads/res/images/spriteimg/ttweixin.jpg)
TechTarget
官方微博
![TechTarget中国官方微博二维码](/wp-content/uploads/res/images/spriteimg/ttweibo.jpg)
TechTarget中国
作者
相关推荐
-
SQL Server 2017将Python视为首选分析工具
Python不再被微软数据库排除在外。SQL Server 2017发布的第二个预览版本,支持使用Python编程语言与R语音用于分析。
-
使用Cassandra进行.Net编程
本文将介绍如何针对特定的架构设计实现特定的功能. 最终实现基于Dotnet Cassandra存储的应用开发。
-
解读SQL Server数据库存储过程发展历史
SQL Server存储过程可以是Transact-SQL(T-SQL)语句,或者是.NET框架的公共语言运行时(CLR),它是专为方便数据库查询而设计的。
-
使用Python来连接MySQL
本来以为使用Python安装MySQL是件容易的事,但是发现,不管怎样每次安装编译都不通过。强大的pip install mysql-python 不再管用。