一、表之间的关系
1.一对一
2.一对多
3.多对多
二、表之间关系建表原则
1.一对多:在多的一方创建一个外键,指向一的一方的主键
2.多对多:创建一个中间表,中间表至少有两个字段,分别作为外键指向多对多双方的主键
3.一对一:主键一一对应,或当成一对多来看待。
三、一对多实现
1)定义
1.在1的domain类中定义:
private Set<link> links= new HashSet<>();
在相应映射配置文件中:
<!--一对多--> <set name="links"><!--set属性名称--> <key column="link_cust_id"></key><!--外键--> <one-to-many class="com.ual.domain.link"></one-to-many> </set>
如果想要保存记录的时候保存其级联的记录,需要在set 后添加
cascade="save-update"
2.在多的domain类中定义:
//一个联系人只对应一个客户 private customer customer;
在相应映射配置文件中:
<many-to-one name="customer" class="com.ual.domain.customer" column="link_cust_id" insert="false" update="false" lazy="false"></many-to-one>
加入lazy="false"后,在查询时会把记录相关的外键对应的记录一起查询出来。
3.在核心配置文件中,把映射关系写入
<mapping resource="com/ual/domain/customer.hbm.xml"/><!--告诉hibernate要操作哪些表,写入映射的配置文件的全路径--> <mapping resource="com/ual/domain/link.hbm.xml"></mapping>
4.实现插入
@Test public void test(){ Session session = HibernateUtil.getCurrentSession(); Transaction transaction = session.beginTransaction(); customer c1 = new customer(); c1.setCust_name("c1"); customer c2= new customer(); c2.setCust_name("c2"); link link1 = new link(); link1.setLink_name("link1"); link link2 = new link(); link2.setLink_name("link2"); link link3 = new link(); link3.setLink_name("link3"); /*配置关系*/ c1.getLinks().add(link1); c1.getLinks().add(link3); c2.getLinks().add(link2); link1.setCustomer(c1); link2.setCustomer(c2); link3.setCustomer(c1); /*保存联系人*/ session.save(c1); session.save(c2); session.save(link1); session.save(link2); session.save(link3); transaction.commit(); }
配置关系时,一般使用双向维护
2)查询
@Test public void test2(){ Session session = HibernateUtil.getCurrentSession(); Transaction transaction = session.beginTransaction(); link link=session.get(com.ual.domain.link.class,6L); transaction.commit(); System.out.println(link.getLink_name()); System.out.println(link.getCustomer().getCust_name()); }
注:
级联操作:
1.问题:在两张表建立一对多关系时,如果只保存一边的对象,会引发异常
2.级联操作:
什么时级联操作:在操作一个对象时,是否会操作其关联的对象
级联分类:
级联保存或更新:cascade="save-update"
级联删除:cascade="delete,save-update"
级联是有方向性的:保存的是谁就到谁里面做级联,删除的是谁就到谁里面做级联
3)更新
@Test public void test4(){ Session session = HibernateUtil.getCurrentSession(); Transaction transaction = session.beginTransaction(); //更新 link link=session.get(link.class,10L); customer customer=session.get(com.ual.domain.customer.class,13L); //10本来关联12,现让其关联13 //双向维护 customer.getLinks().add(link); link.setCustomer(customer); session.update(customer); transaction.commit(); }
注: 由于使用的双向维护,两方同时去维护一个外键,会产生性能问题,可以让一方放弃维护外键,只让外键所在的表维护外键
需要配置:在1的配置文件中:加inverse="true"
四、多对多关系实现
1、表关系:用户角色表
2、多对多映射文件配置
role:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <!--让java中的类与数据库中的表相关联,这样操作domain类就操作了与该类映射的表--> <hibernate-mapping> <class name="com.ual.domain.role" table="role"><!--name对应类中,table对应表中--> <!--建立类属性,哪一个是主键,该主键需要跟数据库中的主键相对应--> <id name="r_id" column="r_id"><!--name对应类,column对应表--> <generator class="native"/><!--主键生成策略--> </id> <!--建立类中的普通属性和数据库中的字段进行关联--> <property name="r_name" column="r_name"/> <!--多对多--> <set name="users" table="role_user"> <key column="r_id"></key> <many-to-many class="com.ual.domain.user" column="u_id"></many-to-many> </set> </class> </hibernate-mapping>
user:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <!--让java中的类与数据库中的表相关联,这样操作domain类就操作了与该类映射的表--> <hibernate-mapping> <class name="com.ual.domain.user" table="user"><!--name对应类中,table对应表中--> <!--建立类属性,哪一个是主键,该主键需要跟数据库中的主键相对应--> <id name="u_id" column="u_id"><!--name对应类,column对应表--> <generator class="native"/><!--主键生成策略--> </id> <!--建立类中的普通属性和数据库中的字段进行关联--> <property name="u_name" column="u_name"/> <!--多对多 name: 当前类下集合属性的名称 table:多对多中间表的表名 column:当前表的外键 <many-to-many class="" column=""></many-to-many> class:当前类集合中对象的全路径 column:集合中对象的外键 --> <set name="roles" table="role_user"> <key column="u_id"></key> <many-to-many class="com.ual.domain.role" column="r_id"></many-to-many> </set> </class> </hibernate-mapping>
3、配置核心配置文件
<mapping resource="com/ual/domain/role.hbm.xml"></mapping> <mapping resource="com/ual/domain/user.hbm.xml"></mapping>
4、插入数据测试
@Test public void test(){ Session session = HibernateUtil.getCurrentSession(); Transaction transaction = session.beginTransaction(); //创建用户 user user1 = new user(); user1.setU_name("user1"); user user2 = new user(); user2.setU_name("user2"); //创建角色 role role1 = new role(); role1.setR_name("role1"); role role2 = new role(); role role3 = new role(); role2.setR_name("role2"); role3.setR_name("role3"); //配置关系 user1.getRoles().add(role1); user1.getRoles().add(role2); user2.getRoles().add(role1); user2.getRoles().add(role3); role1.getUsers().add(user1); role1.getUsers().add(user2); role2.getUsers().add(user1); role3.getUsers().add(user2); //保存 session.save(user1); session.save(user2); transaction.commit(); }
注意:在多对多建表时,使用双向维护,必须要使得一方放弃外键维护权,一般在被选择一方放弃外键维护,如角色被用户选择,让角色放弃外键维护权。否则,报外键重复异常。
<set name="users" table="role_user" inverse="true" > <key column="r_id"></key> <many-to-many class="com.ual.domain.user" column="u_id" ></many-to-many> </set>
5、其他数据操作
@Test public void test2(){ //关系操作 就是操作内部集合 Session session = HibernateUtil.getCurrentSession(); Transaction transaction = session.beginTransaction(); //给用户1添加角色3 user user = session.get(user.class, 1L); role role = session.get(role.class, 3L); user.getRoles().add(role); transaction.commit(); }
@Test public void test3(){ Session session = HibernateUtil.getCurrentSession(); Transaction transaction = session.beginTransaction(); //更改,把用户2的角色3 修改为2 user user2 = session.get(user.class, 2L); role role3 = session.get(role.class, 3L); role role2 = session.get(role.class, 2L); user2.getRoles().remove(role3); user2.getRoles().add(role2); transaction.commit(); }