数据库级联删除怎么实现?

数据库级联删除怎么实现?,第1张

可以用下边的方法,仅供参考:

-- 创建测试主表. ID 是主键.

CREATE TABLE test_main (

id INT NOT NULL,

value VARCHAR(10),

PRIMARY KEY(id)

)

-- 创建测试子表.

CREATE TABLE test_sub (

id INT NOT NULL,

main_id INT ,

value VARCHAR(10),

PRIMARY KEY(id)

)

-- 插入测试主表数据.

INSERT INTO test_main(id, value) VALUES (1, 'ONE')

INSERT INTO test_main(id, value) VALUES (2, 'TWO')

-- 插入测试子表数据.

INSERT INTO test_sub(id, main_id, value) VALUES (1, 1, 'ONEONE')

INSERT INTO test_sub(id, main_id, value) VALUES (2, 2, 'TWOTWO')

然后,创建外键,使用 ON DELETE CASCADE 选项,删除主表的时候,同时删除子表

ALTER TABLE test_sub ADD CONSTRAINT main_id_cons FOREIGN KEY (main_id) REFERENCES test_main ON DELETE CASCADE

执行删除:

DELETE FROM TEST_MAIN WHERE ID = 1

最后:

SELECT * FROM TEST_MAIN

结果子表中就只有ID=2的记录,也就说明级联删除成功。

级联删除你可以把它认为是一个触发器,也就是你删除主表中的数据,那么从表中的相关联的也就一起删除了。。。看个例子:======================create table a\x0d\x0a(\x0d\x0aid varchar(20) primary key,\x0d\x0apassword varchar(20) not null\x0d\x0a)\x0d\x0a\x0d\x0acreate table b\x0d\x0a(\x0d\x0aid int identity(1,1) primary key,\x0d\x0aname varchar(50) not null,\x0d\x0auserId varchar(20),\x0d\x0aforeign key (userId) references a(id) on delete cascade\x0d\x0a)\x0d\x0a表B创建了外码userId 对应A的主码ID,声明了级联删除\x0d\x0a测试数据:\x0d\x0ainsert a values ('11','aaa')\x0d\x0ainsert a values('23','aaa')\x0d\x0ainsert b values('da','11')\x0d\x0ainsert b values('das','11')\x0d\x0ainsert b values('ww','23')\x0d\x0a删除A表内id为‘11’的数据,发现B表内userId 为“11”也被数据库自动删除了,这就是级联删除\x0d\x0adelete a where id='11'=============================================================级联更新也大同小异。。只是关键字为:on update希望回答对你有所帮助........

有两张表 结构如下

Java代码

t_item                           t_bid

id        int                     id        int

name    varchar                   name      varchar

item_id   int

其中表t_item的主键id是表t_bid的item_id字段的外键 那么在这种情况下 如果删除表t_item中的记录 并且该记录中的id主键被t_bid中的item_id字段所引用 就会抛出如下异常

Java代码

ERROR ( ): Cannot delete or update a parent row: a foreign key constraint fails (`test/t_bid` CONSTRAINT `fk_id` FOREIGN KEY (`id`) REFERENCES `t_item

` (`id`))

解决方法 级联删除 即在删除t_item表中的记录时同时删除t_bid表中的相关记录

( ) 增加外键约束时声明级联删除 即

Java代码

alter table t_bid add constraint fk_id foreign key(id) references

key(id) on delete cascade

( ) 使用触发器 在删除t_item表中记录之前先删除与之相关的t_bid表中的记录

触发器代码(MySQL)

Java代码

delimiter //

create trigger tri_delete before delete on t_item

for each row

begin

delete from t_bid where id = old id

end //

Hibernate中的解决方案

这个问题在Hibernate中相对容易解决 只需设置cascade = delete 即可 此时观察发出的sql语句

Java代码

Hibernate: select item _ id as id _ _ item _ name as name _ _ from t_item item _ where item _ id=?

Hibernate: select em_id as item _ _ bids _ id as id _ bids _ id as id _ _ bids _ price as price _ _ em_id as item _ _ _ from t_bid bids _ where em_id=?

Hibernate: update t_bid set item_id=null where item_id=?

Hibernate: delete from t_bid where id=?

Hibernate: delete from t_bid where id=?

Hibernate: delete from t_item where id=?

发现在删除t_bid表中记录之前会先将它的item_id字段值设置为null 但如果我们在映射文件中设置item_id字段不能为null 即设置Bid hbm xml文件为 Java代码

<many to one name= item column= item_id class= po Item not null= true />

注意不能在Item hbm xml文件中进行如下设置(即在key元素中指定not null= true )

Java代码

<set name= bids cascade= all >

<key column= item_id not null= true />

<one to many class= po Bid />

</set>

这样会抛出 Repeated column in mapping for entity 异常

如果我们指定item_id字段值不能为null 那么在删除时会抛出如下异常

Java代码

hibernate exception GenericJDBCException: Could not execute JDBC batch update···

Caused by: java sql BatchUpdateException: Data truncation: Column set to default valueNULL supplied to NOT NULL column item_id at row

