java

位置:IT落伍者 >> java >> 浏览文章

Hibernate中inverse与cascade作用


发布日期:2021年05月07日
 
Hibernate中inverse与cascade作用

? hibernate如何根据pojo来更新数据库

在commit/flush之前hibernate不会对pojo对象作神秘的处理

在select查询出pojo时hibernate根据字段属性的对应关系用字段的值填充pojo的属性

然后根据关系标记生成sql语句从relationTable中查询出满足条件的relationPojo并把这些relatinPojo

放到关系属性这个过程是机械的

在pojo对象被查出来后到commit(或flush)之前它将是一个普通的java对象hibernate不会做额外的手脚

比如不会限制你设置一个属性的值为null或其它任何值

在集合类Set的add(object)操作时 不会改变object的值不会检查参数object是否是一个pojo对象

设置mainPojo的一个桥属性的值不会自动设置relationPojo的对应的桥属性的值

执行sessiondelete(pojo)时pojo本身没有变化他的属性值也没有变化

执行sessionsave(pojo)时如果pojo的id不是hibernate或数据库生成则它的值没有变化

如果pojo的id是hibernate或数据库生成则hibernate会把id给pojo设上去

extend: 对lazy=true的sethibernate在进行set的操作(调用javautilSet中声明的方法)时

会先inialize这个set仅此而已而inialize仅仅是从数据库中捞出set的数据

如果一个set已经被inialize了那么对它进行的操作就是javautilSet接口中定义的语义

另外如果id由hibernate来生成那么在save(pojo)时hibernate会改变该pojo会设置它的id

可能改变该pojo的hashCode详细地讨论见帖《》

mapping文件中标记的某些属性及pojo对象的操作会对数据库操作产生影响这些影响都是在commit时才会起作用

而在commit前pojo的状态不受它们的影响

不过待commit之时将由hibernate完全掌控它好像知道pojo对象从创建到commit这中间的所有变化

关联更新

关系标记对应的属性是一个pojo或一个pojo的集合修改关系属性的值能会导致更新mainTable表也可能会更新relationTable表

这种更新暂叫关联更新

inverse属性的作用(假定没有设置cascade属性)

只有集合标记(set/map/list/array/bag)才有inverse属性

————不妨以标记set为例具体为一个地区(Address表)的学校(School表) addressschoolSet

set的inverse属性决定是否把对set的改动反映到数据库中去

inverse=false————反映inverse=true————不反映

inverse属性默认为false

对<onetomany>和<manytomany>子标记这两条都适用

不管是对set做什么操作都适用

当inverse=false时hibernate如何将对set的改动反映到数据库中

对set的操作主要有)新增元素 addressgetSchoolSet()add(oneSchool);

)删除元素 addressgetSchoolSet()remove(oneSchool);

)删除set addresssetSchoolSet(null);

)设新set addresssetSchoolSet( newSchoolSet);

)转移set otherSchoolSet = otherAddressgetSchoolSet();

otherAddresssetSchoolSet(null);

addresssetSchoolSet(otherSchoolSet);

)改变set中元素的属性的值 如果是改变key属性这会导致异常

如果改变的是普通的属性则hibernate认为set没有变化(在后面可以看出缘由)

所以这种情形不予考虑

改变set后hibernate对数据库的操作根据是<onetomany>关系还是<manytomany>关系而有不同

对onetomany对school set的改动会改变表SCHOOL中的数据:

#SCHOOL_ID是school表的主键SCHOOL_ADDRESS是school表中的地址栏位

#表School的外键为SCHOOL_ADDRESS它对应表Address的主键ADDRESS_ID

)insert oneSchool———— sqlInsertRowString:

update SCHOOL set SCHOOL_ADDRESS=? where SCHOOL_ID=?

(仅仅update foreignkey的值)

)delete oneSchool———— sqlDeleteRowString:

update SCHOOL set SCHOOL_ADDRESS=null where SCHOOL_ID=?

(很奇怪把foreignkey设置为null不知道有什么实际意义?)

)delete 属于某一address的所有school ————sqlDeleteString

