95992828九五至尊2

九五至尊1老品牌值得关于服务器缓存的合计。我的第一个python web开发框架(31)——定制ORM(七)

九月 5th, 2018  |  九五至尊1老品牌值得

  我们于开被,经常会面就此到各种缓存,比如Session、Application、HttpRuntime.Cache、Redis、Memcached、MongoDB、Riak等。而貌似项目中使缓存时,都是于初级的,大多还是广阔的Key-Value方式,通过依赖、时间、同步创新或直接去方法来治本缓存的过期。当然网上对缓存的牵线绝大部分且是立即上面的,而于一连串缓存、缓存与缓存相互关系、表记录和大多缓存关联、后端缓存与前者页面缓存关联、缓存名称动态变化的缓存与其余缓存联动处理、频繁更新的缓存与外缓存联动问题……等等不同情况下该要去管理这些缓存的知识点,我当园里找找了大体上上呢无看出……而多年来自己支付的型受到尽管遇到了缓存管理及的问题,所以犯就篇贴子同大家讨论一下有什么还好之缓解方案。

  几独复杂的ORM方式还已介绍完了,剩下有常用之去、获取记录数据、统计合计数、获取最老价值、获取最小值等办法本身虽不一一详细介绍了,直接吃来代码大家自行查看。

 

