我的第一个python web开发框架(31)——定制ORM(八)
写到这里,基本的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 sql 11 12 def get_model(self, wheres): 13 """通过条件获取一条记录""" 14 # 生成sql 15 sql = self.get_model_sql(wheres) 16 # 初化化数据库链接 17 result = self.select(sql) 18 if result: 19 return result[0] 20 return {}
其他代码不一一细述,大家自己看看重构后的结果
1 #!/usr/bin/env python 2 # coding=utf-8 3 4 from common import db_helper, cache_helper, encrypt_helper 5 6 7 class LogicBase(): 8 """逻辑层基础类""" 9 10 def __init__(self, db, is_output_sql, table_name, column_name_list='*', pk_name='id'): 11 """类初始化""" 12 # 数据库参数 13 self.__db = db 14 # 是否输出执行的Sql语句到日志中 15 self.__is_output_sql = is_output_sql 16 # 表名称 17 self.__table_name = str(table_name).lower() 18 # 查询的列字段名称,*表示查询全部字段,多于1个字段时用逗号进行分隔,除了字段名外,也可以是表达式 19 self.__column_name_list = str(column_name_list).lower() 20 # 主健名称 21 self.__pk_name = str(pk_name).lower() 22 # 缓存列表 23 self.__cache_list = self.__table_name + '_cache_list' 24 25 ##################################################################### 26 ### 生成Sql ### 27 def get_model_sql(self, wheres): 28 """通过条件获取一条记录""" 29 # 如果有条件,则自动添加where 30 if wheres: 31 wheres = ' where ' + wheres 32 33 # 合成sql语句 34 sql = "select %(column_name_list)s from %(table_name)s %(wheres)s" % \ 35 {'column_name_list': self.__column_name_list, 'table_name': self.__table_name, 'wheres': wheres} 36 return sql 37 38 def get_model_for_pk_sql(self, pk, wheres=''): 39 """通过主键值获取数据库记录实体""" 40 # 组装查询条件 41 wheres = '%s = %s' % (self.__pk_name, str(pk)) 42 return self.get_model_sql(wheres) 43 44 def get_value_sql(self, column_name, wheres=''): 45 """ 46 获取指定条件的字段值————多于条记录时,只取第一条记录 47 :param column_name: 单个字段名,如:id 48 :param wheres: 查询条件 49 :return: 7 (指定的字段值) 50 """ 51 if wheres: 52 wheres = ' where ' + wheres 53 54 sql = 'select %(column_name)s from %(table_name)s %(wheres)s limit 1' % \ 55 {'column_name': column_name, 'table_name': self.__table_name, 'wheres': wheres} 56 return sql 57 58 def get_value_list_sql(self, column_name, wheres=''): 59 """ 60 获取指定条件记录的字段值列表 61 :param column_name: 单个字段名,如:id 62 :param wheres: 查询条件 63 :return: [1,3,4,6,7] 64 """ 65 if not column_name: 66 column_name = self.__pk_name 67 elif wheres: 68 wheres = ' where ' + wheres 69 70 sql = 'select array_agg(%(column_name)s) as list from %(table_name)s %(wheres)s' % \ 71 {'column_name': column_name, 'table_name': self.__table_name, 'wheres': wheres} 72 return sql 73 74 def add_model_sql(self, fields, returning=''): 75 """新增数据库记录""" 76 ### 拼接sql语句 ### 77 # 初始化变量 78 key_list = [] 79 value_list = [] 80 # 将传入的字典参数进行处理,把字段名生成sql插入字段名数组和字典替换数组 81 # PS:字符串使用字典替换参数时,格式是%(name)s,这里会生成对应的字串 82 # 比如: 83 # 传入的字典为: {'id': 1, 'name': '名称'} 84 # 那么生成的key_list为:'id','name' 85 # 而value_list为:'%(id)s,%(name)s' 86 # 最终而value_list为字符串对应名称位置会被替换成相应的值 87 for key in fields.keys(): 88 key_list.append(key) 89 value_list.append('%(' + key + ')s') 90 # 设置sql拼接字典,并将数组(lit)使用join方式进行拼接,生成用逗号分隔的字符串 91 parameter = { 92 'table_name': self.__table_name, 93 'pk_name': self.__pk_name, 94 'key_list': ','.join(key_list), 95 'value_list': ','.join(value_list) 96 } 97 # 如果有指定返回参数,则添加 98 if returning: 99 parameter['returning'] = ', ' + returning 100 else: 101 parameter['returning'] = '' 102 103 # 生成可以使用字典替换的字符串 104 sql = "insert into %(table_name)s (%(key_list)s) values (%(value_list)s) returning %(pk_name)s %(returning)s" % parameter 105 # 将生成好的字符串替字典参数值,生成最终可执行的sql语句 106 return sql % fields 107 108 def edit_sql(self, fields, wheres='', returning=''): 109 """ 110 批量编辑数据库记录 111 :param fields: 要更新的字段(字段名与值存储在字典中) 112 :param wheres: 更新条件 113 :param returning: 更新成功后,返回的字段名 114 :param is_update_cache: 是否同步更新缓存 115 :return: 116 """ 117 ### 拼接sql语句 ### 118 # 拼接字段与值 119 field_list = [key + ' = %(' + key + ')s' for key in fields.keys()] 120 # 设置sql拼接字典 121 parameter = { 122 'table_name': self.__table_name, 123 'pk_name': self.__pk_name, 124 'field_list': ','.join(field_list) 125 } 126 # 如果存在更新条件,则将条件添加到sql拼接更换字典中 127 if wheres: 128 parameter['wheres'] = ' where ' + wheres 129 else: 130 parameter['wheres'] = '' 131 132 # 如果有指定返回参数,则添加 133 if returning: 134 parameter['returning'] = ', ' + returning 135 else: 136 parameter['returning'] = '' 137 138 # 生成sql语句 139 sql = "update %(table_name)s set %(field_list)s %(wheres)s returning %(pk_name)s %(returning)s" % parameter 140 return sql % fields 141 142 def edit_model_sql(self, pk, fields, wheres='', returning=''): 143 """编辑单条数据库记录""" 144 if wheres: 145 wheres = self.__pk_name + ' = ' + str(pk) + ' and ' + wheres 146 else: 147 wheres = self.__pk_name + ' = ' + str(pk) 148 149 return self.edit_sql(fields, wheres, returning) 150 151 def delete_sql(self, wheres='', returning=''): 152 """ 153 批量删除数据库记录 154 :param wheres: 删除条件 155 :param returning: 删除成功后,返回的字段名 156 :param is_update_cache: 是否同步更新缓存 157 :return: 158 """ 159 # 如果存在条件 160 if wheres: 161 wheres = ' where ' + wheres 162 163 # 如果有指定返回参数,则添加 164 if returning: 165 returning = ', ' + returning 166 167 # 生成sql语句 168 sql = "delete from %(table_name)s %(wheres)s returning %(pk_name)s %(returning)s" % \ 169 {'table_name': self.__table_name, 'wheres': wheres, 'pk_name': self.__pk_name, 'returning': returning} 170 return sql 171 172 def delete_model_sql(self, pk, wheres='', returning=''): 173 """删除单条数据库记录""" 174 if wheres: 175 wheres = self.__pk_name + ' = ' + str(pk) + ' and ' + wheres 176 else: 177 wheres = self.__pk_name + ' = ' + str(pk) 178 179 return self.delete_sql(wheres, returning) 180 181 def get_list_sql(self, column_name_list='', wheres='', orderby=None, table_name=None): 182 """ 183 获取指定条件的数据库记录集 184 :param column_name_list: 查询字段 185 :param wheres: 查询条件 186 :param orderby: 排序规则 187 :param table_name: 查询数据表,多表查询时需要设置 188 :return: 189 """ 190 # 初始化查询数据表名称 191 if not table_name: 192 table_name = self.__table_name 193 # 初始化查询字段名 194 if not column_name_list: 195 column_name_list = self.__column_name_list 196 # 初始化查询条件 197 if wheres: 198 # 如果是字符串,表示该查询条件已组装好了,直接可以使用 199 if isinstance(wheres, str): 200 wheres = 'where ' + wheres 201 # 如果是list,则表示查询条件有多个,可以使用join将它们用and方式组合起来使用 202 elif isinstance(wheres, list): 203 wheres = 'where ' + ' and '.join(wheres) 204 # 初始化排序 205 if not orderby: 206 orderby = self.__pk_name + ' desc' 207 ############################################################# 208 209 ### 按条件查询数据库记录 210 sql = "select %(column_name_list)s from %(table_name)s %(wheres)s order by %(orderby)s " % \ 211 {'column_name_list': column_name_list, 212 'table_name': table_name, 213 'wheres': wheres, 214 'orderby': orderby} 215 return sql 216 217 def get_count_sql(self, wheres=''): 218 """获取指定条件记录数量""" 219 if wheres: 220 wheres = ' where ' + wheres 221 sql = 'select count(1) as total from %(table_name)s %(wheres)s ' % \ 222 {'table_name': self.__table_name, 'wheres': wheres} 223 return sql 224 225 def get_sum_sql(self, fields, wheres): 226 """获取指定条件记录数量""" 227 sql = 'select sum(%(fields)s) as total from %(table_name)s where %(wheres)s ' % \ 228 {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields} 229 return sql 230 231 def get_min_sql(self, fields, wheres): 232 """获取该列记录最小值""" 233 sql = 'select min(%(fields)s) as min from %(table_name)s where %(wheres)s ' % \ 234 {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields} 235 return sql 236 237 def get_max_sql(self, fields, wheres): 238 """获取该列记录最大值""" 239 sql = 'select max(%(fields)s) as max from %(table_name)s where %(wheres)s ' % \ 240 {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields} 241 return sql 242 243 ##################################################################### 244 245 246 ##################################################################### 247 ### 执行Sql ### 248 249 def select(self, sql): 250 """执行sql查询语句(select)""" 251 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db: 252 # 执行sql语句 253 result = db.execute(sql) 254 if not result: 255 result = [] 256 return result 257 258 def execute(self, sql): 259 """执行sql语句,并提交事务""" 260 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db: 261 # 执行sql语句 262 result = db.execute(sql) 263 if result: 264 db.commit() 265 else: 266 result = [] 267 return result 268 269 def copy(self, values, columns): 270 """批量更新数据""" 271 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db: 272 # 执行sql语句 273 result = db.copy(values, self.__table_name, columns) 274 return result 275 276 def get_model(self, wheres): 277 """通过条件获取一条记录""" 278 # 生成sql 279 sql = self.get_model_sql(wheres) 280 # 执行查询操作 281 result = self.select(sql) 282 if result: 283 return result[0] 284 return {} 285 286 def get_model_for_pk(self, pk, wheres=''): 287 """通过主键值获取数据库记录实体""" 288 if not pk: 289 return {} 290 # 生成sql 291 sql = self.get_model_for_pk_sql(pk, wheres) 292 # 执行查询操作 293 result = self.select(sql) 294 if result: 295 return result[0] 296 return {} 297 298 def get_value(self, column_name, wheres=''): 299 """ 300 获取指定条件的字段值————多于条记录时,只取第一条记录 301 :param column_name: 单个字段名,如:id 302 :param wheres: 查询条件 303 :return: 7 (指定的字段值) 304 """ 305 if not column_name: 306 return None 307 308 # 生成sql 309 sql = self.get_value_sql(column_name, wheres) 310 result = self.select(sql) 311 # 如果查询成功,则直接返回记录字典 312 if result: 313 return result[0].get(column_name) 314 315 def get_value_list(self, column_name, wheres=''): 316 """ 317 获取指定条件记录的字段值列表 318 :param column_name: 单个字段名,如:id 319 :param wheres: 查询条件 320 :return: [1,3,4,6,7] 321 """ 322 # 生成sql 323 sql = self.get_value_list_sql(column_name, wheres) 324 result = self.select(sql) 325 # 如果查询失败或不存在指定条件记录,则直接返回初始值 326 if result and isinstance(result, list): 327 return result[0].get('list') 328 else: 329 return [] 330 331 def add_model(self, fields, returning=''): 332 """新增数据库记录""" 333 # 生成sql 334 sql = self.add_model_sql(fields, returning) 335 result = self.execute(sql) 336 if result: 337 return result[0] 338 return {} 339 340 def edit(self, fields, wheres='', returning='', is_update_cache=True): 341 """ 342 批量编辑数据库记录 343 :param fields: 要更新的字段(字段名与值存储在字典中) 344 :param wheres: 更新条件 345 :param returning: 更新成功后,返回的字段名 346 :param is_update_cache: 是否同步更新缓存 347 :return: 348 """ 349 # 生成sql 350 sql = self.edit_sql(fields, wheres, returning) 351 result = self.execute(sql) 352 if result: 353 # 判断是否删除对应的缓存 354 if is_update_cache: 355 # 循环删除更新成功的所有记录对应的缓存 356 for model in result: 357 self.del_model_for_cache(model.get(self.__pk_name, 0)) 358 # 同步删除与本表关联的缓存 359 self.del_relevance_cache() 360 return result 361 362 def edit_model(self, pk, fields, wheres='', returning='', is_update_cache=True): 363 """编辑单条数据库记录""" 364 if not pk: 365 return {} 366 # 生成sql 367 sql = self.edit_model_sql(pk, fields, wheres, returning) 368 result = self.execute(sql) 369 if result: 370 # 判断是否删除对应的缓存 371 if is_update_cache: 372 # 删除更新成功的所有记录对应的缓存 373 self.del_model_for_cache(result[0].get(self.__pk_name, 0)) 374 # 同步删除与本表关联的缓存 375 self.del_relevance_cache() 376 return result 377 378 def delete(self, wheres='', returning='', is_update_cache=True): 379 """ 380 批量删除数据库记录 381 :param wheres: 删除条件 382 :param returning: 删除成功后,返回的字段名 383 :param is_update_cache: 是否同步更新缓存 384 :return: 385 """ 386 # 生成sql 387 sql = self.delete_sql(wheres, returning) 388 result = self.execute(sql) 389 if result: 390 # 同步删除对应的缓存 391 if is_update_cache: 392 for model in result: 393 self.del_model_for_cache(model.get(self.__pk_name, 0)) 394 # 同步删除与本表关联的缓存 395 self.del_relevance_cache() 396 return result 397 398 def delete_model(self, pk, wheres='', returning='', is_update_cache=True): 399 """删除单条数据库记录""" 400 if not pk: 401 return {} 402 # 生成sql 403 sql = self.delete_model_sql(pk, wheres, returning) 404 result = self.execute(sql) 405 if result: 406 # 同步删除对应的缓存 407 if is_update_cache: 408 self.del_model_for_cache(result[0].get(self.__pk_name, 0)) 409 # 同步删除与本表关联的缓存 410 self.del_relevance_cache() 411 return result 412 413 def get_list(self, column_name_list='', wheres='', page_number=None, page_size=None, orderby=None, table_name=None): 414 """ 415 获取指定条件的数据库记录集 416 :param column_name_list: 查询字段 417 :param wheres: 查询条件 418 :param page_number: 分页索引值 419 :param page_size: 分页大小, 存在值时才会执行分页 420 :param orderby: 排序规则 421 :param table_name: 查询数据表,多表查询时需要设置 422 :return: 返回记录集总数量与分页记录集 423 {'records': 0, 'total': 0, 'page': 0, 'rows': []} 424 """ 425 # 初始化输出参数:总记录数量与列表集 426 data = { 427 'records': 0, # 总记录数 428 'total': 0, # 总页数 429 'page': 1, # 当前页面索引 430 'rows': [], # 查询结果(记录列表) 431 } 432 # 初始化查询数据表名称 433 if not table_name: 434 table_name = self.__table_name 435 # 初始化查询字段名 436 if not column_name_list: 437 column_name_list = self.__column_name_list 438 # 初始化查询条件 439 if wheres: 440 # 如果是字符串,表示该查询条件已组装好了,直接可以使用 441 if isinstance(wheres, str): 442 wheres = 'where ' + wheres 443 # 如果是list,则表示查询条件有多个,可以使用join将它们用and方式组合起来使用 444 elif isinstance(wheres, list): 445 wheres = 'where ' + ' and '.join(wheres) 446 # 初始化排序 447 if not orderby: 448 orderby = self.__pk_name + ' desc' 449 # 初始化分页查询的记录区间 450 paging = '' 451 452 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db: 453 ############################################################# 454 # 判断是否需要进行分页 455 if not page_size is None: 456 ### 执行sql,获取指定条件的记录总数量 457 sql = 'select count(1) as records from %(table_name)s %(wheres)s ' % \ 458 {'table_name': table_name, 'wheres': wheres} 459 result = db.execute(sql) 460 # 如果查询失败或不存在指定条件记录,则直接返回初始值 461 if not result or result[0]['records'] == 0: 462 return data 463 464 # 设置记录总数量 465 data['records'] = result[0].get('records') 466 467 ######################################################### 468 ### 设置分页索引与页面大小 ### 469 if page_size <= 0: 470 page_size = 10 471 # 计算总分页数量:通过总记录数除于每页显示数量来计算总分页数量 472 if data['records'] % page_size == 0: 473 page_total = data['records'] // page_size 474 else: 475 page_total = data['records'] // page_size + 1 476 # 判断页码是否超出限制,超出限制查询时会出现异常,所以将页面索引设置为最后一页 477 if page_number < 1 or page_number > page_total: 478 page_number = page_total 479 # 记录总页面数量 480 data['total'] = page_total 481 # 记录当前页面值 482 data['page'] = page_number 483 # 计算当前页面要显示的记录起始位置(limit指定的位置) 484 record_number = (page_number - 1) * page_size 485 # 设置查询分页条件 486 paging = ' limit ' + str(page_size) + ' offset ' + str(record_number) 487 ############################################################# 488 489 ### 按条件查询数据库记录 490 sql = "select %(column_name_list)s from %(table_name)s %(wheres)s order by %(orderby)s %(paging)s" % \ 491 {'column_name_list': column_name_list, 492 'table_name': table_name, 493 'wheres': wheres, 494 'orderby': orderby, 495 'paging': paging} 496 result = db.execute(sql) 497 if result: 498 data['rows'] = result 499 # 不需要分页查询时,直接在这里设置总记录数 500 if page_size is None: 501 data['records'] = len(result) 502 503 return data 504 505 def get_count(self, wheres=''): 506 """获取指定条件记录数量""" 507 # 生成sql 508 sql = self.get_count_sql(wheres) 509 result = self.select(sql) 510 # 如果查询存在记录,则返回true 511 if result: 512 return result[0].get('total') 513 return 0 514 515 def get_sum(self, fields, wheres): 516 """获取指定条件记录数量""" 517 # 生成sql 518 sql = self.get_sum_sql(fields, wheres) 519 result = self.select(sql) 520 # 如果查询存在记录,则返回true 521 if result and result[0].get('total'): 522 return result[0].get('total') 523 return 0 524 525 def get_min(self, fields, wheres): 526 """获取该列记录最小值""" 527 # 生成sql 528 sql = self.get_min_sql(fields, wheres) 529 result = self.select(sql) 530 # 如果查询存在记录,则返回true 531 if result and result[0].get('min'): 532 return result[0].get('min') 533 534 def get_max(self, fields, wheres): 535 """获取该列记录最大值""" 536 # 生成sql 537 sql = self.get_max_sql(fields, wheres) 538 result = self.select(sql) 539 # 如果查询存在记录,则返回true 540 if result and result[0].get('max'): 541 return result[0].get('max') 542 543 ##################################################################### 544 545 546 ##################################################################### 547 ### 缓存操作方法 ### 548 549 def get_cache_key(self, pk): 550 """获取缓存key值""" 551 return ''.join((self.__table_name, '_', str(pk))) 552 553 def set_model_for_cache(self, pk, value, time=43200): 554 """更新存储在缓存中的数据库记录,缓存过期时间为12小时""" 555 # 生成缓存key 556 key = self.get_cache_key(pk) 557 # 存储到nosql缓存中 558 cache_helper.set(key, value, time) 559 560 def get_model_for_cache(self, pk): 561 """从缓存中读取数据库记录""" 562 # 生成缓存key 563 key = self.get_cache_key(pk) 564 # 从缓存中读取数据库记录 565 result = cache_helper.get(key) 566 # 缓存中不存在记录,则从数据库获取 567 if not result: 568 result = self.get_model_for_pk(pk) 569 self.set_model_for_cache(pk, result) 570 if result: 571 return result 572 else: 573 return {} 574 575 def get_model_for_cache_of_where(self, where): 576 """ 577 通过条件获取记录实体(我们经常需要使用key、编码或指定条件来获取记录,这时可以通过当前方法来获取) 578 :param where: 查询条件 579 :return: 记录实体 580 """ 581 # 生成实体缓存key 582 model_cache_key = self.__table_name + encrypt_helper.md5(where) 583 # 通过条件从缓存中获取记录id 584 pk = cache_helper.get(model_cache_key) 585 # 如果主键id存在,则直接从缓存中读取记录 586 if pk: 587 return self.get_model_for_cache(pk) 588 589 # 否则从数据库中获取 590 result = self.get_model(where) 591 if result: 592 # 存储条件对应的主键id值到缓存中 593 cache_helper.set(model_cache_key, result.get(self.__pk_name)) 594 # 存储记录实体到缓存中 595 self.set_model_for_cache(result.get(self.__pk_name), result) 596 return result 597 598 def get_value_for_cache(self, pk, column_name): 599 """获取指定记录的字段值""" 600 return self.get_model_for_cache(pk).get(column_name) 601 602 def del_model_for_cache(self, pk): 603 """删除缓存中指定数据""" 604 # 生成缓存key 605 key = self.get_cache_key(pk) 606 # log_helper.info(key) 607 # 存储到nosql缓存中 608 cache_helper.delete(key) 609 610 def add_relevance_cache_in_list(self, key): 611 """将缓存名称存储到列表里————主要存储与记录变更关联的""" 612 # 从nosql中读取全局缓存列表 613 cache_list = cache_helper.get(self.__cache_list) 614 # 判断缓存列表是否有值,有则进行添加操作 615 if cache_list: 616 # 判断是否已存储列表中,不存在则执行添加操作 617 if not key in cache_list: 618 cache_list.append(key) 619 cache_helper.set(self.__cache_list, cache_list) 620 # 无则直接创建全局缓存列表,并存储到nosql中 621 else: 622 cache_list = [key] 623 cache_helper.set(self.__cache_list, cache_list) 624 625 def del_relevance_cache(self): 626 """删除关联缓存————将和数据表记录关联的,个性化缓存全部删除""" 627 # 从nosql中读取全局缓存列表 628 cache_list = cache_helper.get(self.__cache_list) 629 # 清除已删除缓存列表 630 cache_helper.delete(self.__cache_list) 631 if cache_list: 632 # 执行删除操作 633 for cache in cache_list: 634 cache_helper.delete(cache) 635 636 #####################################################################
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表操作类ProductLogic 30 _product_logic = product_logic.ProductLogic() 31 # 实例化product_class表操作类product_class_logic 32 _product_class_logic = product_class_logic.ProductClassLogic() 33 # 初始化产品分类主键id 34 id = 1 35 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 return 44 print('----产品分类实体----') 45 print(result) 46 print('-------------------') 47 48 # 禁用产品分类 49 fields = { 50 'is_enable': 0 51 } 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 return 61 # 执行缓存清除操作 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 return 78 # 执行缓存清除操作 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_enable 11 ----执行成功后的产品实体---- 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 本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。
python开发QQ群:669058475 作者博客:http://www.cnblogs.com/EmptyFS/