彻底明白Hibernate中的Inverse。
以前写HBM,用一对多或多对多的时候默认总是加上“inverse=true”。当时想法很简单就是由双方来维护之间的关联关系。今天才终于明白inverse的真正含义了!
(1)其实inverse不复杂,但是要真正明白还是要稍微看一下源码。inverse的真正作用就是指定由哪一方来维护之间的关联关系。当一方中指定了“inverse=false”(默认),那么那一方就有责任负责之间的关联关系,说白了就是hibernate如何生成Sql来维护关联的记录!举个最简单的一对多父子关系。那么代码就写成:
父亲中的关系映射 {set name=”children” lazy=”true” inverse=”true”} {key column=”parent_id”/} {on
儿子中关系映射 {many-to-on
Parent p = new Parent(); Child c = new Child(); c.setParent(p); //维护父子之间关系 p.getChildren().add(c);
session.save(p); session.flush();
注意:{many-to-on
这样运行的下来的结果就是:
Hibernate: insert into parent (id) values (?) Hibernate: insert into child (parent_id, id) values (?, ?)
那么假如c.setParent(p)注释掉,结果就是:
Hibernate: insert into parent (id) values (?)
比较结果显而易见!此外,inverse还有一个重要特点就是会优化Sql。(具体可以把SHOW_SQL这个属性打开,然后观察一下就知道了)
(2)接下来再看看update,还是父子的例子:
Parent p = (Parent) session.load(Parent.class, parentId); Parent p2 = (Parent) session.load(Parent.class, parentId2); c = (Child) session.find( “from Child as child where child.parent = ?”, p, Hibernate.entity(Parent.class)).get(0);
// 改变儿子c的关系 p.getChildren().remove(c); p2.getChildren().add(c); c.setParent(p2);
这样运行下来的结果就是:
Hibernate: select parent0_.id as id from parent parent0_ where parent0_.id=? //get parent 1 Hibernate: select parent0_.id as id from parent parent0_ where parent0_.id=? //get parent 2 Hibernate: select child0_.id as id, child0_.parent_id as parent_id from child child0_ where (child0_.parent_id=? )
Hibernate: select child0_.id as id__, child0_.id as id, child0_.parent_id as parent_id from child child0_ where child0_.parent_id=? Hibernate: select child0_.id as id__, child0_.id as id, child0_.parent_id as parent_id from child child0_ where child0_.parent_id=?
Hibernate: update child set parent_id=? where id=?(正确更新了)
那么根据上面的结论,关系应该是由“inverse=false”方来维护的,那么我把代码改成:
Parent p = (Parent) session.load(Parent.class, parentId); Parent p2 = (Parent) session.load(Parent.class, parentId2); c = (Child) session.find( “from Child as child where child.parent = ?”, p, Hibernate.entity(Parent.class)).get(0);
//p.getChildren().remove(c); //p2.getChildren().add(c); c.setParent(p2);
这样运行下来的结果:
Hibernate: select parent0_.id as id from parent parent0_ where parent0_.id=? //get parent 1 Hibernate: select parent0_.id as id from parent parent0_ where parent0_.id=? //get parent 2 Hibernate: select child0_.id as id, child0_.parent_id as parent_id from child child0_ where (child0_.parent_id=? )
Hibernate: update child set parent_id=? where id=?
比较结果很明显,少了父加载儿子的过程,乍看下是成功更新了。实际上,结果和DB是不一致的。(原因很简单就是父亲p的children并没有被更新)
那么反过来改一下:
Parent p = (Parent) session.load(Parent.class, parentId); Parent p2 = (Parent) session.load(Parent.class, parentId2); c = (Child) session.find( “from Child as child where child.parent = ?”, p, Hibernate.entity(Parent.class)).get(0);
p.getChildren().remove(c); p2.getChildren().add(c); //c.setParent(p2);
这样结果就成了:
Hibernate: select parent0_.id as id from parent parent0_ where parent0_.id=? //get parent 1 Hibernate: select parent0_.id as id from parent parent0_ where parent0_.id=? //get parent 2 Hibernate: select child0_.id as id, child0_.parent_id as parent_id from child child0_ where (child0_.parent_id=? ) //get children
Hibernate: select child0_.id as id__, child0_.id as id, child0_.parent_id as parent_id from child child0_ where child0_.parent_id=? Hibernate: select child0_.id as id__, child0_.id as id, child0_.parent_id as parent_id from child child0_ where child0_.parent_id=?
显而易见,关联更新没有被执行(更新是由“inverse=false”方负责的,而这里恰恰被注释了)。
(3)