九五至尊1老品牌值得 1九五至尊1老品牌值得 2

  随着项目参与人员数量之充实,大家更的不等以及针对缓存的咀嚼不同等,而项目以达成在养条件达标可知处理又特别的出现和良好的习性,缓存的利用也愈加普遍了。项目于老板、运营单位与项目经理的推波助澜产,新力量、新需要不止的推陈出新,代码和复杂度也几乎何级的爆增起来,缓存的使几乎充斥在备代码的调用当中,由于尚未特意写一个甩卖插件对其进行联合保管,造成缓存管理起有点糊涂。

  1 #!/usr/bin/env python
  2 # coding=utf-8
  3 
  4 from common import db_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     #####################################################################
 24     ### 执行Sql ###
 25 
 26     def select(self, sql):
 27         """执行sql查询语句(select)"""
 28         with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
 29             # 执行sql语句
 30             result = db.execute(sql)
 31             if not result:
 32                 result = []
 33         return result
 34 
 35     def execute(self, sql):
 36         """执行sql语句,并提交事务"""
 37         with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
 38             # 执行sql语句
 39             result = db.execute(sql)
 40             if result:
 41                 db.commit()
 42             else:
 43                 result = []
 44         return result
 45 
 46     def copy(self, values, columns):
 47         """批量更新数据"""
 48         with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
 49             # 执行sql语句
 50             result = db.copy(values, self.__table_name, columns)
 51         return result
 52 
 53     def get_model(self, wheres):
 54         """通过条件获取一条记录"""
 55         # 如果有条件,则自动添加where
 56         if wheres:
 57             wheres = ' where ' + wheres
 58 
 59         # 合成sql语句
 60         sql = "select %(column_name_list)s from %(table_name)s %(wheres)s" % \
 61               {'column_name_list': self.__column_name_list, 'table_name': self.__table_name, 'wheres': wheres}
 62         # 初化化数据库链接
 63         result = self.select(sql)
 64         if result:
 65             return result[0]
 66         return {}
 67 
 68     def get_model_for_pk(self, pk, wheres=''):
 69         """通过主键值获取数据库记录实体"""
 70         if not pk:
 71             return {}
 72         # 组装查询条件
 73         wheres = '%s = %s' % (self.__pk_name, str(pk))
 74 
 75         return self.get_model(wheres)
 76 
 77     def get_value(self, column_name, wheres=''):
 78         """
 79         获取指定条件的字段值————多于条记录时,只取第一条记录
 80         :param column_name: 单个字段名,如:id
 81         :param wheres: 查询条件
 82         :return: 7 (指定的字段值)
 83         """
 84         if not column_name:
 85             return None
 86         elif wheres:
 87             wheres = ' where ' + wheres
 88 
 89         sql = 'select %(column_name)s from %(table_name)s %(wheres)s limit 1' % \
 90               {'column_name': column_name, 'table_name': self.__table_name, 'wheres': wheres}
 91         result = self.select(sql)
 92         # 如果查询成功,则直接返回记录字典
 93         if result:
 94             return result[0].get(column_name)
 95 
 96     def get_value_list(self, column_name, wheres=''):
 97         """
 98         获取指定条件记录的字段值列表
 99         :param column_name: 单个字段名,如:id
100         :param wheres: 查询条件
101         :return: [1,3,4,6,7]
102         """
103         if not column_name:
104             column_name = self.__pk_name
105         elif wheres:
106             wheres = ' where ' + wheres
107 
108         sql = 'select array_agg(%(column_name)s) as list from %(table_name)s %(wheres)s' % \
109               {'column_name': column_name, 'table_name': self.__table_name, 'wheres': wheres}
110         result = self.select(sql)
111         # 如果查询失败或不存在指定条件记录,则直接返回初始值
112         if result and isinstance(result, list):
113             return result[0].get('list')
114         else:
115             return []
116 
117     def add_model(self, fields, returning=''):
118         """新增数据库记录"""
119         ### 拼接sql语句 ###
120         # 初始化变量
121         key_list = []
122         value_list = []
123         # 将传入的字典参数进行处理,把字段名生成sql插入字段名数组和字典替换数组
124         # PS:字符串使用字典替换参数时,格式是%(name)s,这里会生成对应的字串
125         # 比如:
126         #   传入的字典为: {'id': 1, 'name': '名称'}
127         #   那么生成的key_list为:'id','name'
128         #   而value_list为:'%(id)s,%(name)s'
129         #   最终而value_list为字符串对应名称位置会被替换成相应的值
130         for key in fields.keys():
131             key_list.append(key)
132             value_list.append('%(' + key + ')s')
133         # 设置sql拼接字典,并将数组(lit)使用join方式进行拼接,生成用逗号分隔的字符串
134         parameter = {
135             'table_name': self.__table_name,
136             'pk_name': self.__pk_name,
137             'key_list': ','.join(key_list),
138             'value_list': ','.join(value_list)
139         }
140         # 如果有指定返回参数,则添加
141         if returning:
142             parameter['returning'] = ', ' + returning
143         else:
144             parameter['returning'] = ''
145 
146         # 生成可以使用字典替换的字符串
147         sql = "insert into %(table_name)s (%(key_list)s) values (%(value_list)s) returning %(pk_name)s %(returning)s" % parameter
148         # 将生成好的字符串替字典参数值,生成最终可执行的sql语句
149         sql = sql % fields
150 
151         result = self.execute(sql)
152         if result:
153             return result[0]
154         return {}
155 
156     def edit(self, fields, wheres='', returning=''):
157         """批量编辑数据库记录"""
158         ### 拼接sql语句 ###
159         # 拼接字段与值
160         field_list = [key + ' = %(' + key + ')s' for key in fields.keys()]
161         # 设置sql拼接字典
162         parameter = {
163             'table_name': self.__table_name,
164             'pk_name': self.__pk_name,
165             'field_list': ','.join(field_list)
166         }
167         # 如果存在更新条件,则将条件添加到sql拼接更换字典中
168         if wheres:
169             parameter['wheres'] = ' where ' + wheres
170         else:
171             parameter['wheres'] = ''
172 
173         # 如果有指定返回参数,则添加
174         if returning:
175             parameter['returning'] = ', ' + returning
176         else:
177             parameter['returning'] = ''
178 
179         # 生成sql语句
180         sql = "update %(table_name)s set %(field_list)s %(wheres)s returning %(pk_name)s %(returning)s" % parameter
181         sql = sql % fields
182 
183         return self.execute(sql)
184 
185     def edit_model(self, pk, fields, wheres='', returning=''):
186         """编辑单条数据库记录"""
187         if not pk:
188             return {}
189         elif wheres:
190             wheres = self.__pk_name + ' = ' + str(pk) + ' and ' + wheres
191         else:
192             wheres = self.__pk_name + ' = ' + str(pk)
193 
194         return self.edit(fields, wheres, returning)
195 
196     def delete(self, wheres='', returning='', is_update_cache=True):
197         """批量删除数据库记录"""
198         # 如果存在条件
199         if wheres:
200             wheres = ' where ' + wheres
201 
202         # 如果有指定返回参数,则添加
203         if returning:
204             returning = ', ' + returning
205 
206         # 生成sql语句
207         sql = "delete from %(table_name)s %(wheres)s returning %(pk_name)s %(returning)s" % \
208               {'table_name': self.__table_name, 'wheres': wheres, 'pk_name': self.__pk_name, 'returning': returning}
209         return self.execute(sql)
210 
211     def delete_model(self, pk, wheres='', returning='', is_update_cache=True):
212         """删除单条数据库记录"""
213         if not pk:
214             return {}
215         elif wheres:
216             wheres = self.__pk_name + ' = ' + str(pk) + ' and ' + wheres
217         else:
218             wheres = self.__pk_name + ' = ' + str(pk)
219 
220         return self.delete(wheres, returning)
221 
222     def get_list(self, column_name_list='', wheres='', page_number=None, page_size=None, orderby=None, table_name=None):
223         """
224         获取指定条件的数据库记录集
225         :param column_name_list:      查询字段
226         :param wheres:      查询条件
227         :param page_number:   分页索引值
228         :param page_size:    分页大小, 存在值时才会执行分页
229         :param orderby:     排序规则
230         :param table_name:     查询数据表,多表查询时需要设置
231         :return: 返回记录集总数量与分页记录集
232             {'records': 0, 'total': 0, 'page': 0, 'rows': []}
233         """
234         # 初始化输出参数:总记录数量与列表集
235         data = {
236             'records': 0,  # 总记录数
237             'total': 0,  # 总页数
238             'page': 1,  # 当前页面索引
239             'rows': [],  # 查询结果(记录列表)
240         }
241         # 初始化查询数据表名称
242         if not table_name:
243             table_name = self.__table_name
244         # 初始化查询字段名
245         if not column_name_list:
246             column_name_list = self.__column_name_list
247         # 初始化查询条件
248         if wheres:
249             # 如果是字符串,表示该查询条件已组装好了,直接可以使用
250             if isinstance(wheres, str):
251                 wheres = 'where ' + wheres
252             # 如果是list,则表示查询条件有多个,可以使用join将它们用and方式组合起来使用
253             elif isinstance(wheres, list):
254                 wheres = 'where ' + ' and '.join(wheres)
255         # 初始化排序
256         if not orderby:
257             orderby = self.__pk_name + ' desc'
258         # 初始化分页查询的记录区间
259         paging = ''
260 
261         with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
262             #############################################################
263             # 判断是否需要进行分页
264             if not page_size is None:
265                 ### 执行sql,获取指定条件的记录总数量
266                 sql = 'select count(1) as records from %(table_name)s %(wheres)s ' % \
267                       {'table_name': table_name, 'wheres': wheres}
268                 result = db.execute(sql)
269                 # 如果查询失败或不存在指定条件记录,则直接返回初始值
270                 if not result or result[0]['records'] == 0:
271                     return data
272 
273                 # 设置记录总数量
274                 data['records'] = result[0].get('records')
275 
276                 #########################################################
277                 ### 设置分页索引与页面大小 ###
278                 if page_size <= 0:
279                     page_size = 10
280                 # 计算总分页数量:通过总记录数除于每页显示数量来计算总分页数量
281                 if data['records'] % page_size == 0:
282                     page_total = data['records'] // page_size
283                 else:
284                     page_total = data['records'] // page_size + 1
285                 # 判断页码是否超出限制,超出限制查询时会出现异常,所以将页面索引设置为最后一页
286                 if page_number < 1 or page_number > page_total:
287                     page_number = page_total
288                 # 记录总页面数量
289                 data['total'] = page_total
290                 # 记录当前页面值
291                 data['page'] = page_number
292                 # 计算当前页面要显示的记录起始位置(limit指定的位置)
293                 record_number = (page_number - 1) * page_size
294                 # 设置查询分页条件
295                 paging = ' limit ' + str(page_size) + ' offset ' + str(record_number)
296             #############################################################
297 
298             ### 按条件查询数据库记录
299             sql = "select %(column_name_list)s from %(table_name)s %(wheres)s order by %(orderby)s %(paging)s" % \
300                   {'column_name_list': column_name_list,
301                    'table_name': table_name,
302                    'wheres': wheres,
303                    'orderby': orderby,
304                    'paging': paging}
305             result = db.execute(sql)
306             if result:
307                 data['rows'] = result
308                 # 不需要分页查询时,直接在这里设置总记录数
309                 if page_size is None:
310                     data['records'] = len(result)
311 
312         return data
313 
314     def get_count(self, wheres=''):
315         """获取指定条件记录数量"""
316         if wheres:
317             wheres = ' where ' + wheres
318         sql = 'select count(1) as total from %(table_name)s %(wheres)s ' % \
319               {'table_name': self.__table_name, 'wheres': wheres}
320         result = self.select(sql)
321         # 如果查询存在记录,则返回true
322         if result:
323             return result[0].get('total')
324         return 0
325 
326     def get_sum(self, fields, wheres):
327         """获取指定条件记录数量"""
328         sql = 'select sum(%(fields)s) as total from %(table_name)s where %(wheres)s ' % \
329               {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}
330         result = self.select(sql)
331         # 如果查询存在记录,则返回true
332         if result and result[0].get('total'):
333             return result[0].get('total')
334         return 0
335 
336     def get_min(self, fields, wheres):
337         """获取该列记录最小值"""
338         sql = 'select min(%(fields)s) as min from %(table_name)s where %(wheres)s ' % \
339               {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}
340         result = self.select(sql)
341         # 如果查询存在记录,则返回true
342         if result and result[0].get('min'):
343             return result[0].get('min')
344 
345     def get_max(self, fields, wheres):
346         """获取该列记录最大值"""
347         sql = 'select max(%(fields)s) as max from %(table_name)s where %(wheres)s ' % \
348               {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}
349         result = self.select(sql)
350         # 如果查询存在记录,则返回true
351         if result and result[0].get('max'):
352             return result[0].get('max')
353 
354             #####################################################################

  比如针对运行中之系于一些情况下实施了清空全部缓存时,偶尔会发出局部有些坏(有些数据读取不正规);对同结果重复使用缓存(A同事创建了一个缓存来存储H任务尽结果的,而B同事不知道A同事创办了,也创了一个),浪费内存空间;多单缓存依赖与一个缓存值的变更,某些人是因为有需改了所依靠缓存的名号与所影响的片缓存时,个别无自己编辑的缓存没有拍卖及要忘记处理了;某些缓存存储内容因临时表来创造的,缓存名称有规律而不稳定,而另外有缓存的始末是基于这些缓存来计算的,当这些缓存更新时怎样能够活动同步所依赖它的缓存……

