我的第一个python web开发框架(32)——定制ORM(八)
写到这里,基本的ORM功能就完成了,不知大家有没有发现,这个ORM每个方法都是在with中执行的,也就是说每个方法都是一个完整的事务,当它执行完成以后也会将事务提交,那么如果我们想要进行一个复杂的事务时,它并不能做到,所以我们还需要对它进行改造,让它支持sql事务。
那么应该怎么实现呢?我们都知道要支持事务,就必须让不同的sql语句在同一个事务中执行,也就是说,我们需要在一个with中执行所有的sql语句,失败则回滚,成功再提交事务。
由于我们的逻辑层各个类都是继承ORM基类来实现的,而事务的开关放在各个类中就不合适,可能会存在问题,所以在执行事务时,直接调用db_helper模块,使用with初始化好数据库链接,然后在方法里编写并执行各个sql语句。
当前逻辑层基类(ORM模块)的sql语句都是在方法中生成(拼接)的,然后在方法的with模块中执行,所以我们需要再次对整个类进行改造,将所有的sql生成方法提炼出来,成为单独的方法,然后在事务中,我们不直接执行获取结果,而是通过ORM生成对应的sql语句,在with中执行这样语句。(当然还有其他方法也能实现事务,不过在这里不做进一步的探讨,因为当前这种是最简单实现事务的方式之一,多层封装处理,有可能会导致系统变的更加复杂,代码更加难懂)
代码改造起来很简单,比如说获取记录方法
def get_model(self, wheres):
"""通过条件获取一条记录"""
# 如果有条件,则自动添加where
if wheres:
wheres = ' where ' + wheres # 合成sql语句
sql = "select %(column_name_list)s from %(table_name)s %(wheres)s" % \
{'column_name_list': self.__column_name_list, 'table_name': self.__table_name, 'wheres': wheres}
# 初化化数据库链接
result = self.select(sql)
if result:
return result[0]
return {}
我们可以将它拆分成get_model_sql()和get_model()两个方法,一个处理sql组合,一个执行获取结果,前者可以给事务调用,后者直接给对应的程序调用
def get_model_sql(self, wheres):
"""通过条件获取一条记录"""
# 如果有条件,则自动添加where
if wheres:
wheres = ' where ' + wheres # 合成sql语句
sql = "select %(column_name_list)s from %(table_name)s %(wheres)s" % \
{'column_name_list': self.__column_name_list, 'table_name': self.__table_name, 'wheres': wheres}
return sql def get_model(self, wheres):
"""通过条件获取一条记录"""
# 生成sql
sql = self.get_model_sql(wheres)
# 初化化数据库链接
result = self.select(sql)
if result:
return result[0]
return {}
其他代码不一一细述,大家自己看看重构后的结果
#!/usr/bin/env python
# coding=utf-8 from common import db_helper, cache_helper, encrypt_helper class LogicBase():
"""逻辑层基础类""" def __init__(self, db, is_output_sql, table_name, column_name_list='*', pk_name='id'):
"""类初始化"""
# 数据库参数
self.__db = db
# 是否输出执行的Sql语句到日志中
self.__is_output_sql = is_output_sql
# 表名称
self.__table_name = str(table_name).lower()
# 查询的列字段名称,*表示查询全部字段,多于1个字段时用逗号进行分隔,除了字段名外,也可以是表达式
self.__column_name_list = str(column_name_list).lower()
# 主健名称
self.__pk_name = str(pk_name).lower()
# 缓存列表
self.__cache_list = self.__table_name + '_cache_list' #####################################################################
### 生成Sql ###
def get_model_sql(self, wheres):
"""通过条件获取一条记录"""
# 如果有条件,则自动添加where
if wheres:
wheres = ' where ' + wheres # 合成sql语句
sql = "select %(column_name_list)s from %(table_name)s %(wheres)s" % \
{'column_name_list': self.__column_name_list, 'table_name': self.__table_name, 'wheres': wheres}
return sql def get_model_for_pk_sql(self, pk, wheres=''):
"""通过主键值获取数据库记录实体"""
# 组装查询条件
wheres = '%s = %s' % (self.__pk_name, str(pk))
return self.get_model_sql(wheres) def get_value_sql(self, column_name, wheres=''):
"""
获取指定条件的字段值————多于条记录时,只取第一条记录
:param column_name: 单个字段名,如:id
:param wheres: 查询条件
:return: 7 (指定的字段值)
"""
if wheres:
wheres = ' where ' + wheres sql = 'select %(column_name)s from %(table_name)s %(wheres)s limit 1' % \
{'column_name': column_name, 'table_name': self.__table_name, 'wheres': wheres}
return sql def get_value_list_sql(self, column_name, wheres=''):
"""
获取指定条件记录的字段值列表
:param column_name: 单个字段名,如:id
:param wheres: 查询条件
:return: [1,3,4,6,7]
"""
if not column_name:
column_name = self.__pk_name
elif wheres:
wheres = ' where ' + wheres sql = 'select array_agg(%(column_name)s) as list from %(table_name)s %(wheres)s' % \
{'column_name': column_name, 'table_name': self.__table_name, 'wheres': wheres}
return sql def add_model_sql(self, fields, returning=''):
"""新增数据库记录"""
### 拼接sql语句 ###
# 初始化变量
key_list = []
value_list = []
# 将传入的字典参数进行处理,把字段名生成sql插入字段名数组和字典替换数组
# PS:字符串使用字典替换参数时,格式是%(name)s,这里会生成对应的字串
# 比如:
# 传入的字典为: {'id': 1, 'name': '名称'}
# 那么生成的key_list为:'id','name'
# 而value_list为:'%(id)s,%(name)s'
# 最终而value_list为字符串对应名称位置会被替换成相应的值
for key in fields.keys():
key_list.append(key)
value_list.append('%(' + key + ')s')
# 设置sql拼接字典,并将数组(lit)使用join方式进行拼接,生成用逗号分隔的字符串
parameter = {
'table_name': self.__table_name,
'pk_name': self.__pk_name,
'key_list': ','.join(key_list),
'value_list': ','.join(value_list)
}
# 如果有指定返回参数,则添加
if returning:
parameter['returning'] = ', ' + returning
else:
parameter['returning'] = '' # 生成可以使用字典替换的字符串
sql = "insert into %(table_name)s (%(key_list)s) values (%(value_list)s) returning %(pk_name)s %(returning)s" % parameter
# 将生成好的字符串替字典参数值,生成最终可执行的sql语句
return sql % fields def edit_sql(self, fields, wheres='', returning=''):
"""
批量编辑数据库记录
:param fields: 要更新的字段(字段名与值存储在字典中)
:param wheres: 更新条件
:param returning: 更新成功后,返回的字段名
:param is_update_cache: 是否同步更新缓存
:return:
"""
### 拼接sql语句 ###
# 拼接字段与值
field_list = [key + ' = %(' + key + ')s' for key in fields.keys()]
# 设置sql拼接字典
parameter = {
'table_name': self.__table_name,
'pk_name': self.__pk_name,
'field_list': ','.join(field_list)
}
# 如果存在更新条件,则将条件添加到sql拼接更换字典中
if wheres:
parameter['wheres'] = ' where ' + wheres
else:
parameter['wheres'] = '' # 如果有指定返回参数,则添加
if returning:
parameter['returning'] = ', ' + returning
else:
parameter['returning'] = '' # 生成sql语句
sql = "update %(table_name)s set %(field_list)s %(wheres)s returning %(pk_name)s %(returning)s" % parameter
return sql % fields def edit_model_sql(self, pk, fields, wheres='', returning=''):
"""编辑单条数据库记录"""
if wheres:
wheres = self.__pk_name + ' = ' + str(pk) + ' and ' + wheres
else:
wheres = self.__pk_name + ' = ' + str(pk) return self.edit_sql(fields, wheres, returning) def delete_sql(self, wheres='', returning=''):
"""
批量删除数据库记录
:param wheres: 删除条件
:param returning: 删除成功后,返回的字段名
:param is_update_cache: 是否同步更新缓存
:return:
"""
# 如果存在条件
if wheres:
wheres = ' where ' + wheres # 如果有指定返回参数,则添加
if returning:
returning = ', ' + returning # 生成sql语句
sql = "delete from %(table_name)s %(wheres)s returning %(pk_name)s %(returning)s" % \
{'table_name': self.__table_name, 'wheres': wheres, 'pk_name': self.__pk_name, 'returning': returning}
return sql def delete_model_sql(self, pk, wheres='', returning=''):
"""删除单条数据库记录"""
if wheres:
wheres = self.__pk_name + ' = ' + str(pk) + ' and ' + wheres
else:
wheres = self.__pk_name + ' = ' + str(pk) return self.delete_sql(wheres, returning) def get_list_sql(self, column_name_list='', wheres='', orderby=None, table_name=None):
"""
获取指定条件的数据库记录集
:param column_name_list: 查询字段
:param wheres: 查询条件
:param orderby: 排序规则
:param table_name: 查询数据表,多表查询时需要设置
:return:
"""
# 初始化查询数据表名称
if not table_name:
table_name = self.__table_name
# 初始化查询字段名
if not column_name_list:
column_name_list = self.__column_name_list
# 初始化查询条件
if wheres:
# 如果是字符串,表示该查询条件已组装好了,直接可以使用
if isinstance(wheres, str):
wheres = 'where ' + wheres
# 如果是list,则表示查询条件有多个,可以使用join将它们用and方式组合起来使用
elif isinstance(wheres, list):
wheres = 'where ' + ' and '.join(wheres)
# 初始化排序
if not orderby:
orderby = self.__pk_name + ' desc'
############################################################# ### 按条件查询数据库记录
sql = "select %(column_name_list)s from %(table_name)s %(wheres)s order by %(orderby)s " % \
{'column_name_list': column_name_list,
'table_name': table_name,
'wheres': wheres,
'orderby': orderby}
return sql def get_count_sql(self, wheres=''):
"""获取指定条件记录数量"""
if wheres:
wheres = ' where ' + wheres
sql = 'select count(1) as total from %(table_name)s %(wheres)s ' % \
{'table_name': self.__table_name, 'wheres': wheres}
return sql def get_sum_sql(self, fields, wheres):
"""获取指定条件记录数量"""
sql = 'select sum(%(fields)s) as total from %(table_name)s where %(wheres)s ' % \
{'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}
return sql def get_min_sql(self, fields, wheres):
"""获取该列记录最小值"""
sql = 'select min(%(fields)s) as min from %(table_name)s where %(wheres)s ' % \
{'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}
return sql def get_max_sql(self, fields, wheres):
"""获取该列记录最大值"""
sql = 'select max(%(fields)s) as max from %(table_name)s where %(wheres)s ' % \
{'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}
return sql ##################################################################### #####################################################################
### 执行Sql ### def select(self, sql):
"""执行sql查询语句(select)"""
with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
# 执行sql语句
result = db.execute(sql)
if not result:
result = []
return result def execute(self, sql):
"""执行sql语句,并提交事务"""
with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
# 执行sql语句
result = db.execute(sql)
if result:
db.commit()
else:
result = []
return result def copy(self, values, columns):
"""批量更新数据"""
with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
# 执行sql语句
result = db.copy(values, self.__table_name, columns)
return result def get_model(self, wheres):
"""通过条件获取一条记录"""
# 生成sql
sql = self.get_model_sql(wheres)
# 执行查询操作
result = self.select(sql)
if result:
return result[0]
return {} def get_model_for_pk(self, pk, wheres=''):
"""通过主键值获取数据库记录实体"""
if not pk:
return {}
# 生成sql
sql = self.get_model_for_pk_sql(pk, wheres)
# 执行查询操作
result = self.select(sql)
if result:
return result[0]
return {} def get_value(self, column_name, wheres=''):
"""
获取指定条件的字段值————多于条记录时,只取第一条记录
:param column_name: 单个字段名,如:id
:param wheres: 查询条件
:return: 7 (指定的字段值)
"""
if not column_name:
return None # 生成sql
sql = self.get_value_sql(column_name, wheres)
result = self.select(sql)
# 如果查询成功,则直接返回记录字典
if result:
return result[0].get(column_name) def get_value_list(self, column_name, wheres=''):
"""
获取指定条件记录的字段值列表
:param column_name: 单个字段名,如:id
:param wheres: 查询条件
:return: [1,3,4,6,7]
"""
# 生成sql
sql = self.get_value_list_sql(column_name, wheres)
result = self.select(sql)
# 如果查询失败或不存在指定条件记录,则直接返回初始值
if result and isinstance(result, list):
return result[0].get('list')
else:
return [] def add_model(self, fields, returning=''):
"""新增数据库记录"""
# 生成sql
sql = self.add_model_sql(fields, returning)
result = self.execute(sql)
if result:
return result[0]
return {} def edit(self, fields, wheres='', returning='', is_update_cache=True):
"""
批量编辑数据库记录
:param fields: 要更新的字段(字段名与值存储在字典中)
:param wheres: 更新条件
:param returning: 更新成功后,返回的字段名
:param is_update_cache: 是否同步更新缓存
:return:
"""
# 生成sql
sql = self.edit_sql(fields, wheres, returning)
result = self.execute(sql)
if result:
# 判断是否删除对应的缓存
if is_update_cache:
# 循环删除更新成功的所有记录对应的缓存
for model in result:
self.del_model_for_cache(model.get(self.__pk_name, 0))
# 同步删除与本表关联的缓存
self.del_relevance_cache()
return result def edit_model(self, pk, fields, wheres='', returning='', is_update_cache=True):
"""编辑单条数据库记录"""
if not pk:
return {}
# 生成sql
sql = self.edit_model_sql(pk, fields, wheres, returning)
result = self.execute(sql)
if result:
# 判断是否删除对应的缓存
if is_update_cache:
# 删除更新成功的所有记录对应的缓存
self.del_model_for_cache(result[0].get(self.__pk_name, 0))
# 同步删除与本表关联的缓存
self.del_relevance_cache()
return result def delete(self, wheres='', returning='', is_update_cache=True):
"""
批量删除数据库记录
:param wheres: 删除条件
:param returning: 删除成功后,返回的字段名
:param is_update_cache: 是否同步更新缓存
:return:
"""
# 生成sql
sql = self.delete_sql(wheres, returning)
result = self.execute(sql)
if result:
# 同步删除对应的缓存
if is_update_cache:
for model in result:
self.del_model_for_cache(model.get(self.__pk_name, 0))
# 同步删除与本表关联的缓存
self.del_relevance_cache()
return result def delete_model(self, pk, wheres='', returning='', is_update_cache=True):
"""删除单条数据库记录"""
if not pk:
return {}
# 生成sql
sql = self.delete_model_sql(pk, wheres, returning)
result = self.execute(sql)
if result:
# 同步删除对应的缓存
if is_update_cache:
self.del_model_for_cache(result[0].get(self.__pk_name, 0))
# 同步删除与本表关联的缓存
self.del_relevance_cache()
return result def get_list(self, column_name_list='', wheres='', page_number=None, page_size=None, orderby=None, table_name=None):
"""
获取指定条件的数据库记录集
:param column_name_list: 查询字段
:param wheres: 查询条件
:param page_number: 分页索引值
:param page_size: 分页大小, 存在值时才会执行分页
:param orderby: 排序规则
:param table_name: 查询数据表,多表查询时需要设置
:return: 返回记录集总数量与分页记录集
{'records': 0, 'total': 0, 'page': 0, 'rows': []}
"""
# 初始化输出参数:总记录数量与列表集
data = {
'records': 0, # 总记录数
'total': 0, # 总页数
'page': 1, # 当前页面索引
'rows': [], # 查询结果(记录列表)
}
# 初始化查询数据表名称
if not table_name:
table_name = self.__table_name
# 初始化查询字段名
if not column_name_list:
column_name_list = self.__column_name_list
# 初始化查询条件
if wheres:
# 如果是字符串,表示该查询条件已组装好了,直接可以使用
if isinstance(wheres, str):
wheres = 'where ' + wheres
# 如果是list,则表示查询条件有多个,可以使用join将它们用and方式组合起来使用
elif isinstance(wheres, list):
wheres = 'where ' + ' and '.join(wheres)
# 初始化排序
if not orderby:
orderby = self.__pk_name + ' desc'
# 初始化分页查询的记录区间
paging = '' with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:
#############################################################
# 判断是否需要进行分页
if not page_size is None:
### 执行sql,获取指定条件的记录总数量
sql = 'select count(1) as records from %(table_name)s %(wheres)s ' % \
{'table_name': table_name, 'wheres': wheres}
result = db.execute(sql)
# 如果查询失败或不存在指定条件记录,则直接返回初始值
if not result or result[0]['records'] == 0:
return data # 设置记录总数量
data['records'] = result[0].get('records') #########################################################
### 设置分页索引与页面大小 ###
if page_size <= 0:
page_size = 10
# 计算总分页数量:通过总记录数除于每页显示数量来计算总分页数量
if data['records'] % page_size == 0:
page_total = data['records'] // page_size
else:
page_total = data['records'] // page_size + 1
# 判断页码是否超出限制,超出限制查询时会出现异常,所以将页面索引设置为最后一页
if page_number < 1 or page_number > page_total:
page_number = page_total
# 记录总页面数量
data['total'] = page_total
# 记录当前页面值
data['page'] = page_number
# 计算当前页面要显示的记录起始位置(limit指定的位置)
record_number = (page_number - 1) * page_size
# 设置查询分页条件
paging = ' limit ' + str(page_size) + ' offset ' + str(record_number)
############################################################# ### 按条件查询数据库记录
sql = "select %(column_name_list)s from %(table_name)s %(wheres)s order by %(orderby)s %(paging)s" % \
{'column_name_list': column_name_list,
'table_name': table_name,
'wheres': wheres,
'orderby': orderby,
'paging': paging}
result = db.execute(sql)
if result:
data['rows'] = result
# 不需要分页查询时,直接在这里设置总记录数
if page_size is None:
data['records'] = len(result) return data def get_count(self, wheres=''):
"""获取指定条件记录数量"""
# 生成sql
sql = self.get_count_sql(wheres)
result = self.select(sql)
# 如果查询存在记录,则返回true
if result:
return result[0].get('total')
return 0 def get_sum(self, fields, wheres):
"""获取指定条件记录数量"""
# 生成sql
sql = self.get_sum_sql(fields, wheres)
result = self.select(sql)
# 如果查询存在记录,则返回true
if result and result[0].get('total'):
return result[0].get('total')
return 0 def get_min(self, fields, wheres):
"""获取该列记录最小值"""
# 生成sql
sql = self.get_min_sql(fields, wheres)
result = self.select(sql)
# 如果查询存在记录,则返回true
if result and result[0].get('min'):
return result[0].get('min') def get_max(self, fields, wheres):
"""获取该列记录最大值"""
# 生成sql
sql = self.get_max_sql(fields, wheres)
result = self.select(sql)
# 如果查询存在记录,则返回true
if result and result[0].get('max'):
return result[0].get('max') ##################################################################### #####################################################################
### 缓存操作方法 ### def get_cache_key(self, pk):
"""获取缓存key值"""
return ''.join((self.__table_name, '_', str(pk))) 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 {} def get_model_for_cache_of_where(self, where):
"""
通过条件获取记录实体(我们经常需要使用key、编码或指定条件来获取记录,这时可以通过当前方法来获取)
:param where: 查询条件
:return: 记录实体
"""
# 生成实体缓存key
model_cache_key = self.__table_name + encrypt_helper.md5(where)
# 通过条件从缓存中获取记录id
pk = cache_helper.get(model_cache_key)
# 如果主键id存在,则直接从缓存中读取记录
if pk:
return self.get_model_for_cache(pk) # 否则从数据库中获取
result = self.get_model(where)
if result:
# 存储条件对应的主键id值到缓存中
cache_helper.set(model_cache_key, result.get(self.__pk_name))
# 存储记录实体到缓存中
self.set_model_for_cache(result.get(self.__pk_name), result)
return result def get_value_for_cache(self, pk, column_name):
"""获取指定记录的字段值"""
return self.get_model_for_cache(pk).get(column_name) def del_model_for_cache(self, pk):
"""删除缓存中指定数据"""
# 生成缓存key
key = self.get_cache_key(pk)
# log_helper.info(key)
# 存储到nosql缓存中
cache_helper.delete(key) def add_relevance_cache_in_list(self, key):
"""将缓存名称存储到列表里————主要存储与记录变更关联的"""
# 从nosql中读取全局缓存列表
cache_list = cache_helper.get(self.__cache_list)
# 判断缓存列表是否有值,有则进行添加操作
if cache_list:
# 判断是否已存储列表中,不存在则执行添加操作
if not key in cache_list:
cache_list.append(key)
cache_helper.set(self.__cache_list, cache_list)
# 无则直接创建全局缓存列表,并存储到nosql中
else:
cache_list = [key]
cache_helper.set(self.__cache_list, cache_list) def del_relevance_cache(self):
"""删除关联缓存————将和数据表记录关联的,个性化缓存全部删除"""
# 从nosql中读取全局缓存列表
cache_list = cache_helper.get(self.__cache_list)
# 清除已删除缓存列表
cache_helper.delete(self.__cache_list)
if cache_list:
# 执行删除操作
for cache in cache_list:
cache_helper.delete(cache) #####################################################################
从完整代码可以看到,重构后的类多了很多sql生成方法,它们其实是从原方法中分享出sql合成代码,将它们独立出来而已。
接下来我们编写单元测试代码,执行一下事务看看效果
#!/usr/bin/evn python
# coding=utf-8 import unittest
from common import db_helper
from common.string_helper import string
from config import db_config
from logic import product_logic, product_class_logic class DbHelperTest(unittest.TestCase):
"""数据库操作包测试类""" def setUp(self):
"""初始化测试环境"""
print('------ini------') def tearDown(self):
"""清理测试环境"""
print('------clear------') def test(self):
##############################################
# 只需要看这里,其他代码是测试用例的模板代码 #
##############################################
# 测试事务
# 使用with方法,初始化数据库链接
with db_helper.PgHelper(db_config.DB, db_config.IS_OUTPUT_SQL) as db:
# 实例化product表操作类ProductLogic
_product_logic = product_logic.ProductLogic()
# 实例化product_class表操作类product_class_logic
_product_class_logic = product_class_logic.ProductClassLogic()
# 初始化产品分类主键id
id = 1 # 获取产品分类信息(为了查看效果,所以加了这段获取分类信息)
sql = _product_class_logic.get_model_for_pk_sql(id)
print(sql)
# 执行sql语句
result = db.execute(sql)
if not result:
print('不存在指定的产品分类')
return
print('----产品分类实体----')
print(result)
print('-------------------') # 禁用产品分类
fields = {
'is_enable': 0
}
sql = _product_class_logic.edit_model_sql(id, fields, returning='is_enable')
print(sql)
# 执行sql语句
result = db.execute(sql)
if not result:
# 执行失败,执行回滚操作
db.rollback()
print('禁用产品分类失败')
return
# 执行缓存清除操作
_product_class_logic.del_model_for_cache(id)
_product_class_logic.del_relevance_cache()
print('----执行成功后的产品分类实体----')
print(result)
print('-------------------------------') # 同步禁用产品分类对应的所有产品
sql = _product_logic.edit_sql(fields, 'product_class_id=' + str(id), returning='is_enable')
print(sql)
# 执行sql语句
result = db.execute(sql)
if not result:
# 执行失败,执行回滚操作
db.rollback()
print('同步禁用产品分类对应的所有产品失败')
return
# 执行缓存清除操作
for model in result:
_product_class_logic.del_model_for_cache(model.get('id'))
_product_class_logic.del_relevance_cache()
print('----执行成功后的产品实体----')
print(result)
print('---------------------------') db.commit()
print('执行成功')
############################################## if __name__ == '__main__':
unittest.main()
细心的朋友可能会发现,在事务处理中,进行编辑操作以后,会执行缓存的清除操作,这是因为我们在ORM中所绑定的缓存自动清除操作,是在对应的执行方法中,而不是sql生成方法里,所以在进行事务时,如果你使用了缓存的方法,在这里就需要手动添加清除缓存操作,不然就会产生脏数据。
执行结果:
------ini------
select * from product_class where id = 1
----产品分类实体----
[{'add_time': datetime.datetime(2018, 8, 17, 16, 14, 54), 'id': 1, 'is_enable': 1, 'name': '饼干'}]
-------------------
update product_class set is_enable = 0 where id = 1 returning id , is_enable
----执行成功后的产品分类实体----
[{'id': 1, 'is_enable': 0}]
-------------------------------
update product set is_enable = 0 where product_class_id=1 returning id , is_enable
----执行成功后的产品实体----
[{'id': 2, 'is_enable': 0}, {'id': 7, 'is_enable': 0}, {'id': 14, 'is_enable': 0}, {'id': 15, 'is_enable': 0}]
---------------------------
执行成功
------clear------
本文对应的源码下载(一些接口进行了重构,有些还没有处理,所以源码可能直接运行不了,下一章节会讲到所有代码使用ORM模块重构内容)
版权声明:本文原创发表于 博客园,作者为 AllEmpty 本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。
python开发QQ群:669058475(本群已满)、733466321(可以加2群) 作者博客:http://www.cnblogs.com/EmptyFS/
我的第一个python web开发框架(32)——定制ORM(八)的更多相关文章
- 我的第一个python web开发框架(41)——总结
我的第一个python web开发框架系列博文从17年6.7月份开始写(存了近十章稿留到9月份才开始发布),到今天结束,一年多时间,想想真不容易啊. 整个过程断断续续,中间有段时间由于工作繁忙停了好长 ...
- 我的第一个python web开发框架(14)——后台管理系统登录功能
接下来正式进入网站的功能开发.要完成后台管理系统登录功能,通过查看登录页面,我们可以了解到,我们需要编写验证码图片获取接口和登录处理接口,然后在登录页面的HTML上编写AJAX. 在进行接口开发之前, ...
- 我的第一个python web开发框架(1)——前言
由于之前经验不是很丰富,写的C#系统太过复杂,所以一直想重写,但学的越多越觉得自己懂的越少,越觉的底气不足.所以一直不敢动手,在内心深处对自己讲,要静下心来认真学习,继续沉淀沉淀.这两年多以来找各种机 ...
- 我的第一个python web开发框架(3)——怎么开始?
小白与小美公司经过几次接触商谈,好不容易将外包签订了下来,准备开始大干一场.不过小白由于没有太多的项目经验,学过python懂得python的基本语法,在公司跟着大家做过简单功能,另外还会一些HTML ...
- 我的第一个python web开发框架(22)——一个安全小事故
在周末的一个早上,小白还在做着美梦,就收到了小美的连环追魂call,电话一直响个不停. 小白打着哈欠拿起电话:早上好美女. 小美:出事了出事了,我们公司网站一早访问是一片空白,什么内容都没有了,你赶急 ...
- 我的第一个python web开发框架(2)——一个简单的小外包
第一部分说明 第一部分大概有20来章,主要讲的是一些开发常识.开发前中后期准备内容.开发环境与服务器部署环境安装设置.python基础框架结构与功能等内容,代码会比较简单. 本系列会以故事的方式,向大 ...
- 我的第一个python web开发框架(6)——第一个Hello World
小白中午听完老菜讲的那些话后一直在思考,可想来想去还是一头雾水,晕晕呼呼的一知半解,到最后还是想不明白,心想:老大讲的太高深了,只能听懂一半半,看来只能先记下来,将明白的先做,不明白的等以后遇到再学. ...
- 我的第一个python web开发框架(7)——本地部署前端访问服务器
PS:本系列内容进度节奏会放的很慢,每次知识点都尽量少一点,这样大家接触的知识点少了,会更容易理解,因为少即是多.另外,对于后面代码部分,虽然尽量不用那些复杂的封装和类,但它并不表示看了就能全部记住, ...
- 我的第一个python web开发框架(10)——工具函数包说明(一)
PS:原先是想直接进入功能开发,要用到什么函数时再创建,这样也容易熟悉每个函数的由来和使用方法,但考虑到这样操作,到时会经常在不同文件间切换,不好描述,容易造成混乱,所以还是使用函数库这种方式来说明. ...
随机推荐
- java设计模式(1)---总则
设计模式总则 一.概述 1.什么是设计模式 设计模式是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结. 解释下: 分类编目:就是说可以找到一些特征去划分这些设计模式,从而进行分类. ...
- 在.net core上使用Entity FramWork(Db first)
在.net core中不可以向往常一样去直接可视化创建EF了,那我们可以通过命令安装 其依赖项有 Install-package Microsoft.EntityFrameworkCore Insta ...
- 说一说MVC的控制器(二)
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...
- influxdb使用说明
前言 influxdb是目前比较流行的时间序列数据库. 何谓时间序列数据库?什么是时间序列数据库,最简单的定义就是数据格式里包含Timestamp字段的数据,比如某一时间环境的温度,CPU的使用率等. ...
- 重磅!阿里巴巴工程师获得 containerd 社区席位,与社区共建云时代容器标准
重磅!阿里巴巴工程师获得 containerd 社区席位,与社区共建云时代容器标准 11 月 29 日,CNCF containerd 社区正式宣布:两位阿里巴巴工程师正式获得 containerd ...
- Docker Compose 简介
Compose 是 docker 提供的一个命令行工具,用来定义和运行由多个容器组成的应用.使用 compose,我们可以通过 YAML 文件声明式的定义应用程序的各个服务,并由单个命令完成应用的创建 ...
- demo_1
我练习的demo是基于SSM+MySQL+Eclipse+Tomcat8+Maven3实现的: 创建项目 ## 创建Maven Project: Artifact Id: cn.com.demo ...
- C#调用Oracle的存储过程时,连接字符串需要配置PLSQLRSet=1
C#调用Oracle的存储过程时, 如果有个SYS_REFCURSOR的Output参数存储时, web.config文件中的连接字符串需要配置PLSQLRSet=1, 否则可能会报这个错:参数个数或 ...
- jQuery中关于全选、全不选和反选
1.首先我们要获取当前点击的对象,然后得到点击事件, 判断他的状态如果是checked的话就把该第二行的选中, 否则就取消选中. 2.当第二列功能小项没有全部选中时,该行第一列的复选款也要取消 ...
- hive 中遇到的正则
1.提取科室中,"科"字前面的内容 regexp_extract(t1.doctor_department_format,'(.*)科') 2.去除字符串中的数字 第一种方式: S ...