寫到這裏,基本的ORM功能就完成了,不知你們有沒有發現,這個ORM每一個方法都是在with中執行的,也就是說每一個方法都是一個完整的事務,當它執行完成之後也會將事務提交,那麼若是咱們想要進行一個複雜的事務時,它並不能作到,因此咱們還須要對它進行改造,讓它支持sql事務。python
那麼應該怎麼實現呢?咱們都知道要支持事務,就必須讓不一樣的sql語句在同一個事務中執行,也就是說,咱們須要在一個with中執行全部的sql語句,失敗則回滾,成功再提交事務。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組合,一個執行獲取結果,前者能夠給事務調用,後者直接給對應的程序調用app
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 {}
其餘代碼不一一細述,你們本身看看重構後的結果nosql
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 #####################################################################
從完整代碼能夠看到,重構後的類多了不少sql生成方法,它們實際上是從原方法中分享出sql合成代碼,將它們獨立出來而已。ide
接下來咱們編寫單元測試代碼,執行一下事務看看效果單元測試
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(本羣已滿)、733466321(能夠加2羣) 做者博客:http://www.cnblogs.com/EmptyFS/