View Code

  当然者这些情况要还发生另的气象单独编制代码来拍卖肯定得兑现,只待花费多一些岁月而已,问题是如系统很巨大后,充斥差各种交叉关联的缓存时,它们曾像蜘蛛网一样,动一发而带来全身,写这些处理代码一个从未有过考虑好就会影响到任何情节。况且有诸多下更新临时表记录时,有些缓存名称是勿稳定的(根据一些规则关联到任何表记录或日期等办法转变的复苏存名称),代码并无可能智能识别而一并更新那些缓存。所以编写一个无敌的自动化缓存处理插件也势在必行了。

 

  相信博客园团队以及另部分大型的网站都有所好一样仿到的缓存管理方,由于自己知识广度还非敷,暂时无于网上发现发生相同效完善、高效之化解方案可以借鉴,只好自己来纪念办法化解,所以先丢来一致块砖头,看能否引来一堆积美台了,嘿嘿…

  大家如果掌握了ORM简单的成sql方法,就可以自由发挥,根据自己之用去创造不同的办法了,也得擅自变换mysql、mssql等数据库。

 

  当然,这只是无与伦比简便的ORM方式,提交字段参数和准参数时,它不会见自行识别字段的品类,不会见自动初始化默认值,如果想吃其换的尤其强有力,还得举行更多之改造以及处理,这样做的语句它呢会随之变的更错综复杂和难懂,性能也会就下跌。不过当下效应于绝大多数列以来,已经足够使用了。大家要来要可以活动钻研进展扩展。

  下面我们先来打探一下缓存中的组成部分分类以及名词说明

 

  按名的命名可分为:

  以平常操作着,获取指定记录实体是无与伦比广泛使用最累之操作,为了减少针对数据库的询问,我们好拿ORM与Nosql结合起来,提升ORM的操作性能,当然如果你无思使用nosql缓存,也可以直接跨越了本章节。

  固定名称:通常为表名、字段名、功能名称、前几项的结合……等照每位的喜欢好来进展命名,调用时也直接惠及

  使用Nosql,首先我们用一个链接Nosql的部署文件,用它们来储存Nosql的劳务地方、端口、密码等参数

  有定点前缀(单个或多个可换后缀或只是易后缀+固定后缀组合等):表名+记录Id、临时表名(表名按自然规则进行更改,比如后缀为日、关联表的Id等)、功能名称+编码……调用时要动态传入指定的参数,在未晓得参数的事态下无法对拖欠缓存进行操作

  于config文件夹着我们创建redis_config.py配置文件

 

#!/usr/bin/env python
# coding=utf-8

### redis缓存配置参数 ###
REDIS = {
    # 服务地址
    'server': '127.0.0.1',
    # 服务端口
    'post': 6379,
    # 服务密码
    'pwd': '',
    # 数据库序号
    'db': 1
}

  按缓存依赖内容可分为:

  然后我们还欲一个nosql链接工具包(cache_helper.py),用来对nosql进行set、get、delete和clear操作(存储、获取、删除和清空缓存)

  依赖指定表:指定表记录多、修改、删除、更新时,需要一起更新该缓存内容

九五至尊1老品牌值得 3九五至尊1老品牌值得 4

  依赖指定表中的一些或某某条记下:同齐

  1 #!/usr/bin/env python
  2 # coding=utf-8
  3 
  4 import redis
  5 
  6 from common import log_helper
  7 from config import redis_config
  8 
  9 # 设置redis配置参数
 10 _redis = redis_config.REDIS
 11 # 初始化Redis缓存链接
 12 r = None
 13 try:
 14     if not r:
 15         r = redis.Redis(host=_redis.get('server', ''),
 16                         port=_redis.get('post', ''),
 17                         db=_redis.get('db', ''),
 18                         password=_redis.get('pwd', ''),
 19                         socket_timeout=1,
 20                         socket_connect_timeout=1)
 21 except Exception as e:
 22     log_helper.info('连接redis出错:(' + str(_redis) + ')' + str(e.args))
 23     pass
 24 
 25 
 26 def set(key, value, time=86400):
 27     """
 28     写缓存
 29     :param key: 缓存key,字符串,不区分大小写
 30     :param value: 要存储的值
 31     :param time: 缓存过期时间(单位:秒),0=永不过期
 32     :return:
 33     """
 34     # 将key转换为小写字母
 35     key = str(key).lower()
 36     try:
 37         r.set(key, value, time)
 38     except Exception as e:
 39         log_helper.info('写缓存失败:key(' + key + ')' + str(e.args))
 40         pass
 41 
 42 
 43 def get(key):
 44     """
 45     读缓存
 46     :param key: 缓存key,字符串,不区分大小写
 47     :return:
 48     """
 49     # 将key转换为小写字母
 50     key = str(key).lower()
 51     try:
 52         value = r.get(key)
 53     except Exception as e:
 54         # log_helper.error('读缓存失败:key(' + key + ')' + str(e.args) + ' r:' + str(r) + ' _redis:' + str(_redis))
 55         value = None
 56 
 57     return _str_to_json(value)
 58 
 59 
 60 def push(key, value):
 61     """
 62     添加数据到队列头部
 63     :param key: 缓存key,字符串,不区分大小写
 64     :param value: 要存储的值
 65     """
 66     # 将key转换为小写字母
 67     key = str(key).lower()
 68     try:
 69         r.lpush(key, value)
 70     except Exception as e:
 71         log_helper.info('写缓存失败:key(' + key + ')' + str(e.args))
 72         pass
 73 
 74 
 75 def pop(key):
 76     """
 77     从缓存队列的后尾读取一条数据
 78     :param key: 缓存key,字符串,不区分大小写
 79     :return: 缓存数据
 80     """
 81     # 将key转换为小写字母
 82     key = str(key).lower()
 83     try:
 84         value = r.rpop(key)
 85     except Exception as e:
 86         log_helper.info('读取缓存队列失败:key(' + key + ')' + str(e.args))
 87         value = None
 88 
 89     return _str_to_json(value)
 90 
 91 
 92 def _str_to_json(value):
 93     """
 94     将缓存中读取出来的字符串转换成对应的数据、元组、列表或字典
 95     """
 96     if not value:
 97         return value
 98     # 否则直接转换
 99     try:
100         value = value.decode()
101         return eval(value)
102     except Exception as e:
103         print(e.args)
104         pass
105     # 否则直接输出字符串
106     return value
107 
108 
109 def delete(key):
110     """
111     删除缓存
112     :param key:缓存key,字符串,不区分大小写
113     :return:
114     """
115     # 将key转换为小写字母
116     key = str(key).lower()
117     try:
118         log_helper.info(str(r.delete(key)))
119     except Exception as e:
120         log_helper.info('Exception:' + str(e.args))
121         pass
122 
123 
124 def clear():
125     """
126     清空所有缓存
127     """
128     try:
129         r.flushdb()
130     except:
131         pass

  依赖多只说明数据:同齐

