关系映射
对象中的关系映射有如下四种,而且分为单向和双向两种,单向和双向的区别主要在java类中才会有区别,在数据库中时没区别的。
- 一对一
- 一对多
- 多对一
- 多对多
其中一对多双向关联和多对一双向关联是一样的。所以总的来说,我们要注意的关系映射有七种。
OneToOne(凡是双向,都要用mappedBy)
单向外键
- 使用annotation进行配置。如果使用annotation进行配置,那么和之前一样,首先要进行表的配置,即@Entity,还有id,自增等等,这里不做重复介绍。
在使用annotation进行单向配置的时候,比如存在这么两张表(husband、wife),那么就会存在husband和wife两个类文件,在husband中设置一个wife对象,然后再生成的getter方法前面用@onetoone进行注解,这样就表示进行了单向的关联。要注意,这里生成的外键的名字,也就是在表husband生成的字段的名字为wife属性名_id,如设置的wife属性为wife,那么自动生成的字段为wife_id。这样的操作明显不是我们想要的,如果想要设置成自己想要的字段名,可以在@onetoone下面再用一个新的注解:@joinColumn(name=”wifeId”),这样就表示把应的字段名设置为wifeId。
- xml文件进行配置。使用xml文件进行配置的时候,是在对应的xml文件中配置一个元素:<many-to-one>,指定name、column、unique三个属性,name指定的是在对应的java类中对应的属性,column对应的是在数据库中生成的字段,unique则是设置为唯一的。很多人会认为这里是不是出错了,觉得<many-to-one>是多对一而不是一对多。其实在xml文件的配置中,不能很好的见名知义,这里是通过unique属性来进行唯一配置,没有unique属性,没办法进行one-to-one的配置。
双向外键
- 使用annotation。双向外键和单向外键的设置方法是一样的,在对应的java类中,要设置好对应的关系。只是在使用双向外键的时候,使数据库的设计变得冗余了。所以在这里,可以用@OneToOne的时候指定mappedBy属性,属性内的值填的时类中设置的关系类中的具体属性。如Husband中的Wife类型的wife属性。
- 这样设置的话表示在对应的husband和wife表中,外键关系主要由husband中的wifeId来指定。
- xml文件。使用xml文件进行配置的时候,为避免出现两张表互相存在外键的情况,在其中一个xml文件中配置<one-to-one>,配置的时候要指定一个name属性和property-ref属性。name属性指定的是具体java类中设置的属性,property-ref属性则是两张表中的外键属性主要是由student指定。其中property-ref指定的其实是对应java类中的属性,这里是Student类的student属性。
单向主键(不重要)
- annotation配置。单向主键和单向外键的区别仅是用主键来进行区分,在实际的配置中是一样的。只是添加一个新的注解@PrimaryKeyJoinColumn,这里不需要指定name属性,因为在数据表中主键是唯一的,所以无需指定。
- xml配置。使用xml进行配置时,不能再配置many-to-one了,而是用one-to-one进行配置,要指定一个name属性,对应的是java类中的对应属性,表示用作联系的表。在配置时想要让生成的表出现关联字段,那么还需要配置constrained=”true”,表示建表的时候自动生成关联关系。在使用xml文件进行配置的时候还要注意,在设置id的时候,指定了自增的格式是native,这里明显不能使用native了,而是要用foreign,表示外键自增。而且因为存在一张表多个外键的问题,所以在指定foreign的时候还要传递一个参数,name为property,表示具体是由那张表的主键进行关联的。
双向主键(不重要)
- annotation配置。同上的配置,只是在两个类的对应设置的关系属性中都要进行配置。同双向外键一样,只是配置时用@PrimaryKeyJoinColumn。但是在配置one-to-one的时候不用配置对应的mappedBy的值,因为主键不会产生歧义。
- xml文件。同之前一样,只是使用的时one-to-one的操作。同样需要指定property-ref属性。
单向联合主键(不常用,有印象)
在这里只是说明用annotation进行的配置。进行配置联合主键的时候,可以新建一个新的联合主键类(wifePK),然后存放对应的字段。在具体的java类(Wife)中用@idClass进行注解。要注意用联合主键的话,要继承serializable接口、重写hashCode和equals方法
用联合主键进行注解的时候,如果只是简单的使用@JoinColumn是不行的,这里要使用的注解是@JoinColumns,注意查看这个注解的api文档,你会发现返回的是一个JoinColumn的数组,所以使用@JoinColumns这个注解的时候,要传递进去多个@JoinColumn,而且还要说明对应的字段是以哪个属性作为依赖的,用referencedColumnName进行指定。
component组件映射
当我们进行一对一的操作的时候,往往会发现根本不需要建立两个table,也就是说一个table就可以解决问题了。所以在这里,用component就是把两个java类中的对象映射成一个table的操作
- Annotation。只需要在一个java类(husband)中进行映射,在映射的时候,在设置的另一个类的属性(Wife:wife)的getter方法前面用@Embedded进行注解,只指的是在把wife的信息嵌入到husband中,表示把Wife类中的属性以普通字段的形式添加到对应的table中。
- xml。在这里,要在对应的类文件的class.hbm.xml文件中进行设置,除了普通的设置之外,还要添加这么如下一个元素<component>,并指定其中的name属性,name指定的是对应的类文件中指定到另一个类文件的指引(如Husband中有一个Wife类型的wife属性,那么这里填的就是wife)。然后还要用<property>进行设置属性,设置的时指引类(wife)中的属性。
More to One Or One to More
进行多对一的表映射的时候,一般是在数据比较多的表(如有两个表,group和user,那么就是user表)中添加外键,消除数据冗余,但是要注意,数据表不要和数据库中的关键字重复,如这里的group和user。
M-O单向外键
- annotation。只需要简单的使用@many-to-one注解即可,如果要为字段进行修改名字,则用@JoinColumn。
- xml。只需要在数据多的那方的xml文件中设置一个many-to-one元素,指定name和column即可,不做重复累述。
O-M单向外键
- annotation。用annotation进行一对多注解时,需要在进行注解的类(Group)中设置一个集合,用来保存另一个类(User)的属性,这里是用set集合,原因是set集合里面的数据都是不存在重复值的。
- 不过要注意,当进行一对多注解的时候,hibernate会默认当作是多对多的情况,生成一张中间表用来保存表之间数据的映射。如果不想生成中间表的话,在进行注解的类(Group)中用@JoinColumn进行注解,不过注解之后生成的字段是在数据多的表里面的,所以这里设置的字段会在user表中存在。
- xml。在进行注解的类的xml文件中进行配置,需要先配置一个set元素,指定name属性,name属性中的值对应的具体类的设置的集合的属性名。在set元素下面还要配置两个子元素,一个是key元素,一个是one-to-many元素。Key元素指定一个column属性,表示的是表中对应的字段。One-to-many设置一个class属性,指定的是数据多的那个类(User)的具体路径。
O-M Or M-O双向关联
- annotation。使用双向关联,一定要注意用mappedBy来指定依赖于哪个外键。否则的话在对应的数据表中会出现多个外键,一般是由数据多的那部分来主导,即在group和user两个表中,是由user中的字段来主导的,那么在类中用annotation进行映射时,要在group中的@OneToMany中指定mappedBy(name=“groupId”),表示由user中的来指定。
- xml。使用xml文件进行配置的时候,在两个类的xml文件中都要配置对应的信息,在数据少(Group)的表中先配置set元素,再配置one-to-many元素。在数据多(User)表中配置many-to-one元素。不过要注意,在这里配置的时候,set元素下面的key的属性和many-to-one元素下面的column属性要一致,不然在数据表中会出现多个外键。而加入不配置key属性的话,需要不会出现重名的外键,但出现了主键关联。
Many-to-Many
单向外键
- annotation。使用many2many和one2many其实区别并不是很大。因为是单向,所以在这里要注意,在其中一方会用一个集合来保存另一方的对象。如在Teacher和Student两个对象,在Teacher中会有一个set集合(不可重复)来存放student的对象,然而在这个set集合对应的getter方法上面用@ManyToMany这个注解进行映射。这个时候就会在数据库中生成一张Teacher表、Student表、Teacher_Student表。如果想修改中间表的名字,与其中的字段,就要用到一个新的注解@JoinTable,然后指定一个name属性,那么name属性中的值就对应着中间表的名字。查看JoinTable的api,会发现还有joincolumns和reserveJoinColumns两个属性,都是JoinColumns数组。分别在这两个属性中指定一个@JoinColumn注解,用name属性来指定中间表中数据库的字段。
- xml。使用xml文件对many2many进行配置的时候, 因为是单向,所以只需要在其中一个xml文件中配置即可,另一个xml文件只需要进行简单的数据表字段的生成即可。在这里,是在teacher.hbm.xml文件中进行重要的配置,除了基本的-配置之外,还要设置一个<set>元素,元素中指定了一个name属性和table属性,name属性是用来指定存放的student对象的集合的名字,table则指定的是生成的中间表的名字,如果不指定table属性,那么hibernate将会自动用teacher表名的名字和set元素中name属性的值来进行命名,如teacher_students。除此之外,设置为set元素之后,要设置两个子元素,一个是key,并指定column,表示的是中间表中当前对象所对应的字段名,这里是teacher在中间表对应的字段名。一个是many-to-many元素,要指定class属性和column属性,class是对应的对象的路径,column则是对象指定的字段名。这里是student在中间表对应的字段名。
双向关联
- annotation。双向关联基本上使用的很少,而且使用起来和单向是没有区别的,只是在两个对象都进行设置一样的注解。只是需要注意的是,当双方都使用了@many-to-many注解之后,在某一方的注解中只需要简单的设置@many-to-many,并且指定mappedBy属性,指定的值是另一个对象中设置关系的属性的名字。如在这里,是在student所加的注解中添加mappedBy属性,所以对应的值是Teacher对象中设置的set集合的元素的名字,为students。
- xml。使用xml也是一样的道理,在另一个配置文件中设置set元素,内容对应的发生改变,这里不进行累述。只是要注意的是,这里两个配置文件设置的set元素的table属性要一致,不然会生成两张不同的表。