http://zetcode.com/db/mysqlpython/
这个地址中有一些关于mysqldb模块的使用介绍。
其中关键一点的是事务支持。
“
For databases that support transactions, the Python interface silently starts a transaction when the cursor is created. The commit() method commits the updates made using that cursor, and the rollback() method discards them.
”
上面这句话说的比较好。在py的mysqldb中,一旦创建了一个cursor,那么就默认创建了一个事务。直到提交事务为止,数据库的数据才会进行更改。但是对于不支持事务的数据库来说,事务不起作用。
------------------------------------------------------------
上面是mysqldb的事务支持。那么,我自己的pybatis要怎么实现呢?
目前是这样的:
对于单一的查询,开启一个数据库连接,执行sql,然后提交事务,关闭cursor和conn即可。
但是对于用户需要全局事务来说,是这样的:
把所有的查询都放在同一个connection中。在最后的时候再使用conn.commit()进行提交。
贴一下临时的transactionmanager的代码:
# -*- coding:utf-8 -*- ''' Created on 2013-3-10 @author: naughty ''' from _mysql_exceptions import IntegrityError from com.util.Data2Object import Data2Object from com.util.SqlPreprocessing import processSql import MySQLdb as mdb class TransactionManager(object): ''' handles all transaction and db query ''' def __init__(self): ''' 初始化的时候传入一个连接 ''' self.conn = mdb.connect(host='localhost', user='', passwd='', db='test') #======================================================================= # 初始化一个cursor #======================================================================= self.cursor = self.conn.cursor() def startTransaction(self): ''' For databases that support transactions, the Python interface silently starts a transaction when the cursor is created. so we do nothing here. ''' pass def commitTransaction(self): ''' 提交事务 ''' self.cursor.close() self.conn.commit() def endTransaction(self): ''' 结束事务 ''' pass def rollbackTransaction(self): ''' 回滚事务 ''' self.cursor.close() self.conn.rollback() def queryInsert(self, sqlid, inputObject): ''' 查询插入 ''' #======================================================================= # resultclasstype参数在没有返回值的时候用不到 #======================================================================= sql , resultclasstype = processSql(sqlid, inputObject) try: var=self.cursor.execute(sql) return var except IntegrityError: return -1 def queryUpdate(self, sqlid, inputObject): ''' 查询更新 ''' self.queryInsert(sqlid, inputObject) def queryDelete(self, sqlid, inputObject): ''' 查询删除 ''' self.queryInsert(sqlid, inputObject) def queryForObject(self, sqlid, inputObject): ''' 查询并返回一个对象 ''' sql, resultclasstype = processSql(sqlid, inputObject) self.cursor.execute(sql) objList = Data2Object.data2object(self.cursor, resultclasstype) if len(objList) == 0: return None elif len(objList) == 1: return objList[0] else: raise Exception('query for one object, but get many.'); def queryForList(self, sqlid, inputObject): ''' 查询并返回一个列表 ''' sql , resultclasstype = processSql(sqlid, inputObject) self.cursor.execute(sql) objList = Data2Object.data2object(self.cursor, resultclasstype) return objList
上面的代码只有在commitTransaction的时候才会提交事务。【rollbackTransaction的时候,最后还需要关闭连接。上面的代码忘记关闭了】
看下面的测试用例:
# -*- coding:utf-8 -*- ''' Created on 2013-3-5 @author: naughty ''' from com.domain import beans from com.domain.TransactionManager import TransactionManager from com.util.DBExecuteCenter import queryForObject, queryInsert, queryUpdate, \ queryDelete if __name__ == '__main__': s = beans.Student() s.age = '1' s.name = 'zoer' s.score = 11 t = TransactionManager() try: t.startTransaction() num = t.queryDelete('del', s) print num s.score = 22 num = t.queryDelete('del', s) print num t.commitTransaction() except: t.rollbackTransaction() print 'end'
用例中,尝试删除score是11和22的学生。但是,由于22是有外键约束的【我人为添加的一个外键约束】,所以删除22 的学生的时候会失败。这样,上面的代码在执行到删除22的时候由于抛出异常,就会去回滚事务。
--------------------------------
上面展示的是“大事务”控制。使用TransactionManager来操作。
下面展示一下单个操作时候的事务控制。
单个事务控制是放在 中进行解决的。
# -*- coding:utf-8 -*- ''' Created on 2013-3-6 @author: naughty ''' from Data2Object import Data2Object from com.util.SqlPreprocessing import processSql import MySQLdb as mdb import com.pybatis.Global def queryForObject(sqlid, inputObject=None): ''' 查询并返回对象 ''' #=========================================================================== # 每次都新建连接 #=========================================================================== conn = mdb.connect(host='localhost', user='', passwd='', db='test') cursor = conn.cursor() sql, resultclasstype = processSql(sqlid, inputObject) try: cursor.execute(sql) except: cursor.close() conn.rollback() conn.close() else: objList = Data2Object.data2object(cursor, resultclasstype) cursor.close() if len(objList) == 0: conn.close() return None elif len(objList) == 1: conn.close() return objList[0] else: conn.close() raise Exception('query for one object, but get many.'); def queryForList(sqlid, inputObject=None): ''' 查询并返回列表 ''' #=========================================================================== # 每次都新建连接 #=========================================================================== conn = mdb.connect(host='localhost', user='', passwd='', db='test') cursor = conn.cursor() sql , resultclasstype = processSql(sqlid, inputObject) try: cursor.execute(sql) except: cursor.close() conn.rollback() conn.close() else: objList = Data2Object.data2object(cursor, resultclasstype) cursor.close() conn.close() return objList def queryInsert(sqlid, inputObject=None): ''' 执行插入操作 ''' conn = mdb.connect(host='localhost', user='', passwd='', db='test') cursor = conn.cursor() sql , resultclasstype = processSql(sqlid, inputObject) try: count = cursor.execute(sql) except: #=========================================================================== # 关闭游标 #=========================================================================== cursor.close() conn.rollback() conn.close() count = -1 else: cursor.close() conn.commit() conn.close() return count def queryUpdate(sqlid, inputObject=None): ''' 执行更新操作 ''' queryInsert(sqlid, inputObject) def queryDelete(sqlid, inputObject=None): ''' 执行删除操作 ''' queryInsert(sqlid, inputObject)
单个事务控制的时候,把对数据库的操作放在了上面的这些函数中进行。具体看看queryInsert函数。操作是否成功需要根据返回值进行判断。如果返回值是-1,那么说明操作没有成功。相反则成功。
下面是一个使用的例子:
# -*- coding:utf-8 -*- ''' Created on 2013-3-5 @author: naughty ''' from com.domain import beans from com.domain.TransactionManager import TransactionManager from com.util.DBExecuteCenter import queryForObject, queryInsert, queryUpdate, \ queryDelete if __name__ == '__main__': s = beans.Student() s.age = '1' s.name = 'naughty' s.score = 11 count=queryInsert('insert',s) print count print 'end'
例子中插入了一个学生信息。由于数据库中已经存在了name是naughty的学生【name是主键】,所以插入失败。print出来的值是-1。
--------------------------------------
上面基本展示了pybatis处理全局事务和单个事务的方法。其本质就是将所有的事务处理交给基本的connection去处理,pybatis只是使用了connection。
------------------------------------------
至此,pybatis的事务管理就告一个段落了【不是最终版本】。
接下来还需要一个数据库连接池。