写到这里,基本的ORM功能就完成了,不知大家有没有发现,这个ORM每个方法都是在with中执行的,也就是说每个方法都是一个完整的事务,当它执行完成以后也会将事务提交,那么如果我们想要进行一个复杂的事务时,它并不能做到,所以我们还需要对它进行改造,让它支持sql事务。
那么应该怎么实现呢?我们都知道要支持事务,就必须让不同的sql语句在同一个事务中执行,也就是说,我们需要在一个with中执行所有的sql语句,失败则回滚,成功再提交事务。
由于我们的逻辑层各个类都是继承ORM基类来实现的,而事务的开关放在各个类中就不合适,可能会存在问题,所以在执行事务时,直接调用db_helper模块,使用with初始化好数据库链接,然后在方法里编写并执行各个sql语句。
当前逻辑层基类(ORM模块)的sql语句都是在方法中生成(拼接)的,然后在方法的with模块中执行,所以我们需要再次对整个类进行改造,将所有的sql生成方法提炼出来,成为单独的方法,然后在事务中,我们不直接执行获取结果,而是通过ORM生成对应的sql语句,在with中执行这样语句。(当然还有其他方法也能实现事务,不过在这里不做进一步的探讨,因为当前这种是最简单实现事务的方式之一,多层封装处理,有可能会导致系统变的更加复杂,代码更加难懂)
代码改造起来很简单,比如说获取记录方法
1 def get_model(self, wheres): 2 """通过条件获取一条记录""" 3 # 如果有条件,则自动添加where 4 if wheres: 5 wheres = ' where ' + wheres 6 7 # 合成sql语句 8 sql = "select %(column_name_list)s from %(table_name)s %(wheres)s" % \ 9 {'column_name_list': self.__column_name_list, 'table_name': self.__table_name, 'wheres': wheres}10 # 初化化数据库链接11 result = self.select(sql)12 if result:13 return result[0]14 return {}
我们可以将它拆分成get_model_sql()和get_model()两个方法,一个处理sql组合,一个执行获取结果,前者可以给事务调用,后者直接给对应的程序调用
1 def get_model_sql(self, wheres): 2 """通过条件获取一条记录""" 3 # 如果有条件,则自动添加where 4 if wheres: 5 wheres = ' where ' + wheres 6 7 # 合成sql语句 8 sql = "select %(column_name_list)s from %(table_name)s %(wheres)s" % \ 9 {'column_name_list': self.__column_name_list, 'table_name': self.__table_name, 'wheres': wheres}10 return sql11 12 def get_model(self, wheres):13 """通过条件获取一条记录"""14 # 生成sql15 sql = self.get_model_sql(wheres)16 # 初化化数据库链接17 result = self.select(sql)18 if result:19 return result[0]20 return {}
其他代码不一一细述,大家自己看看重构后的结果
View Code
从完整代码可以看到,重构后的类多了很多sql生成方法,它们其实是从原方法中分享出sql合成代码,将它们独立出来而已。
接下来我们编写单元测试代码,执行一下事务看看效果
1 #!/usr/bin/evn python 2 # coding=utf-8 3 4 import unittest 5 from common import db_helper 6 from common.string_helper import string 7 from config import db_config 8 from logic import product_logic, product_class_logic 9 10 11 class DbHelperTest(unittest.TestCase):12 """数据库操作包测试类"""13 14 def setUp(self):15 """初始化测试环境"""16 print('------ini------')17 18 def tearDown(self):19 """清理测试环境"""20 print('------clear------')21 22 def test(self):23 ##############################################24 # 只需要看这里,其他代码是测试用例的模板代码 #25 ##############################################26 # 测试事务27 # 使用with方法,初始化数据库链接28 with db_helper.PgHelper(db_config.DB, db_config.IS_OUTPUT_SQL) as db:29 # 实例化product表操作类ProductLogic30 _product_logic = product_logic.ProductLogic()31 # 实例化product_class表操作类product_class_logic32 _product_class_logic = product_class_logic.ProductClassLogic()33 # 初始化产品分类主键id34 id = 135 36 # 获取产品分类信息(为了查看效果,所以加了这段获取分类信息)37 sql = _product_class_logic.get_model_for_pk_sql(id)38 print(sql)39 # 执行sql语句40 result = db.execute(sql)41 if not result:42 print('不存在指定的产品分类')43 return44 print('----产品分类实体----')45 print(result)46 print('-------------------')47 48 # 禁用产品分类49 fields = {50 'is_enable': 051 }52 sql = _product_class_logic.edit_model_sql(id, fields, returning='is_enable')53 print(sql)54 # 执行sql语句55 result = db.execute(sql)56 if not result:57 # 执行失败,执行回滚操作58 db.rollback()59 print('禁用产品分类失败')60 return61 # 执行缓存清除操作62 _product_class_logic.del_model_for_cache(id)63 _product_class_logic.del_relevance_cache()64 print('----执行成功后的产品分类实体----')65 print(result)66 print('-------------------------------')67 68 # 同步禁用产品分类对应的所有产品69 sql = _product_logic.edit_sql(fields, 'product_class_id=' + str(id), returning='is_enable')70 print(sql)71 # 执行sql语句72 result = db.execute(sql)73 if not result:74 # 执行失败,执行回滚操作75 db.rollback()76 print('同步禁用产品分类对应的所有产品失败')77 return78 # 执行缓存清除操作79 for model in result:80 _product_class_logic.del_model_for_cache(model.get('id'))81 _product_class_logic.del_relevance_cache()82 print('----执行成功后的产品实体----')83 print(result)84 print('---------------------------')85 86 db.commit()87 print('执行成功')88 ##############################################89 90 if __name__ == '__main__':91 unittest.main()
细心的朋友可能会发现,在事务处理中,进行编辑操作以后,会执行缓存的清除操作,这是因为我们在ORM中所绑定的缓存自动清除操作,是在对应的执行方法中,而不是sql生成方法里,所以在进行事务时,如果你使用了缓存的方法,在这里就需要手动添加清除缓存操作,不然就会产生脏数据。
执行结果:
1 ------ini------ 2 select * from product_class where id = 1 3 ----产品分类实体---- 4 [{'add_time': datetime.datetime(2018, 8, 17, 16, 14, 54), 'id': 1, 'is_enable': 1, 'name': '饼干'}] 5 ------------------- 6 update product_class set is_enable = 0 where id = 1 returning id , is_enable 7 ----执行成功后的产品分类实体---- 8 [{'id': 1, 'is_enable': 0}] 9 -------------------------------10 update product set is_enable = 0 where product_class_id=1 returning id , is_enable11 ----执行成功后的产品实体----12 [{'id': 2, 'is_enable': 0}, {'id': 7, 'is_enable': 0}, {'id': 14, 'is_enable': 0}, {'id': 15, 'is_enable': 0}]13 ---------------------------14 执行成功15 ------clear------
本文对应的源码下载(一些接口进行了重构,有些还没有处理,所以源码可能直接运行不了,下一章节会讲到所有代码使用ORM模块重构内容)
版权声明:本文原创发表于 博客园,作者为 AllEmpty 本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。
原文出处:https://www.cnblogs.com/EmptyFS/p/9484686.html
共同学习,写下你的评论
评论加载中...
作者其他优质文章