View Code

  依赖指定字段值:默字段值改变时,同步修改(主要用于创新频率比较高的字段,比如页面点击计数等,如果要用到缓存的,需要单独出来存储,以免更新时实行一起清除功能)

  我常用的凡redis,所以用cache_helper.py时,需要装redis服务和呼应的Python包。如果您利用的是memcache,你就需要重构一下cache_helper.py代码就可了。

  依赖其他缓存:指定缓存值改动时,需要联合修改所倚它的任何缓存值(比如借助某些计算结果还是状态值;存储某些临时记录等)

  接下我们改造一下逻辑层基类(ORM模块)

  ……

  首先我们用导入cache_helper

 

from common import db_helper, cache_helper

  按影响缓存值的操作而分为:

  于使nosql缓存时,大家都知晓我们是采取key来进行对象存取的,而此key也是绝无仅有的,所以key的生成就很重点的,为了避免key的再度,我们在针对记录设置key时,可以据此表名+主键id的办法来做key,当然为调用方便,可以以收获key写成一个术来变化

  数据表记录的长、修改、删除;其他缓存值的翻新变更;某些计算结果的转等

    def get_cache_key(self, pk):
        """获取缓存key值"""
        return ''.join((self.__table_name, '_', str(pk)))

  对于所据的情变更后,相关缓存就需同更新,这样以可分为实时同步和延时同等方式

  这里运用join的章程,将表名、下横线、主键值组合生成缓存key字符串

  缓存更新策略通过发:实时更新(主要针对记录级别缓存,直接同步创新指定记录;当然为足以整表更新,但这么针对性程序执行性能有较充分之震慑)、超时检测(比如缓存依赖其他缓存时,设置一个末更新时间及博时间,通过比较简单单时刻来规定缓存是否过)、绝对时间过(为缓存设定过日子)、动态时间过(缓存被聘后过时推迟)等。

 

 

  对于缓存的操作,主要有安缓存、获取缓存、删除缓存这三种植操作,当然为好我们收获记录着指定字段值,我们可增加读取指定字段值方法。

  按缓存数据集合大小分:

  首先是安装缓存方法,大家省下面代码,它非常简单,先调用生成缓存key,然后将对象存储到缓存中,并指定过期时,当装time为0时,它用绝不过期

  单值、单条记下、小型数据集合、中型数据集合、大型数据集合、超大型数据集合

    def set_model_for_cache(self, pk, value, time=43200):
        """更新存储在缓存中的数据库记录,缓存过期时间为12小时"""
        # 生成缓存key
        key = self.get_cache_key(pk)
        # 存储到nosql缓存中
        cache_helper.set(key, value, time)

  对于缓存管理,数据集越小则存取与易速度更是快,所以当数码集合了怪时,就必须开展剪切,将聚合尽量分成小片,提升缓存使用性能

 

 

  接着是赢得缓存对象方法

  按缓存更新频率分:

    def get_model_for_cache(self, pk):
        """从缓存中读取数据库记录"""
        # 生成缓存key
        key = self.get_cache_key(pk)
        # 从缓存中读取数据库记录
        result = cache_helper.get(key)
        # 缓存中不存在记录,则从数据库获取
        if not result:
            result = self.get_model_for_pk(pk)
            self.set_model_for_cache(pk, result)
        if result:
            return result
        else:
            return {}

  固定值(指的是一些配置信息,存储进缓存后她的价值就是不再变化)、偶尔更新、经常更新、频繁更新

  我们首先使召开的一模一样是颇成缓存key,然后调用get方法从缓存中读取对象,执行了晚,需要看清该对象是不是有缓存中,如果未设有则意味着该目标没存储到缓存中或她可能存储过期了,所以需要重打数据库被读取出来,并拿其存储到缓存中,然后将读取出来的记录实体返回下。

 

 

  按缓存级别划分:

  然后我们还多一个读取指定记录字段值的不二法门

  无分级缓存、二级缓存

    def get_value_for_cache(self, pk, column_name):
        """获取指定记录的字段值"""
        return self.get_model_for_cache(pk).get(column_name)

 

  它一直调用获取缓存对象方法,然后打返回的对象吃读取指定的配段值就可以了

  其他:

 

  数据缓存、页面缓存……

  删除缓存方法呢酷粗略,生成缓存key后,直接调用delete进行去。对于删除方法,有时候调用不知是不是nosql自身bug问题,还是在主从关系的nosql中读写分离会招删除失败,如果起这种状态,可以以delete改吗set,将欠缓存set为空就得化解之问题

 

    def del_model_for_cache(self, pk):
        """删除缓存中指定数据"""
        # 生成缓存key
        key = self.get_cache_key(pk)
        # log_helper.info(key)
        # 存储到nosql缓存中
        cache_helper.delete(key)

  一般的话,大部分人数利用缓存还是一直key-value,这样种操作简单方便,无需太多之算法去处理。而如此操作对于记录集合比较老的数额(当然不克一直缓存大型或者超大型数据)来说,频繁之拓展多少存取转换为会消耗过多资源,所以有时需要以斯基础及又加个二级缓存,将NOSQL缓存中读取出来的多少载入IIS缓存中,程序直接编写代码调用,只有相关值更改时再重加载一次于,这样就算减少了针对异常数据易的性能损耗,当然程序的复杂度就大大升级了不少。

  PS:在使用缓存操作时,有时我们一直指向数据库进行操作,就见面招数据和缓存不匹配,出现浑浊数据的状,这时在后台增加清空缓存的操作,直接调用cache_helper.clear()进行清空缓存。

  对于下二级缓存或据其他缓存的缓存来说,经常更新或数更新影响是最为充分之,程序写的不得了直接会晤造成性能几哪里级的狂跌(因为各个一样潮创新都亟待一块更新相关的有缓存)。

 

 

  基本办法还形成了,接下便只要指向ORM的删减与修改章程开展改造了,让其活动根据需要对缓存进行对应操作,让缓存与数量表中的笔录保持一致。

  时系统以缓存状况

  以改造时,我们只需要针对勾与改操作进行拍卖,对新增及查询操作不待操作,因为新增的笔录,它并于缓存中连无存,所以无待开展操作,而查询也非会见改变多少内容,只有进行去和改操作时,才见面改数据内容,这时便待变更缓存,让数据保持一致。

  时自我的框架下的是二级缓存,首先是使Redis缓存存储各种表记录以及价值,然后于一些数据量不略,修改不多只是利用相对较频繁的数码,为了减少从Redis缓存中不停止的读取出来后展开反序列化操作,会从Redis缓存中读取出来后以它存储到IIS缓存中,当这些数量产生更新时会见实时同步创新IIS缓存中之数额,这些代码都封闭装于逻辑层中,统一运用模板生成,方便快捷。

  改造编辑记录实体方法

  将工作数据量大之模块进行了分,每天以不同属性生成N个临时表,第二龙凌晨会履定时任务将对准这些临时表进行剖析处理,去除无效数据后联合更新到历史表中(历史表明按月度转移)。业务数据分割后,每个表底记录量都怪少,它们还见面蕴藏到对应的苏存着受前后端、服务、Socket等接口进行共同调用处理,目前是殊服务器所有功能共用一个缓存服务。各种系统服务会将常用的数额要记录存储到指定的休息存着,减少逾临时表查询操作还是全表数据查询操作。有些效益就利用当天若是为此到的部分新颖数据,旧数据不再动用不需要与查询,也会用单独的缓存来进行仓储,缓存存储按一定前缀+有平整之后缀进行管制。

 1     def edit(self, fields, wheres='', returning='', is_update_cache=True):
 2         """
 3         批量编辑数据库记录
 4         :param fields: 要更新的字段(字段名与值存储在字典中)
 5         :param wheres: 更新条件
 6         :param returning: 更新成功后,返回的字段名
 7         :param is_update_cache: 是否同步更新缓存
 8         :return:
 9         """
