個人第一個python web開發框架(32)——定製ORM(八)

  寫到這裏,基本的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     #####################################################################
View Code

  從完整代碼能夠看到,重構後的類多了不少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/

相關文章
相關標籤/搜索