???

此时的解决方法是设置inverse= true 这在Hibernate文档中有相应的描述 Java代码

Very Important Note: If the <key>column of a <one to many>association is declared NOT NULL Hibernate may cause constraint violations when it creates or updates the association To prevent this problem you must use a bidirectional association with the many valued end (the set or bag) marked as inverse= true

观察此时发出的sql语句

Java代码

Hibernate: select item _ id as id _ _ item _ name as name _ _ from t_item item _ where item _ id=?

Hibernate: select em_id as item _ _ bids _ id as id _ bids _ id as id _ _ bids _ amount as amount _ _ em_id as item _ _ _ from t_bid bids _ where em_id=?

Hibernate: delete from t_bid where id=?

Hibernate: delete from t_bid where id=?

Hibernate: delete from t_item where id=?

没有发出update语句 关于inverse= true 的理解

save update: 级联保存(load以后如果子对象发生了更新 也会级联更新) 但它不会级联删除

delete: 级联删除 但不具备级联保存和更新

all delete orphan: 在解除父子关系时 自动删除不属于父对象的子对象 也支持级联删除和级联保存更新

all: 级联删除 级联更新 但解除父子关系时不会自动删除子对象

delete orphan:删除所有和当前对象解除关联关系的对象

注意 以上设在哪一段就是指对哪一端的 *** 作而言 比如delete 如果设在one的一端的<set>属性里 就是当one被删除的时候 自动删除所有的子记录

如果设在many一端的<many to one>标签里 就是在删除many一端的数据时 会试图删除one一端的数据 如果仍然有many外键引用one 就会报 存在子记录 的错误 如果在one的一端同时也设置了cascade= delete 属性 就会发生很危险的情况 删除many一端的一条记录 会试图级联删除对应的one端记录 因为one也设置了级联删除many 所以其他所有与one关联的many都会被删掉

所以 千万谨慎在many一端设置cascade= delete 属性

故此cascade一般用在<one to one>和<one to many>中

one to many中设置级联删除 比如:

[x]

<set

name= entryvalues

lazy= false

inverse= true

order by= VALUEID

cascade= all delete orphan

>

<key>

<column name= CONTEXTENTRYID />

</key>

<one to many

class= Entryvalue

/>

</set>

如果用Hiberante的SchemaExport导出表到数据库 是不会在数据库中设置外键的cascade属性的 查看ENTRYVALUE表 其中的外键CONTEXTENTRYID的on delete属性是no action

但是使用Hiberante管理事务 它是会维护这种级联关系的 比如这样 *** 作:

[java]

public void testCascadeDelete() {

Session s = HibernateUtil getSession()

Transaction tx

try {

tx = s beginTransaction()

Contextentry ce = (Contextentry)s load(Contextentry class new Long( ))

s delete(ce)

mit()

} catch (HibernateException e) {

// TODO Auto generated catch block

e printStackTrace()

}

}

则引用此Contextentry的Entryvalue是会被正确级联删除的

如果使用普通JDBC *** 作 比如:

[java]

public void testCascadeDeleteSQL() {

Session s = HibernateUtil getSession()

Transaction tx

String sql = delete contextentry where id=

try {

tx = s beginTransaction()

Connection con = nnection()

Statement st = con createStatement()

st execute(sql)

mit()

} catch (HibernateException e) {

// TODO Auto generated catch block

e printStackTrace()

} catch (SQLException e) {

// TODO Auto generated catch block

e printStackTrace()

}

}

则会报 存在子记录 的错误 这里的Transaction实际上是无效的 因为用的是JDBC的Connection和Statement 已经脱离了Hibernate的管理 如果手动将ENTRYVALUE表的相关外键ON DELETE属性设为CASCADE 则上面的 *** 作当然正确执行——级联删除子记录

all delete-orphan 的能力

当保存或更新父方对象时 级联保存或更新所有关联的子方对象 相当于 cascade 为 save update

当删除父方对象时 级联删除所有关联的子方对象 相当于 cascade 为 delete

删除不再和父方对象关联的所有子方对象 当然 不再和父方对象关联的所有子方对象 必须是在本次事务中发生的

解除父子关系的 java 语句例如

[java]

public void testCascadeDelete() {

Session s = HibernateUtil getSession()

Transaction tx

try {

tx = s beginTransaction()

Contextentry ce = (Contextentry)s load(Contextentry class new Long( ))

Entryvalue ev = (Entryvalue)s load(Entryvalue class new Long( ))

ev setContextentry(null)

s delete(ce)

mit()

} catch (HibernateException e) {

// TODO Auto generated catch block

e printStackTrace()

}

}

如果 cascade 属性取默认值 null 当解除父子关系时 会执行如下 sql

update ENTRYVALUE set CONTEXTENTRYID=null where ID=

lishixinzhi/Article/program/Java/ky/201311/28140


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/sjk/9427762.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-28
下一篇2023-04-28

发表评论

登录后才能评论

评论列表(0条)

    保存