为了账号安全,请及时绑定邮箱和手机立即绑定

我的第一个python web开发框架(31)——定制ORM(八)

标签:
Python

 写到这里,基本的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

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消