Python 如何从代码而不是数据库的角度主动避免重复行?
我得到了一个名为Python 如何从代码而不是数据库的角度主动避免重复行?,python,mysql,python-2.7,sqlalchemy,Python,Mysql,Python 2.7,Sqlalchemy,我得到了一个名为tb\u user\u grait的表,它保存了客户的头像,它的模式看起来很简单 CREATE TABLE `tb_user_portrait` ( id BIGINT NOT NULL AUTO_INCREMENT COMMENT 'primary key', user_id BIGINT NOT NULL DEFAULT 0 COMMENT 'custormer id', portrait_hash CHAR(255) NOT NULL DEFAULT
tb\u user\u grait
的表,它保存了客户的头像,它的模式看起来很简单
CREATE TABLE `tb_user_portrait` (
id BIGINT NOT NULL AUTO_INCREMENT COMMENT 'primary key',
user_id BIGINT NOT NULL DEFAULT 0 COMMENT 'custormer id',
portrait_hash CHAR(255) NOT NULL DEFAULT '' COMMENT 'portrait image hash',
is_valid TINYINT NOT NULL DEFAULT 1 COMMENT 'validation flag of this row',
primary key(id)
)
我没有设置任何唯一的密钥,因为客户可能会多次上传头像。但是,每个用户应该只有一个有效的肖像(即每个用户只能有一个is\u valid=1
记录)
我处理上传操作的代码也很简单
def upload(user_id, portrait_hash, is_valid=1):
# find the last is_valid=1 records, and set invalid
portrait = DBSession().query(UserPortrait).\
filter(UserPortrait.user_id == user_id).\
filter(UserPortrait.is_valid == 1).\
scalar()
if portrait:
portrait.is_valid = 0
DBSession().add(portrait)
# create new valid portrait and save it to db
new_portrait = UserPortrait(
user_id=user_id,
portrait_hash=portrait_hash,
is_valid=is_valid)
DBSession().add(new_portrait)
DBSession().commit()
虽然我首先找到了有效记录并将其设置为无效,但我总是遇到MultipleRowsFound
,并且数据库中有多个记录(is\u valid=1
)
顺便说一下,我使用了SQLAlchemy并打开了session.autoflush
我想知道为什么会这样?有什么最佳实践可以避免这种情况吗?来自SQLAlchemy:
autoflush–如果为True,则所有查询操作将在继续之前对此会话发出flush()调用。这是一个方便的特性,因此不需要重复调用flush(),数据库查询就可以检索结果。自动刷新通常与autocommit=False一起使用。在这种情况下,很少需要显式调用flush();通常只需调用commit()(刷新)即可完成更改
所以,基本上您不会将更改提交到数据库,这就是为什么它不起作用,并且您有多条记录is\u invalid=1
尝试手动操作,而不是打开会话。自动刷新,因此:
...
if portrait:
portrait.is_valid = 0
DBSession().add(portrait)
DBSession().flush() # <-- here
new_portrait = UserPortrait(
user_id=user_id,
portrait_hash=portrait_hash,
is_valid=is_valid)
...
只需使用:
DBSession().commit()
来自SQLAlchemy:
autoflush–如果为True,则所有查询操作将在继续之前对此会话发出flush()调用。这是一个方便的特性,因此不需要重复调用flush(),数据库查询就可以检索结果。自动刷新通常与autocommit=False一起使用。在这种情况下,很少需要显式调用flush();通常只需调用commit()(刷新)即可完成更改
所以,基本上您不会将更改提交到数据库,这就是为什么它不起作用,并且您有多条记录is\u invalid=1
尝试手动操作,而不是打开会话。自动刷新,因此:
...
if portrait:
portrait.is_valid = 0
DBSession().add(portrait)
DBSession().flush() # <-- here
new_portrait = UserPortrait(
user_id=user_id,
portrait_hash=portrait_hash,
is_valid=is_valid)
...
只需使用:
DBSession().commit()