首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

14.5  事务

当前绝大多数数据库服务器支持事务。事务可以把多条对数据库的改动放到一条命令中。

事务对于数据库的可靠性而言非常重要。对于复杂的数据库,一个简单的逻辑改变会影响很多不同的表,并需要执行多个查询。例如:添加一个新的客户除了会需要一个客户表之外,还需要一个地址表。

如果这些情况中的某一个执行了,而由于某种原因另外的一个没有执行——也许是因为一个错误或是服务器当机——数据库将处在一个不一致的状态。(希望这两个表能够一致的软件将会在判断上产生混乱。)

事务可以确保所有的改变要么都被执行,要么都不执行。同时,它确保只有commit()被调用后,改变才生效。

在前面的例子中,思考一下如果在第二个INSERT语句前发生错误会怎样。答案是会产生一个异常,程序会终止。由于commit()并没有被调用,数据库不会改变什么。表并没有被建立,

第一行数据也没有被插入。

还有一个相关的函数称为rollback()。这个函数可以有效地放弃从上一次调用commit()或rollback()之后的改动。这个函数在您发现出现错误,想放弃已经发送的事务时非常有用。

在处理异常时您也应该使用rollback()。有些数据库服务器在错误发生后,在您试图使用commit()提交变更时,可能会与您期望的行为不同。

14.5.1  事件执行的性能

执行事件的性能很大程度取决于不同的服务器。然而,有一些共同的规律:

l  在每个单独的命令后都提交是更新数据库的最慢的方法。

l  一次提交非常大的数据会使服务器事件buffer溢出,并产生错误或当机。

让我们假设您想往数据库中插入大量数据——也许您要插入50 000条,对于每一条,您运行一次INSERT INTO指令。您或许会在每条后运行一次commit(),因为那就是事件的全部。这样是可以的,但是会很慢,并且这需要您在代码中考虑分载负荷。

或许您会考虑在执行所有的50 000指令后只执行一次commit()。这种可行性,取决于您的数据库。也许您会使您服务器的内存溢出,因为它会试图在commit()中保存50 000指令。有些服务器也许可以,但是如果您想您的代码能在多种数据库上运行,您就不应该这样做。

一个折衷的方法是在每100条指令后调用一次commit()。这样,可以避免性能下降,同时也可以避免服务器溢出。然而,您还需要确保在服务器当机时,您可以处理。您的程序不得不清空表,或者确保不重复插入一条相同的数据。

14.5.2  在结束前隐藏改变

事务的一个有趣的副作用是,其他用户只有当您提交了它们之后,才能看到数据的改变。下面是一个利用了这个概念的例子:

#!/usr/bin/env python

# Commit example - Chapter 14 - commit.py

import psycopg

def getdsn(db = None, user = None, passwd = None, host = None):

    if user == None:

        # Default user to the one they're logged in as

        import os, pwd

        user = pwd.getpwuid(os.getuid())[0]

    if db == None:

        # Default to the username.

        db = user

    dsn = 'dbname=%s user=%s' % (db, user)

    if passwd != None:

        dsn += ' password=' + passwd

    if host != None:

        dsn += ' host=' + host

    return dsn

dsn = getdsn()

print "Connecting to %s" % dsn

dbh = psycopg.connect(dsn)

print "Connection successful."

cur = dbh.cursor()

cur.execute("DELETE FROM ch14")

cur.execute("INSERT INTO ch14 VALUES (0)")

dbh.commit()

dbh.close()

这个程序用一个单独的行替换了表的内容。一些自动插入程序会周期性运行,替换某个表的内容为新数据。

在这种情况下,使用事务的一个好处是,即使您发送了DELETE FROM指令,其他用户还可以从表中读取数据。只要在调用commit()之前,这都是可以的。所以,即使上传新数据需要花费您半个小时,用户在您调用commit()之前,看到的都是完整的旧版本。

注意:对于改变数据的程序来说,DB-API并没有定义是在提交前还是提交后数据改变。如果您对于数据运行查询,您不一定会看到没有提交的改变。在多数情况下,建立第二个数据库的连接,就能保证您看到待改变的数据还没有改变。

还有,请注意有些数据库不支持的事务。在这些系统上,改变是立刻的,commit()什么都不做,并且rollback()会产生错误。然而,所有当前流行的免费或商业的数据库都支持事务。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论