update SCHOOL set SCHOOL_ADDRESS=null where SCHOOL_ADDRESS=?

)update ————sqlUpdateRowString no need

对manytomany对school set的改动会改变关系表ADDRESS_SCHOOL中的数据:

#地区————学校的关系为多对多的关系有点牵强只是为了方便与上面的onetomany作比较

#假设有一个关系表ADDRESS_SCHOOL有两个字段ADDRESS_ID SCHOOL_ID

#这两个字段分别对应ADDRESS和SCHOOL两表的key

)insert的SQL语句为 insert into ADDRESS_SCHOOL(ADDRESS_ID SCHOOL_ID)

values(??)

)delete的SQL语句为 delete from ADDRESS_SCHOOL

where ADDRESS_ID=? AND SCHOOL_ID=?

)delete all的SQL语句为 delete from ADDRESS_SCHOOL

where ADDRESS_ID=?

)update的sql语句为 ————sqlUpdateRowString

update ADDRESS_SCHOOL set ADDRESS_ID=?

where ADDRESS_ID=? AND SCHOOL_ID=?

对set的操作()hibernate会执行()sqlInsertRowString

对set的操作()hibernate会执行()sqlDeleteRowString

对set的操作()hibernate会执行()sqlDeleteString

对set的操作()老的schoolSet因为没有所属的address所以被全部delete掉即先执行()sqlDeleteString

然后新增新的schoolSet即再执行sqlInsertRowString

对set的操作()实际上就是将set从一个pojo转移到另一pojo

首先执行sqlDeleteString删除掉otherAddress所属的school

然后执行sqlDeleteString删除掉address原先的school

最后执行sqlInsertRowString将otherSchoolSet新增给address

总结)对onetomany而言改变set会让hibernate执行一系列的update语句 不会delete/insert数据

)对manytomany而言改变set只修改关系表的数据不会影响manytomany的另一方

)虽然onetomany和manytomany的数据库操作不一样但目的都是一个维护数据的一致性执行的sql都

只涉及到桥字段不会考虑或改变其他的字段所以对set的操作()是没有效果地

extend:对list可能还会维护index字段

inverse与cascade没有什么关系互无牵扯

commit后这两个属性发挥作用的时机不同hibernate会根据对pojo对象的改动及cascade属性的设置

生成一系列的Action比如UpdateActionDeleteActionInsertAction等每个Action都有execute方法以执行对应的sql语句

待所有这些Action都生成好了后hibernate再一起执行它们在执行sql前inverse属性起作用

当inverse=true时不执行sql当inverse=false时执行sql

inverse的默认值为false所以inverse属性默认会进行关联更新

建议只对set + manytomany设置inverse=false其他的标记不考虑inverse属性

糟糕的是不设置inverse属性时inverse默认为false

级联(cascade)属性的作用

只有关系标记才有cascade属性manytooneonetoone any

set(map bag idbag list array) + onetomany(manytomany)

级联指的是当主控方执行操作时关联对象(被动方)是否同步执行同一操作

pojo和它的关系属性的关系就是主控方 被动方的关系如果关系属性是一个set那么被动方就是set中的一个一个元素

比如学校(School)有三个属性地区(Address)校长(TheMaster)和学生(Set 元素为Student)

执行sessiondelete(school)时级联决定是否执行sessiondelete(Address)sessiondelete(theMaster)

是否对每个aStudent执行sessiondelete(aStudent)

extend:这点和inverse属性是有区别的

一个操作因级联cascade可能触发多个关联操作前一个操作叫主控操作后一个操作叫关联操作

cascade属性的可选值

all : 所有情况下均进行关联操作

none所有情况下均不进行关联操作这是默认值

saveupdate:在执行save/update/saveOrUpdate时进行关联操作

delete在执行delete时进行关联操作

具体执行什么关联操作是根据主控操作来的

主控操作 关联操作

sessionsaveOrUpdate > sessionsaveOrUpdate (执行saveOrUpdate实际上会执行save或者update)