10         ### 拼接sql语句 ###
11         # 拼接字段与值
12         field_list = [key + ' = %(' + key + ')s' for key in fields.keys()]
13         # 设置sql拼接字典
14         parameter = {
15             'table_name': self.__table_name,
16             'pk_name': self.__pk_name,
17             'field_list': ','.join(field_list)
18         }
19         # 如果存在更新条件,则将条件添加到sql拼接更换字典中
20         if wheres:
21             parameter['wheres'] = ' where ' + wheres
22         else:
23             parameter['wheres'] = ''
24 
25         # 如果有指定返回参数,则添加
26         if returning:
27             parameter['returning'] = ', ' + returning
28         else:
29             parameter['returning'] = ''
30 
31         # 生成sql语句
32         sql = "update %(table_name)s set %(field_list)s %(wheres)s returning %(pk_name)s %(returning)s" % parameter
33         sql = sql % fields
34 
35         result = self.execute(sql)
36         if result:
37             # 判断是否删除对应的缓存
38             if is_update_cache:
39                 # 循环删除更新成功的所有记录对应的缓存
40                 for model in result:
41                     self.del_model_for_cache(model.get('id', 0))
42         return result

  前端页面则直缓存在Redis中。

  大家好视,该法增加了is_update_cache 是否同步更新缓存参数,这是盖咱们于采用缓存时会见存在一些非正规状况,比如说批量更新很多数目经常,如果下循环逐长长的清理对承诺缓存时,会占用比较多资源,我们得以合缓存的同步创新,直接调用clear清空所有缓存会更加高效;又比如说,页面访问数的更新,它见面更新的坏累,我们不欲实时清除,可以采取外方法触发清理,也得以用点击数用独立缓存存储使用相当

  ……

  而清理缓存,我们仅仅待用缓存内容一直删除就足以了,因为实施更新之后,返回的笔录实体没有安装也*常,只回去主键id,直接装的言语会招缓存数据丢失细节的问题,另外,我们实施更新之后,该记录为非肯定还会给读取出来。

 

 

  缓存处理在问题

  删除记录也进行同样的改建

  除了前面所说的缓存问题外,我们后端更新某些数据常常(比如商品资料),就非得破除前端有着页面缓存,全面又转(因为过剩页面都见面显商品有关消息),由于没一个归结管理缓存的框架,在更新时就见面将片不必去的缓存也一头清除了。而当好几时候缓存被不少任何缓存所依靠时,清除该缓存也会见消除一些盈余的缓存,而无是精确定位。对于动态变化的可变后缀的缓存,在好几时候无法传递后缀参数时,将颇为难同步创新这些缓存内容。

 1     def delete(self, wheres='', returning='', is_update_cache=True):
 2         """
 3         批量删除数据库记录
 4         :param wheres: 删除条件
 5         :param returning: 删除成功后,返回的字段名
 6         :param is_update_cache: 是否同步更新缓存
 7         :return:
 8         """
 9         # 如果存在条件
10         if wheres:
11             wheres = ' where ' + wheres
12 
13         # 如果有指定返回参数,则添加
14         if returning:
15             returning = ', ' + returning
16 
17         # 生成sql语句
18         sql = "delete from %(table_name)s %(wheres)s returning %(pk_name)s %(returning)s" % \
19               {'table_name': self.__table_name, 'wheres': wheres, 'pk_name': self.__pk_name, 'returning': returning}
20         result = self.execute(sql)
21         if result:
22             # 同步删除对应的缓存
23             if is_update_cache:
24                 for model in result:
25                     self.del_model_for_cache(model.get('id', 0))
26         return result

 

 

  缓存处理解决思路

  对于缓存基本上就是马上有限个假设开展改建的操作了。在贯彻支付被,我们认真想同一思念,其实我们还会有部分特有之情景,比如说我们对数码进行加工处理后,将加工后的价值存储到缓存中,而针对性系记录进行改动或者去操作后,由于这些缓存它同记录并无涉及,所以实行有关操作后,它便改为孤岛,不见面实时同步,产生污染数据。所以我们用来一个成效,可以以它管理起来,与拖欠数据表的改动及去操作关联起来,进行改动及去操作后一头清除这些突出缓存。

  对于出现上面的一对问题,在综合考虑后,想写个单身的缓存处理插件来拍卖这些题材。主要透过配备来以缓存直接绑定数据表、字段、记录Id、关联缓存、页面缓存等关乎内容,在这些缓存更新时并清除对应之缓存模块,以便其他缓存还开缓存载入程序来加载相应数额到缓存中。在消除时有针对性,而休见面跨界清空多余的休养存。不知大家发出什么好的提议?

  根据这些要求,我们即便需要再次充实有限只缓存操作方法,用来囤积这些独特之休养生息存名称,然后在拓展修改及去操作时,同步清除这些新鲜缓存。

 

  首先我们需要以初始化方法中,添加一个绑定该数据表的全局缓存变量self.__cache_list,它由表名称+_cache_list组成。

  下面是自身之组成部分化解思路:

 1     def __init__(self, db, is_output_sql, table_name, column_name_list='*', pk_name='id'):
 2         """类初始化"""
 3         # 数据库参数
 4         self.__db = db
 5         # 是否输出执行的Sql语句到日志中
 6         self.__is_output_sql = is_output_sql
 7         # 表名称
 8         self.__table_name = str(table_name).lower()
 9         # 查询的列字段名称,*表示查询全部字段,多于1个字段时用逗号进行分隔,除了字段名外,也可以是表达式
10         self.__column_name_list = str(column_name_list).lower()
11         # 主健名称
12         self.__pk_name = str(pk_name).lower()
13         # 缓存列表
14         self.__cache_list = self.__table_name + '_cache_list'

  1、首先缓存插件必须是一个单独的次序

 

  2、调用必须透过联合之接口来进行拍卖

  然后我们再度上加特别缓存存储方

  3、缓存关联必须通过部署来实现绑定

 1     def add_relevance_cache_in_list(self, key):
 2         """将缓存名称存储到列表里————主要存储与记录变更关联的"""
 3         # 从nosql中读取全局缓存列表
 4         cache_list = cache_helper.get(self.__cache_list)
 5         # 判断缓存列表是否有值,有则进行添加操作
 6         if cache_list:
 7             # 判断是否已存储列表中,不存在则执行添加操作
 8             if not key in cache_list:
 9                 cache_list.append(key)
10                 cache_helper.set(self.__cache_list, cache_list)
11         # 无则直接创建全局缓存列表,并存储到nosql中
12         else:
13             cache_list = [key]
14             cache_helper.set(self.__cache_list, cache_list)

  4、缓存命名必须符合一定的正经

  执行该方法,会拿我们于定义之休养存名称存储到全局缓存变量中

 

 

  具体实现方式:

  就我们还补偿加一个免去所有特别缓存的不二法门

  获取缓存:Get Cache => Check null
