初识Hibernate——关系映射
Hibernate的主要目的就是是Java程序员可以随心所欲的使用对象编程思维来操纵数据库。所以,一些数据库表的关系我们应该可以通过hibernate实现,比如在数据库中我们厂用的用到的主外键关系,还有一些跟主外键有关系的设置,比如主键的信息被删除,外键关联的信息也要删除等等,所以,Hibernate同样应该实现这种映射关系。
Hibernate映射的基本结构:
Hibernate在实现ORM功能的时候主要用到的文件有:映射类(*.java)、映射文件(*.hbm.xml)和数据库配置文件(*.properties/*.cfg.xml),它们各自的作用如下。
映射类(*.java):它是描述数据库表的结构,表中的字段在类中被描述成属性,将来就可以实现把表中的记录映射成为该类的对象了。
映射文件(*.hbm.xml):它是指定数据库表和映射类之间的关系,包括映射类和数据库表的对应关系、表字段和类属性类型的对应关系以及表字段和类属性名称的对应关系等。
数据库配置文件(*.properties/*.cfg.xml):它是指定与数据库连接时需要的连接信息,比如连接哪种数据库、登录数据库的用户名、登录密码以及连接字符串等。当然还可以把映射类的地址映射信息放在这里。
下面着重介绍关系映射:
一对一关联映射原理:让两个实体的主键一样,这样就不需要加入多余的字段了
<classname="com.bjpowernode.hibernate.Person"table="t_person"><idname="id"><!--采用foreign生成策略,forgeign会取得关联对象的标识 --><generatorclass="foreign"><!--property只关联对象 --><paramname="property">idCard</param></generator></id><propertyname="name"/><!--one-to-one指示hibernate如何加载其关联对象,默认根据主键加载也就是拿到关系字段值,根据对端的主键来加载关联对象 constrained="true表示,当前主键(person的主键)还是一个外键参照了对端的主键(IdCard的主键),也就是会生成外键约束语句 --><one-to-onename="idCard" constrained="true"/></class>
需要在IdCard加入<one-to-one>标签,指示hibernate将关联对象Person
根据主键加载上来
<one-to-one>不影响存储,只影响加载
一对一唯一外键关联映射其实是多对一的特例
采用<many-to-one>标签来映射,指定多的一端unique为true,这样就限制了多的一端的多重性
为一,就是这样来映射的。
一对多关联映射和多对一关联映射映射原理是一致的,都是在多的一端加入一个外键,指向一的一端
它们的区别在于维护的关系不同:
*多对一维护的关系是:多指向一的关系,有了此关系,在加载多的时候可以将一加载上来
*一对多维护的关系是:一指向多的关系,有了此关系,在加载一的时候可以将多加载上来
在一一端维护关系存在缺陷:
*因为多的一端Student不知道Classes的存在(也就是Student没有维护与Classes的关系)
所以在保存Student的时候关系字段classesid是为null的,如果将该关系字段设置为非空,则
将无法保存数据
*另外因为Student不维护关系,而Classes维护关系,Classes就会发出多余的update语句,保证
Classes和Student有关系,这样加载Classes的时候才可以把该Classes对应的学生加载上来
采用一对多双向关联映射的目的主要是为了主要是为了解决一对多单向关联的缺陷
而不是需求驱动的
一对多双向关联的映射方式:
*在一的一端的集合上采用<key>标签,在多的一端加入一个外键
*在多的一端采用<many-to-one>标签
!!!注意:<key>标签和<many-to-one>标签加入的字段保持一直,否则会产生数据混乱
inverse属性:
*inverse属性可以用在一对多和多对多双向关联上,inverse属性默认为false,为
false表示本端可以维护关系,如果inverse为true,则本端不能维护关系,会交给另一端
维护关系,本端失效。
所以一对多关联映射我们通常在多的一端维护关系,让一的一端失效,所以设置为inverse为true
inverse和cascade
*inverse是控制方向上的反转,只影响存储
*cascade是操作上的连锁反映
1.hibernate多对一关联映射
关联映射,就是将关联关系映射到数据库中,所谓的关联关系
在对象模型中就是一个或多个引用
多对一关联映射原理:在多的一端加入一个外键,指向一的一端
在多的一端采用如下标签映射:
<many-to-onename="group" column="groupid"/>
掌握级联的含义?
*级联是对象之间的连锁操作,它只影响添加、删除和修改
具体映射:
<setname="roles" table="t_user_role"><keycolumn="user_id"/><many-to-manyclass="com.bjpowernode.hibernate.Role"column="role_id"/> </set>
映射方法:
<setname="users" table="t_user_role"><keycolumn="role_id" not-null="true"/><many-to-manyclass="com.bjpowernode.hibernate.User"column="user_id"/></set>
需要注意:
*生成的中间表名称必须一样
*生成的中间表中的字段必须一样
关联小结:
通过对比发现,其实这些所谓的一对一、一对多、多对一、多对多,其实就是就是如果甲对乙,则甲维护(即在甲方处添加相应的维护字段),然后根据具体情况,是多少对多少,用相应的语句,所谓的双向,其实就是甲对乙成立,则乙对甲也成立,所以在甲乙双方都需要添加维护字段即可。
代码举例:
下面以双向一对多为例用代码具体说明:
Classes作为一方,先看classes的配置文件Classes.hbm.xml:
<hibernate-mapping><classname="com.bjpowernode.hibernate.Classes"table="t_classes"><idname="id"><generatorclass="native"/></id><propertyname="name"/><setname="students" inverse="true"><!--<keycolumn="classesid" not-null="true"/> --> <key column="classesid"/><one-to-manyclass="com.bjpowernode.hibernate.Student"/></set></class></hibernate-mapping>
如果是单向的一对多,则多的一方不需要维护,则代码为:
<hibernate-mapping><classname="com.bjpowernode.hibernate.Student"table="t_student"><idname="id"><generatorclass="native"/></id><propertyname="name"/></class></hibernate-mapping>
可是这里是双向,也就是班级对完学生,还需要学生对班级,学生对班级,其实就是多对一,所以我们发现双向一对多在多的一方用到的是many-to-one 标签:
<hibernate-mapping><classname="com.bjpowernode.hibernate.Student"table="t_student"><idname="id"><generatorclass="native"/></id><propertyname="name"/><many-to-onename="classes" column="classesid"/></class></hibernate-mapping>
其实总得下面,双向一对多其实就是单向一对多加上单向多对一,所以,在我们看来的这么多的关系中,其实只有一个原则,甲对乙则甲维护,所谓的双向,只是两个单向的组合。
运行结果:
在关联映射中,我们经常会用到一些级联策略,下面介绍一下:
在Many与One的关系中,级联策略很重要,这关系着效率与完整性等问题。
在<set>、<many-to-one>、<one-to-one>元素中都有一个cascade属性,它用于指定如何操纵与当前对象关联的其他对象。cascade有如下几个可选属性值:
none:是默认值,在保存、更新、删除当前对象时,忽略其他关联对象。
save-update:当通过Session的save()、update()和saveOrUpdate()保存或更新对象时,级联保存所有关联的新建的临时对象,并且级联更新所有关联的游离对象。
delete:当通过Session的delete()删除当前对象时,级联删除所有关联对象。
all:包含save-update和delete的行为。此外,当对当前对象执行evict()或lock()操作时,也会对所有级联的持久化对象执行evict和lock操作。
delete-orphan:删除所有和当前对象接触关联关系的对象。
all-delete_orphan:包含all和delete-orphan的行为。
好了,现在的关系映射就差不错都介绍完了,其实从关系映射的各种关系我们也可以发现,其实映射的宗旨很简单,他指哪儿你就映射哪儿,不用去想什么所谓的哪一种映射对应的哪一条语句,由此我们也可以想到,其实对于一些符合主键映射、继承映射也是一样的,符合主键映射一定是在符合主键的地方加关键字,而继承映射肯定是处理继承的类,但是我们需要考虑到继承一般有好几个对象,这几个对象是放在一张表里还是分开放,剩下的用相应的字段处理就好了,所以,大道至简应该就是这个道理,看似复杂的关系,其实都是尊崇一个道理,然后开始延伸,如果明白这个道理,所以的事情就会变得十分简单了。