sessionsave > sessionsaveOrUpdate

sessionudpate > sessionsaveOrUpdate

sessiondelete > sessiondelete

主控操作和关联操作的先后顺序是先保存one再保存many先删除many再删除one先update主控方再update被动方

对于onetoone当其属性constrained=false(默认值)时它可看作onetomany关系

当其属性constrained=true它可看作manytoone关系

对manytomany它可看作onetomany

比如学校(School)有三个属性地区(Address)校长(TheMaster其constrained=false)和学生(Set 元素为Student)

当执行sessionsave(school)时

实际的执行顺序为sessionsave(Address);

sessionsave(school);

sessionsave(theMaster);

for( 对每一个student ){

sessionsave(aStudent);

}

当执行sessiondelete(school)时

实际的执行顺序为sessiondelete(theMaster);

for( 对每一个student ){

sessiondelete(aStudent);

}

sessiondelete(school);

sessiondelete(Address);

当执行sessionupdate(school)时

实际的执行顺序为sessionupdate(school);

sessionsaveOrUpdate(Address);

sessionsaveOrUpdate(theMaster);

for( 对每一个student ){

sessionsaveOrUpdate(aStudent);

}

注意update操作因级联引发的关联操作为saveOrUpdate操作而不是update操作

saveOrUpdate与update的区别是前者根据操作对象是保存了还是没有保存而决定执行update还是save

extends: 实际中删除学校不会删除地区即地区的cascade一般设为false

另外manytomany关系很少设置cascade=true而是设置inverse=false这个反映了cascade和inverse的区别

cascade的默认值为false所以inverse属性默认会进行关联更新

总结级联(cascade)就是操作一个对象时对它的属性(其cascade=true)也进行这个操作

inverse和cascade的比较

这两个属性本身互不影响但起的作用有些类似都能引发对关系表的更新

inverse只对set+onetomany(或manytomany)有效对manytoone onetoone无效

cascade对关系标记都有效

inverse对集合对象整体起作用cascade对集合对象中的一个一个元素起作用如果集合为空那么cascade不会引发关联操作

比如将集合对象置为null schoolsetStudentSet(null)

inverse导致hibernate执行:udpate STUDENT set SCHOOL_ID=null where SCHOOL_ID=?

cascade则不会执行对STUDENT表的关联更新 因为集合中没有元素

再比新增一个school sessionsave(school)

inverse导致hibernate执行

for( 对(school的每一个student ){

udpate STUDENT set SCHOOL_ID=? where STUDENT_ID=? //将学生的school_id改为新的school的id

}

cascade导致hibernate执行

for( 对school的每一个student ){

sessionsave(aStudent); //对学生执行save操作

}

extends:如果改变集合中的部分元素(比如新增一个元素)

inverse: hibernate先判断哪些元素改变了对改变的元素执行相应的sql

cascade: 它总是对集合中的每个元素执行关联操作

(在关联操作中hibernate会判断操作的对象是否改变)

两个起作用的时机不同

cascade在对主控方操作时级联发生

inverse: 在flush时(commit会自动执行flush)对session中的所有sethibernate判断每个set是否有变化

对有变化的set执行相应的sql执行之前会有个判断if( inverse == true ) return;

可以看出cascade在先inverse在后

inverse 对set + onetomany 和 set + manytomany 起的作用不同hibernate生成的sql不同

对onetomanyhibernate对many方的数据库表执行update语句

对manytomany hibernate对关系表执行insert/update/delte语句注意不是对many方的数据库表而是关系表

cascase 对set都是一致的不管onetomany还是manytomany都简单地把操作传递到set中的每个元素所以它总是更新many

方的数据库表

建议只对set + manytomany设置inverse=false其他的标记不考虑inverse属性都设为inverse=true

对cascade一般对manytoonemanytomanyconstrained=true的onetoone 不设置级联删除

上一篇:Eclipse 走上榜首 照亮Java众生

下一篇:struts分发请求的过程与相关配置