=> Load =>
Save(保存时会尽存储数据的反省,这里开时若小心,避免出现死循环)
=> Return Cache
(即获缓存时要检查指定缓存是否为空,为空时调用Load接口载入数据到缓存——Load函数功能由操作方实现,使用安排+IoC来调用,IoC配置文件以及接口文件可以用T4模板直接生成——,然后用数据存储到缓存中,最后回到所而的缓存;当然如果缓存不呢空时直接回缓存)

 1     def del_relevance_cache(self):
 2         """删除关联缓存————将和数据表记录关联的,个性化缓存全部删除"""
 3         # 从nosql中读取全局缓存列表
 4         cache_list = cache_helper.get(self.__cache_list)
 5         # 清除已删除缓存列表
 6         cache_helper.delete(self.__cache_list)
 7         if cache_list:
 8             # 执行删除操作
 9             for cache in cache_list:
10                 cache_helper.delete(cache)

  存储数据:Save Cache => Save =>
Check Relevance => Delete Relevance Cache
(即存储数据常常,首先用数据保存及缓存中,然后读取配置信息检查该缓存与那些缓存关联,如果存在涉嫌关系之缓存,则共清除这些缓存,以便下次获取这些缓存时能够还加载)

 

  删除缓存:Delete Cache => Delete
=> Check Relevance => Delete Relevance
Cache(删除时实施递归调用,按常规的话,这种关联应该无会见无限可怜)

  添加完成之后,我们再次来改造一下窜及删除代码,只需要在里加加祛除所有特别缓存方法就是足以了

  设置缓存参数:Set
(修改缓存插件的有的大局配置)

九五至尊1老品牌值得 5九五至尊1老品牌值得 6

 

 1     def edit(self, fields, wheres='', returning='', is_update_cache=True):
 2         """
 3         批量编辑数据库记录
 4         :param fields: 要更新的字段(字段名与值存储在字典中)
 5         :param wheres: 更新条件
 6         :param returning: 更新成功后,返回的字段名
 7         :param is_update_cache: 是否同步更新缓存
 8         :return:
 9         """
10         ### 拼接sql语句 ###
11         # 拼接字段与值
12         field_list = [key + ' = %(' + key + ')s' for key in fields.keys()]
13         # 设置sql拼接字典
14         parameter = {
15             'table_name': self.__table_name,
16             'pk_name': self.__pk_name,
17             'field_list': ','.join(field_list)
18         }
19         # 如果存在更新条件,则将条件添加到sql拼接更换字典中
20         if wheres:
21             parameter['wheres'] = ' where ' + wheres
22         else:
23             parameter['wheres'] = ''
24 
25         # 如果有指定返回参数,则添加
26         if returning:
27             parameter['returning'] = ', ' + returning
28         else:
29             parameter['returning'] = ''
30 
31         # 生成sql语句
32         sql = "update %(table_name)s set %(field_list)s %(wheres)s returning %(pk_name)s %(returning)s" % parameter
33         sql = sql % fields
34 
35         result = self.execute(sql)
36         if result:
37             # 判断是否删除对应的缓存
38             if is_update_cache:
39                 # 循环删除更新成功的所有记录对应的缓存
40                 for model in result:
41                     self.del_model_for_cache(model.get('id', 0))
42                 # 同步删除与本表关联的缓存
43                 self.del_relevance_cache()
44         return result
45 
46     def delete(self, wheres='', returning='', is_update_cache=True):
47         """
48         批量删除数据库记录
49         :param wheres: 删除条件
50         :param returning: 删除成功后,返回的字段名
51         :param is_update_cache: 是否同步更新缓存
52         :return:
53         """
54         # 如果存在条件
55         if wheres:
56             wheres = ' where ' + wheres
57 
58         # 如果有指定返回参数,则添加
59         if returning:
60             returning = ', ' + returning
61 
62         # 生成sql语句
63         sql = "delete from %(table_name)s %(wheres)s returning %(pk_name)s %(returning)s" % \
64               {'table_name': self.__table_name, 'wheres': wheres, 'pk_name': self.__pk_name, 'returning': returning}
65         result = self.execute(sql)
66         if result:
67             # 同步删除对应的缓存
68             if is_update_cache:
69                 for model in result:
70                     self.del_model_for_cache(model.get('id', 0))
71                 # 同步删除与本表关联的缓存
72                 self.del_relevance_cache()
73         return result

  给外部直接调用的但来Get/Save/Delete,需要外表程序实现的接口暂定为Load这一个,里面实现数量加载的代码

View Code

  以布置时,缓存依赖必须单向,避免出现死循环(可写程序检查部署)

  

  要拍卖好动态后缀缓存的拍卖,能通过参数控制智能判断缓存的干。比如名为tablename_id的缓存,在推行Load时会见用id截取出来传递让操作函数,那么载入时就独自加载该id的笔录;

  ORM的缓存改造就尽成就了,下面是完好代码

  对于创新往往之数码,比如页面点击计数等,如果急需用到缓存的,需要独自出来存取和换代,以免更新时实行并清除功能

九五至尊1老品牌值得 7九五至尊1老品牌值得 8

  可以由此Set来开或关闭Load、Delete
