关闭

<三>重温Hibernate one to many 映射配置

467人阅读 评论(0) 收藏 举报
分类:

多对一关联映射:在多的一端加入一个外键指向一的一端,它维护的关系是多指向一
一对多关联映射:在多的一端加入一个外键指向一的一端,它维护的关系是一指向多

也就是说一对多和多对一的映射策略是一样的,只是站的角度不同


用户表:

CREATE TABLE `tbl_user` 

(`id` INT(32) NOT NULL AUTO_INCREMENT,`user_name` VARCHAR(20) NULL DEFAULT NULL,

`password` VARCHAR(20) NULL DEFAULT NULL,PRIMARY KEY (`id`)

)

银行卡表:

CREATE TABLE `tbl_bank` 

(`id` INT(10) NOT NULL AUTO_INCREMENT,`bank_card` VARCHAR(50) NULL DEFAULT NULL,

`user_id` INT(10) NULL DEFAULT '0',PRIMARY KEY (`id`),

INDEX `FK__tbl_user` (`user_id`),

CONSTRAINT `FK__tbl_user` FOREIGN KEY (`user_id`) REFERENCES `tbl_user` (`id`) ON UPDATE CASCADE ON DELETE CASCADE

)


1.单向一对多:只需在放进行配置

public class Users {

private int id;

private String userName;

private String password;

private Set<Bank> bank=new HashSet<Bank>();

}

<hibernate-mapping>

<class name="wb.wk.review.mapping.onetomany.sigenlMapping.Users" table="tbl_user">

<id name="id" column="id" type="java.lang.Integer">

<generator class="identity"></generator>

</id>

<property name="userName" type="java.lang.String" column="user_name"/>

<property name="password" type="java.lang.String" column="password"/>

<!-- 一对多单向关联 -->

<set name="bank" table="tbl_bank" cascade="all" inverse="false">

<key column="user_id" /><!-- 确定关联的外键列 -->

            <one-to-many class="wb.wk.review.mapping.onetomany.sigenlMapping.Bank"/>

</set>

</class>

</hibernate-mapping>

public class Bank {

private int id;

private String bankCard;

private int userId;//不是users对象

}

<hibernate-mapping>

<class name="wb.wk.review.mapping.onetomany.sigenlMapping.Bank" table="tbl_bank">

<id name="id" column="id" type="java.lang.Integer">

<generator class="identity"></generator>

</id>

<property name="bankCard" type="java.lang.String" column="bank_card"/>

<!-- 一对多单向关联 -->

<!--外键-->

<property name="userId" type="java.lang.Integer" column="user_id"/>

</class>

</hibernate-mapping>

运行出现异常:

org.hibernate.exception.ConstraintViolationException:  could not insert: [wb.wk.review.mapping.onetomany.sigenlMapping.Bank]

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException

Cannot add or update a child row: a foreign key constraint fails

 (`ppi`.`tbl_bank`, CONSTRAINT `FK_tbl_bank_tbl_user` FOREIGN KEY (`user_id`) REFERENCES `tbl_user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE)

 

一看就是外键的问题。查了半天,也看了hibernate文档,没有针对外键这一块的解释。但是两张表必须通过外键关联啊。最后删除了外键约束。插入成功。不知道咋回事。

Hibernate: 

    insert  intotbl_user (user_name, password) values(?, ?)

Hibernate: 

    insert  intotbl_bank(bank_card, user_id) values(?, ?)

Hibernate: 

insert  intotbl_bank(bank_card, user_id) values(?, ?)

Hibernate: 

    insert  intotbl_bank(bank_card, user_id) values(?, ?)

 

Hibernate: 

update tbl_bank set  user_id=? where  id=?

Hibernate: 

    update tbl_bank set  user_id=? where  id=?

 

Hibernate: 

    update tbl_bank set  user_id=? where  id=?

总结:另外要注意inverse属性,当时我设置了true,维护段就交给"一"端user了,结果插入时候先插入bank,后插入user,bank获取不到user_id

就出错了。



 

2.双向一对多:

一是关系维护端(owner side),多是关系被维护端(inverse side

需要在关联双方都加以配置,而且需要在一的一方设置inverse=true

 

public class Bank {

private int id;

private String bankCard;

private Users users;

}


Bank xml

<hibernate-mapping>

<class name="wb.wk.review.mapping.onetomany.bean.Bank" table="tbl_bank">

<id name="id" column="id" type="java.lang.Integer">

<generator class="identity"></generator>

</id>

<property name="bankCard" type="java.lang.String" column="bank_card"/>

<many-to-one name="users" class="wb.wk.review.mapping.onetomany.bean.Users" column="user_id"></many-to-one>

</class>

</hibernate-mapping>

 

public class Users {

private int id;

private String userName;

private String password;

private Set<Bank> bank;

}

User xml

<hibernate-mapping>

<class name="wb.wk.review.mapping.onetomany.bean.Users" table="print_user">

<id name="id" column="id" type="java.lang.Integer">

<generator class="identity"></generator>

</id>

<property name="userName" type="java.lang.String" column="user_name"/>

<property name="password" type="java.lang.String" column="password"/>

<set name="bank" table="tbl_bank" cascade="all">

<key column="user_id" /><!-- 确定关联的外键列 -->

            <one-to-many class="wb.wk.review.mapping.onetomany.bean.Bank" />

</set>

</class>

</hibernate-mapping>

测试的main方法:

Session session=null;

Transaction tran=null;

try {

session=HibernateSessionFactory.getSession();

tran=session.beginTransaction();

Users users=new Users();

users.setUserName("lko");

users.setPassword("1213456");

Set<Bank> bakSet=new HashSet<Bank>();

Bank b1=new Bank();

b1.setBankCard("s_001");

b1.setUsers(users);

Bank b2=new Bank();

b2.setBankCard("s_002");

b2.setUsers(users);

Bank b3=new Bank();

b3.setBankCard("s_003");

b3.setUsers(users);

bakSet.add(b1);

bakSet.add(b2);

bakSet.add(b3);

users.setBank(bakSet);

session.save(users);

tran.commit();

catch (HibernateException e) {

tran.rollback();

e.printStackTrace();

}finally{

session.flush();

session.close();

}

出现异常:

null id in wb.wk.review.mapping.onetomany.bean.Users entry (don't flush the Session after an exception occurs)

原因:

这个异常原因很多,这块主要是我没有设置外键(外键约束因为单向一对多的时候报错给在删除了),

设置后插入数据成功。

执行如下sql语句:

Hibernate: 

    insert into tbl_user(user_name, password) values (?, ?)

Hibernate: 

    insert into tbl_bank(bank_card, user_id) values (?, ?)

Hibernate: 

    insert  into tbl_bank (bank_card, user_id) values (?, ?)

Hibernate: 

    insert into tbl_bank (bank_card, user_id) values  (?, ?)

Hibernate: 

    update tbl_bank set user_id=? where  id=?

Hibernate: 

    update tbl_bank set  user_id=?  where id=?

Hibernate: 

Update tbl_bank  set user_id=? Where id=?

 

如果在“一”的一方在加上:inverse="true",如下:

<set name="bank" table="tbl_bank" cascade="all" inverse="true">

<key column="user_id" /><!-- 确定关联的外键列 -->

            <one-to-many class="wb.wk.review.mapping.onetomany.bean.Bank"/>

</set>

运行main方法:

Hibernate: 

    insert into tbl_user(user_name, password) values (?, ?)

Hibernate: 

    insert into tbl_bank(bank_card, user_id) values (?, ?)

Hibernate: 

    insert  into tbl_bank (bank_card, user_id) values (?, ?)

Hibernate: 

insert into tbl_bank (bank_card, user_id) values  (?, ?)

发现update语句没了。

这是因为:在一对多中,如果要""方维护关系,就会在插入或是删除""方时去update""方的每一个与这个""的对象有关系的对象。
而如果让"方面维护关系时就不会有update操作,因为关系就是在多方的对象中的,直指插入或是删除多方对象就行了。
当然这时也要遍历""方的每一个对象显示的操作及关系的变化体现到DB中。不管怎样说,还是让""方维护关系更直观一些。

关于inverse的作用

在hibernate中是通过inverse的设置来决定是有谁来维护表和表之间的关系的。

我们说inverse设立不当会导致性能低下,其实是说inverse设立不当,会产生多余重复的SQL语句甚至致使JDBC exception的throw。这是我们在建立实体类关系时必须需要关注的地方。一般来说,inverse=true是推荐使用,双向关联中双方都设置 inverse=false的话,必会导致双方都重复更新同一个关系。但是如果双方都设立inverse=true的话,双方都不维护关系的更新,这也是 不行的,好在一对多中的一端:many-to-one默认是inverse=false,避免了这种错误的产生。但是多对多就没有这个默认设置了,所以很 多人经常在多对多的两端都使用inverse=true,结果导致连接表的数据根本没有记录,就是因为他们双分都没有责任维护关系。所以说,双向关联中最 好的设置是一端为inverse=true,一端为inverse=false。一般inverse=false会放在多的一端,那么有人提问了, many-to-many两边都是多的,inverse到底放在哪儿?其实hibernate建立多对多关系也是将他们分离成两个一对多关系,中间连接一个连接表。所以通用存在一对多的关系,也可以这样说:一对多是多对多的基本组成部分。

 

 

 

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:24307次
    • 积分:511
    • 等级:
    • 排名:千里之外
    • 原创:21篇
    • 转载:37篇
    • 译文:0篇
    • 评论:4条
    最新评论