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的事务管理就告一个段落了【不是最终版本】。
接下来还需要一个数据库连接池。