Relevance Cache功能等

  1 #!/usr/bin/env python
  2 # coding=utf-8
  3 
  4 from common import db_helper, cache_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 
 28     def select(self, sql):
 29         """执行sql查询语句(select)"""
 30         with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
 31             # 执行sql语句
 32             result = db.execute(sql)
 33             if not result:
 34                 result = []
 35         return result
 36 
 37     def execute(self, sql):
 38         """执行sql语句,并提交事务"""
 39         with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
 40             # 执行sql语句
 41             result = db.execute(sql)
 42             if result:
 43                 db.commit()
 44             else:
 45                 result = []
 46         return result
 47 
 48     def copy(self, values, columns):
 49         """批量更新数据"""
 50         with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
 51             # 执行sql语句
 52             result = db.copy(values, self.__table_name, columns)
 53         return result
 54 
 55     def get_model(self, wheres):
 56         """通过条件获取一条记录"""
 57         # 如果有条件,则自动添加where
 58         if wheres:
 59             wheres = ' where ' + wheres
 60 
 61         # 合成sql语句
 62         sql = "select %(column_name_list)s from %(table_name)s %(wheres)s" % \
 63               {'column_name_list': self.__column_name_list, 'table_name': self.__table_name, 'wheres': wheres}
 64         # 初化化数据库链接
 65         result = self.select(sql)
 66         if result:
 67             return result[0]
 68         return {}
 69 
 70     def get_model_for_pk(self, pk, wheres=''):
 71         """通过主键值获取数据库记录实体"""
 72         if not pk:
 73             return {}
 74         # 组装查询条件
 75         wheres = '%s = %s' % (self.__pk_name, str(pk))
 76 
 77         return self.get_model(wheres)
 78 
 79     def get_value(self, column_name, wheres=''):
 80         """
 81         获取指定条件的字段值————多于条记录时,只取第一条记录
 82         :param column_name: 单个字段名,如:id
 83         :param wheres: 查询条件
 84         :return: 7 (指定的字段值)
 85         """
 86         if not column_name:
 87             return None
 88         elif wheres:
 89             wheres = ' where ' + wheres
 90 
 91         sql = 'select %(column_name)s from %(table_name)s %(wheres)s limit 1' % \
 92               {'column_name': column_name, 'table_name': self.__table_name, 'wheres': wheres}
 93         result = self.select(sql)
 94         # 如果查询成功,则直接返回记录字典
 95         if result:
 96             return result[0].get(column_name)
 97 
 98     def get_value_list(self, column_name, wheres=''):
 99         """
100         获取指定条件记录的字段值列表
101         :param column_name: 单个字段名,如:id
102         :param wheres: 查询条件
103         :return: [1,3,4,6,7]
104         """
105         if not column_name:
106             column_name = self.__pk_name
107         elif wheres:
108             wheres = ' where ' + wheres
109 
110         sql = 'select array_agg(%(column_name)s) as list from %(table_name)s %(wheres)s' % \
111               {'column_name': column_name, 'table_name': self.__table_name, 'wheres': wheres}
112         result = self.select(sql)
113         # 如果查询失败或不存在指定条件记录,则直接返回初始值
114         if result and isinstance(result, list):
115             return result[0].get('list')
116         else:
117             return []
118 
119     def add_model(self, fields, returning=''):
120         """新增数据库记录"""
121         ### 拼接sql语句 ###
122         # 初始化变量
123         key_list = []
124         value_list = []
125         # 将传入的字典参数进行处理,把字段名生成sql插入字段名数组和字典替换数组
126         # PS:字符串使用字典替换参数时,格式是%(name)s,这里会生成对应的字串
127         # 比如:
128         #   传入的字典为: {'id': 1, 'name': '名称'}
129         #   那么生成的key_list为:'id','name'
130         #   而value_list为:'%(id)s,%(name)s'
131         #   最终而value_list为字符串对应名称位置会被替换成相应的值
132         for key in fields.keys():
133             key_list.append(key)
134             value_list.append('%(' + key + ')s')
135         # 设置sql拼接字典,并将数组(lit)使用join方式进行拼接,生成用逗号分隔的字符串
136         parameter = {
137             'table_name': self.__table_name,
138             'pk_name': self.__pk_name,
139             'key_list': ','.join(key_list),
140             'value_list': ','.join(value_list)
141         }
142         # 如果有指定返回参数,则添加
143         if returning:
144             parameter['returning'] = ', ' + returning
145         else:
146             parameter['returning'] = ''
147 
148         # 生成可以使用字典替换的字符串
149         sql = "insert into %(table_name)s (%(key_list)s) values (%(value_list)s) returning %(pk_name)s %(returning)s" % parameter
150         # 将生成好的字符串替字典参数值,生成最终可执行的sql语句
151         sql = sql % fields
152 
153         result = self.execute(sql)
154         if result:
155             return result[0]
156         return {}
157 
158     def edit(self, fields, wheres='', returning='', is_update_cache=True):
159         """
160         批量编辑数据库记录
161         :param fields: 要更新的字段(字段名与值存储在字典中)
162         :param wheres: 更新条件
163         :param returning: 更新成功后,返回的字段名
164         :param is_update_cache: 是否同步更新缓存
165         :return:
166         """
167         ### 拼接sql语句 ###
168         # 拼接字段与值
169         field_list = [key + ' = %(' + key + ')s' for key in fields.keys()]
170         # 设置sql拼接字典
171         parameter = {
172             'table_name': self.__table_name,
173             'pk_name': self.__pk_name,
174             'field_list': ','.join(field_list)
175         }
176         # 如果存在更新条件,则将条件添加到sql拼接更换字典中
177         if wheres:
178             parameter['wheres'] = ' where ' + wheres
179         else:
180             parameter['wheres'] = ''
181 
182         # 如果有指定返回参数,则添加
183         if returning:
184             parameter['returning'] = ', ' + returning
185         else:
186             parameter['returning'] = ''
187 
188         # 生成sql语句
189         sql = "update %(table_name)s set %(field_list)s %(wheres)s returning %(pk_name)s %(returning)s" % parameter
190         sql = sql % fields
191 
192         result = self.execute(sql)
193         if result:
194             # 判断是否删除对应的缓存
195             if is_update_cache:
196                 # 循环删除更新成功的所有记录对应的缓存
197                 for model in result:
198                     self.del_model_for_cache(model.get('id', 0))
199                 # 同步删除与本表关联的缓存
200                 self.del_relevance_cache()
201         return result
202 
203     def edit_model(self, pk, fields, wheres='', returning=''):
204         """编辑单条数据库记录"""
205         if not pk:
206             return {}
207         elif wheres:
208             wheres = self.__pk_name + ' = ' + str(pk) + ' and ' + wheres
209         else:
210             wheres = self.__pk_name + ' = ' + str(pk)
211 
212         return self.edit(fields, wheres, returning)
213 
214     def delete(self, wheres='', returning='', is_update_cache=True):
215         """
216         批量删除数据库记录
217         :param wheres: 删除条件
218         :param returning: 删除成功后,返回的字段名
219         :param is_update_cache: 是否同步更新缓存
220         :return:
221         """
222         # 如果存在条件
223         if wheres:
224             wheres = ' where ' + wheres
225 
226         # 如果有指定返回参数,则添加
227         if returning:
228             returning = ', ' + returning
229 
230         # 生成sql语句
231         sql = "delete from %(table_name)s %(wheres)s returning %(pk_name)s %(returning)s" % \
232               {'table_name': self.__table_name, 'wheres': wheres, 'pk_name': self.__pk_name, 'returning': returning}
233         result = self.execute(sql)
234         if result:
235             # 同步删除对应的缓存
236             if is_update_cache:
237                 for model in result:
238                     self.del_model_for_cache(model.get('id', 0))
239                 # 同步删除与本表关联的缓存
240                 self.del_relevance_cache()
241         return result
242 
243     def delete_model(self, pk, wheres='', returning='', is_update_cache=True):
244         """删除单条数据库记录"""
245         if not pk:
246             return {}
247         elif wheres:
248             wheres = self.__pk_name + ' = ' + str(pk) + ' and ' + wheres
249         else:
250             wheres = self.__pk_name + ' = ' + str(pk)
251 
252         return self.delete(wheres, returning)
253 
254     def get_list(self, column_name_list='', wheres='', page_number=None, page_size=None, orderby=None, table_name=None):
255         """
256         获取指定条件的数据库记录集
257         :param column_name_list:      查询字段
258         :param wheres:      查询条件
259         :param page_number:   分页索引值
260         :param page_size:    分页大小, 存在值时才会执行分页
261         :param orderby:     排序规则
262         :param table_name:     查询数据表,多表查询时需要设置
263         :return: 返回记录集总数量与分页记录集
264             {'records': 0, 'total': 0, 'page': 0, 'rows': []}
265         """
266         # 初始化输出参数:总记录数量与列表集
267         data = {
268             'records': 0,  # 总记录数
269             'total': 0,  # 总页数
270             'page': 1,  # 当前页面索引
271             'rows': [],  # 查询结果(记录列表)
272         }
273         # 初始化查询数据表名称
274         if not table_name:
275             table_name = self.__table_name
276         # 初始化查询字段名
277         if not column_name_list:
278             column_name_list = self.__column_name_list
279         # 初始化查询条件
280         if wheres:
281             # 如果是字符串,表示该查询条件已组装好了,直接可以使用
282             if isinstance(wheres, str):
283                 wheres = 'where ' + wheres
284             # 如果是list,则表示查询条件有多个,可以使用join将它们用and方式组合起来使用
285             elif isinstance(wheres, list):
286                 wheres = 'where ' + ' and '.join(wheres)
287         # 初始化排序
288         if not orderby:
289             orderby = self.__pk_name + ' desc'
290         # 初始化分页查询的记录区间
291         paging = ''
292 
293         with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
294             #############################################################
295             # 判断是否需要进行分页
296             if not page_size is None:
297                 ### 执行sql,获取指定条件的记录总数量
298                 sql = 'select count(1) as records from %(table_name)s %(wheres)s ' % \
299                       {'table_name': table_name, 'wheres': wheres}
300                 result = db.execute(sql)
301                 # 如果查询失败或不存在指定条件记录,则直接返回初始值
302                 if not result or result[0]['records'] == 0:
303                     return data
304 
305                 # 设置记录总数量
306                 data['records'] = result[0].get('records')
307 
308                 #########################################################
309                 ### 设置分页索引与页面大小 ###
310                 if page_size <= 0:
311                     page_size = 10
312                 # 计算总分页数量:通过总记录数除于每页显示数量来计算总分页数量
313                 if data['records'] % page_size == 0:
314                     page_total = data['records'] // page_size
315                 else:
316                     page_total = data['records'] // page_size + 1
317                 # 判断页码是否超出限制,超出限制查询时会出现异常,所以将页面索引设置为最后一页
318                 if page_number < 1 or page_number > page_total:
319                     page_number = page_total
320                 # 记录总页面数量
321                 data['total'] = page_total
322                 # 记录当前页面值
323                 data['page'] = page_number
324                 # 计算当前页面要显示的记录起始位置(limit指定的位置)
325                 record_number = (page_number - 1) * page_size
326                 # 设置查询分页条件
327                 paging = ' limit ' + str(page_size) + ' offset ' + str(record_number)
328             #############################################################
329 
330             ### 按条件查询数据库记录
331             sql = "select %(column_name_list)s from %(table_name)s %(wheres)s order by %(orderby)s %(paging)s" % \
332                   {'column_name_list': column_name_list,
333                    'table_name': table_name,
334                    'wheres': wheres,
335                    'orderby': orderby,
336                    'paging': paging}
337             result = db.execute(sql)
338             if result:
339                 data['rows'] = result
340                 # 不需要分页查询时,直接在这里设置总记录数
341                 if page_size is None:
342                     data['records'] = len(result)
343 
344         return data
345 
346     def get_count(self, wheres=''):
347         """获取指定条件记录数量"""
348         if wheres:
349             wheres = ' where ' + wheres
350         sql = 'select count(1) as total from %(table_name)s %(wheres)s ' % \
351               {'table_name': self.__table_name, 'wheres': wheres}
352         result = self.select(sql)
353         # 如果查询存在记录,则返回true
354         if result:
355             return result[0].get('total')
356         return 0
357 
358     def get_sum(self, fields, wheres):
359         """获取指定条件记录数量"""
360         sql = 'select sum(%(fields)s) as total from %(table_name)s where %(wheres)s ' % \
361               {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}
362         result = self.select(sql)
363         # 如果查询存在记录,则返回true
364         if result and result[0].get('total'):
365             return result[0].get('total')
366         return 0
367 
368     def get_min(self, fields, wheres):
369         """获取该列记录最小值"""
370         sql = 'select min(%(fields)s) as min from %(table_name)s where %(wheres)s ' % \
371               {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}
372         result = self.select(sql)
373         # 如果查询存在记录,则返回true
374         if result and result[0].get('min'):
375             return result[0].get('min')
376 
377     def get_max(self, fields, wheres):
378         """获取该列记录最大值"""
379         sql = 'select max(%(fields)s) as max from %(table_name)s where %(wheres)s ' % \
380               {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}
381         result = self.select(sql)
382         # 如果查询存在记录,则返回true
383         if result and result[0].get('max'):
384             return result[0].get('max')
385 
386             #####################################################################
387 
388 
389     #####################################################################
390     ### 缓存操作方法 ###
391 
392     def get_cache_key(self, pk):
393         """获取缓存key值"""
394         return ''.join((self.__table_name, '_', str(pk)))
395 
396     def set_model_for_cache(self, pk, value, time=43200):
397         """更新存储在缓存中的数据库记录,缓存过期时间为12小时"""
398         # 生成缓存key
399         key = self.get_cache_key(pk)
400         # 存储到nosql缓存中
401         cache_helper.set(key, value, time)
402 
403     def get_model_for_cache(self, pk):
404         """从缓存中读取数据库记录"""
405         # 生成缓存key
406         key = self.get_cache_key(pk)
407         # 从缓存中读取数据库记录
408         result = cache_helper.get(key)
409         # 缓存中不存在记录,则从数据库获取
410         if not result:
411             result = self.get_model_for_pk(pk)
412             self.set_model_for_cache(pk, result)
413         if result:
414             return result
415         else:
416             return {}
417 
418     def get_value_for_cache(self, pk, column_name):
419         """获取指定记录的字段值"""
420         return self.get_model_for_cache(pk).get(column_name)
421 
422     def del_model_for_cache(self, pk):
423         """删除缓存中指定数据"""
424         # 生成缓存key
425         key = self.get_cache_key(pk)
426         # log_helper.info(key)
427         # 存储到nosql缓存中
428         cache_helper.delete(key)
429 
430     def add_relevance_cache_in_list(self, key):
431         """将缓存名称存储到列表里————主要存储与记录变更关联的"""
432         # 从nosql中读取全局缓存列表
433         cache_list = cache_helper.get(self.__cache_list)
434         # 判断缓存列表是否有值,有则进行添加操作
435         if cache_list:
436             # 判断是否已存储列表中,不存在则执行添加操作
437             if not key in cache_list:
438                 cache_list.append(key)
439                 cache_helper.set(self.__cache_list, cache_list)
440         # 无则直接创建全局缓存列表,并存储到nosql中
441         else:
442             cache_list = [key]
443             cache_helper.set(self.__cache_list, cache_list)
444 
445     def del_relevance_cache(self):
446         """删除关联缓存————将和数据表记录关联的,个性化缓存全部删除"""
447         # 从nosql中读取全局缓存列表
448         cache_list = cache_helper.get(self.__cache_list)
449         # 清除已删除缓存列表
450         cache_helper.delete(self.__cache_list)
451         if cache_list:
452             # 执行删除操作
453             for cache in cache_list:
454                 cache_helper.delete(cache)
455 
456     #####################################################################

  

View Code

 

 

  由于工作时繁忙,本随笔断断续续写了好长时间,有些想法与笔触没有马上记下来还记不清了,暂时想到这么多,思路为非是异常熟,不知大家有什么好之提议?这种处理模式是否留存什么问题?欢迎大家出来拍砖

 

 

版权声明:本文原创发表于 博客园,作者为 AllEmpty 正文欢迎转载,但未经作者同意要保留这个段子声明,且当文章页面明显位置于来原文连接,否则便是侵权。

 

python开发QQ群:669058475   
作者博客:http://www.cnblogs.com/EmptyFS/

 版权声明:

  本文由AllEmpty原创并披露让博客园,欢迎转载,未经我同意要保留这个段子声明,且在篇章页面明显位置给出原来和链接,再不保留追究法律责任的权利。如发题目,可以透过1654937@qq.com
联系自己,非常感谢。

 

  发表本编内容,**为和大家一起学习共同进步,九五至尊1老品牌值得有趣味之朋友可以加加Q群:327360708
,大家并追。

 

  更多内容,敬请观注博客:http://www.cnblogs.com/EmptyFS/

 

相关文章

标签:,

Your Comments

近期评论

    功能


    网站地图xml地图