数据库级联操作mysql_数据库进阶实践-级联操作 --

数据库进阶实践

级联操作

Cascade意为“级联操作”,就是在操作一个对象的同时,对相关的对象也执行某些操作。我们通过一个Post模型和Comment模型来演示级联操作,分别表示文章(帖子)和评论,两者是一对多关系:

classPost(db.Model):

id= db.Column(db.Integer, primary_key =True)

title= db.Column(db.String(50), unique =True)

body=db.Column(db.Text)

comments= db.relationship('Comment', back_populates = 'post')classComment(db.Model):

id= db.Column(db.Integer, primary_key =True)

body=db.Column(db.Text)

post_id= db.Column(db.Integer, db.ForeignKey('post.id'))

post= db.relationship('Post', back_populates = 'comments')

级联行为通过关系函数relationship()的cascade参数设置。我们希望在操作Post对象时,处于附属地位的Comment对象也被相应执行某些操作,这时应该在Post类的关系函数中定义级联参数。设置了cascade参数的一侧将被视为父对象,相关的对象则被视为子对象。

cascade通常使用多个组合值,级联值之间使用逗号分隔,比如:

classPost(db.Model):

comments= db.relationship('Comment', cascade = 'save-update, merge,delete',back_populates = 'post')

常用的配置组合如下所示:

1)      save-update、merge(默认值)

2)      save-update、merge、delete

3)      all

4)      all、delete-orphan

当没有设置cascade参数时,会使用默认值save-upgrate、merge。上面的all等同于除了delete-orphan以外所有可用值的组合,即save-update、merge、refresh-expire、expunge、delete。

下面介绍常用的几个级联值:

1、save-update

save-update是默认的级联行为,当cascade参数设为save-update时,如果使用db.session.add()方法将Post对象添加到数据库会话时,那么与Post相关联的Comment对象也将被添加到数据库会话。我们首先创建一个Post对象和两个Comment对象:

>>> post =Post()>>> comment1 =Comment()>>> comment2 =Comment()

将post1添加到数据库会话后,只有post1在数据库会话中:>>>db.session.add(post)>>> post indb.session

True>>> comment1 indb.session

False>>> comment2 indb.session

False

如果我们让post1与这两个Comment对象建立关系,那么这两个Comment对象也会自动被添加到数据库会话中:>>>post.comments.append(comment1)>>>post.comments.append(comment2)>>> comment1 indb.session

True>>> comment2 indb.session

True

当调用db.session.commit()提交数据库会话时,这三个对象都会被提交到数据库中。

2、delete

如果某个Post对象被删除,那么按照默认的行为,该Post对象相关联的所有Comment对象都将与这个Post对象取消关联,外键字段的值会被清空。如果Post类的关系函数中cascade参数设为delete时,这些相关的Comment会在关联的Post对象删除时一并删除,当需要设置delete级联时,我们会将级联值设为all或save-update、merge、delete,比如:

classPost(db.Model):

id= db.Column(db.Integer, primary_key =True)

title= db.Column(db.String(50), unique =True)

body=db.Column(db.Text)

comments= db.relationship('Comment',cascade = 'all', back_populates = 'post')

我们先创建一个文章对象post2和两个评论对象comment3和comment4,并将这两个评论对象与文章对象建立关系,将它们添加到数据库会话并提交:

>>> comment3 = Comment(body = 'very good')>>> comment4 = Comment(body = 'excellent')>>> post2 = Post(title = 'i have a good plan', body = 'tomorrow i will go to climbing')>>>post2.comments.append(comment3)>>>post2.comments.append(comment4)>>>db.session.add(post2)>>> db.session.commit()

现在共有两条Post记录和四条Comment记录:

>>>Post.query.all()

[, ]>>>Commment.query.all()

Traceback (most recent call last):

File"", line 1, in NameError: name'Commment' is notdefined>>>Comment.query.all()

[, , , ]

如果删除文对象Post2,那么对应的两个评论对象也会一并被删除:

>>> post = Post.query.get(2)>>>post

>>>db.session.delete(post)>>>db.session.commit()>>>Post.query.all()

[]>>>Comment.query.all()

[, ]

3、delete-orphan

这个模式是基于delete级联的,必须和delete级联一起使用,通常会设为all、delete-orphan,因为all包含delete。因此当cascade参数设为delete-orphan时,它首先包含delete级联的行为:当某个Post对象被删除时,所有相关的Comment对象都将被删除(delete级联)。除此之外,当某个Post对象(父对象)与某个Comment对象(子对象)解除关系时,也会删除该Comment对象,这个解除关系的对象被称为鼓励对象(orphan object),现在comments属性中的级联值为all、delete-orphan,如下所示:

classPost(db.Model):

id= db.Column(db.Integer, primary_key =True)

title= db.Column(db.String(50), unique =True)

body=db.Column(db.Text)

comments= db.relationship('Comment',cascade = 'all, delete-orphan', back_populates = 'post')

我们先创建一个文章对象post3和两个评论对象comment5和comment6,并将这两个评论对象与文章对象建立关系,将他们添加到数据库会话并提交:

>>> post3 =Post()>>> post3 = Post(title = 'today learn python', body = 'python include class and object')>>> comment5 = Comment(body = 'i also wanna learn python')>>> comment6 = Comment(body = 'python is easy to learn, but you have to pay your time every day')>>>post3.comments.append(comment5)>>>post3.comments.append(comment6)>>>db.session.add(post3)>>>db.session.commit())

File"", line 1db.session.commit())^SyntaxError: invalid syntax>>> db.session.commit()

现在数据库中有两条文章记录和四条评论记录:

>>>Post.query.all()

[, ]>>>Comment.query.all()

[, , , ]

下面我们将comment5和comment6与post3解除关系并提交数据库会话:>>>post3.comments.remove(comment5)>>>post3.comments.remove(comment6)>>> db.session.commit()

默认情况下,相关评论对象的外键会被设为空值。因为我们设置了delete-orphan级联,所以现在你会发现解除关系的两条评论记录都被删除了:

>>>Comment.query.all()

[, ]

delete和delete-orphan通常会在一对多关系模式中,而且“多”这一侧的对象附属于“一”这一侧的对象时使用。尤其是如果“一”这一侧的“父”对象不存在了,那么“多”这一侧的“子”对象不再有意义的情况。比如,文章和评论的关系就是一个典型的示例。当文章被删除了,那么评论也就没必要在留存。在这种情况下,如果不使用级联操作,那么我们就需要手动迭代关系另一侧的所有评论对象,然后一一进行删除操作。

对于这两个级联选项,如果你不会通过列表语义对集合关系属性调用remove()方法等方式来操作关系,那么使用delete级联即可。

虽然级联操作方便,但是容易带来安全隐患,因此要谨慎使用。默认值能够满足大部分情况,所以最好仅在需要的时候才修改它。

在SQLAlchemy中,级联的行为和配置选项等最初衍生自另一个ORM—Hibernate ORM。如果对这部分内容感到困惑,那么引用SQLAlchemy文档中关于Hibernate文档的结论:“The sections we have just covered can be a bit confusing.However, in practice, it all works out nicely. (我们刚刚介绍的这部分内容可能会有一些让人困惑,不过在实际使用中,他们都会工作的很顺利)”

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值