表与表之间的关系
- 1对多
- 分类和商品关系,一个分类里面有多个商品,一个商品只能属于一个分类
- 客户和联系人是一个一对多的关系(公司与员工的关系)
- 客户: 与公司有业务往来的
- 联系人:公司里面的员工
- 1对多建表,通过外键约束(要在多的那一方创建一个字段,作为外键,指向1的那一方)
- 多对多
- 订单和商品关系,一个订单里面有多个商品,一个商品属于多个订单
- 用户和角色是多对多的关系(任一用户可以是多种角色,任一角色可对应多个用户)
- 多对多需要第三张表来维护这个关系(第三张表至少含有两个字段,包含其他两个表的主键)
- 1对1
- 一个男人只能有一个妻子,一个女人只能用一个丈夫
Hibernate中一对多的操作(重点)
- 一对多映射配置
- 第一步:导入hibernate的jar包
- 第二步:创建实体类(客户、联系人)
- 第三部:在客户实体类里面表示多个联系人,一个客户有多个联系人(hibernate中要求使用set集合)
- 第四步:在联系人中表示一个联系人只能属于一个客户
- 第五步:配置映射文件
- 第六步:在配置文件中,配置1对多的映射关系
- 在客户映射文件中,表示所有联系人
<!-- 使用set表示所有联系人,set标签的name值为set集合的名称 -->
<set name="setLinkMan">
<!-- hibernate中双向维护外键,在一和多的那一方都要配置外键 -->
<key column="clid"></key>
<!-- 联系人的全路径 -->
<one-to-many class="com.eric.demo.entity.LinkMan"/>
</set>
- 在联系人文件中表述所属客户
<!-- 表示联系人所属客户
name:因为在联系人实体类使用customer对象表示,写customer名称
class:customer类的全路径
column:外键名称-->
<many-to-one name="customer" class="com.eric.demo.entity.Customer" column="clid"></many-to-one>
- 在核心配置文件中引入映射文件
<mapping resource="com/eric/demo/entity/Customer.hbm.xml"/>
<mapping resource="com/eric/demo/entity/LinkMan.hbm.xml"/>
- 在客户映射文件中,表示所有联系人
一对多级联操作
级联保存
// 复杂的写法 SessionFactory sessionFactory = null; Transaction tx = null; Session session = null; try{ // 开启事务 // 提交事务 sessionFactory = HibernateUtils.getSessionFactory(); session = sessionFactory.openSession(); tx = session.beginTransaction(); Customer customer = new Customer(); customer.setCustName("Eric"); customer.setCustLevel("vip"); customer.setCustSource("网络"); customer.setCustPhone("13456"); customer.setCustMobile("9999"); LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("lucy"); linkMan.setLkm_gender("女"); linkMan.setLkm_phone("123"); //建立关系 customer.getSetLinkMan().add(linkMan); linkMan.setCustomer(customer); //保存 session.save(customer); session.save(linkMan); tx.commit(); } catch(Exception e) { // 回滚事务 e.printStackTrace(); tx.rollback(); } finally { // 关闭 session.close(); sessionFactory.close(); }
// 简化操作 // 第一步:在一的那个表对应的配置文件中配置cascade="save-update" <!-- 使用set表示所有联系人,set标签的name值为set集合的名称 --> <set name="setLinkMan" cascade="save-update"> <!-- hibernate中双向维护外键,在一和多的那一方都要配置外键 --> <key column="clid"></key> <!-- 联系人的全路径 --> <one-to-many class="com.eric.demo.entity.LinkMan"/> </set> // 第二步:把多的那个对应的对象直接放到客户里面就可以了 SessionFactory sessionFactory = null; Transaction tx = null; Session session = null; try{ // 开启事务 // 提交事务 sessionFactory = HibernateUtils.getSessionFactory(); session = sessionFactory.openSession(); tx = session.beginTransaction(); Customer customer = new Customer(); // 创建一的对象 customer.setCustName("百度"); customer.setCustLevel("普通客户"); customer.setCustSource("网络"); customer.setCustPhone("13456"); customer.setCustMobile("9999"); // 创建多的对象 LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("小红"); linkMan.setLkm_gender("女"); linkMan.setLkm_phone("123"); // 把多设置到一中 customer.getSetLinkMan().add(linkMan); // 保存一 session.save(customer); // 提交事务 tx.commit(); } catch(Exception e) { // 回滚事务 e.printStackTrace(); tx.rollback(); } finally { // 关闭 session.close(); sessionFactory.close(); }
一对多的级联删除(例:删除某个客户,把对应的联系人也删除)
// 第一步:在客户(一)映射文件中的set标签进行配置cascade="save-update" <!-- 使用set表示所有联系人,set标签的name值为set集合的名称 --> <set name="setLinkMan" cascade="save-update,delete"> <!-- hibernate中双向维护外键,在一和多的那一方都要配置外键 --> <key column="clid"></key> <!-- 联系人的全路径 --> <one-to-many class="com.eric.demo.entity.LinkMan"/> </set> // 第二步:在代码中删除客户(一)。根据id查询对象,再执行delete操作 SessionFactory sessionFactory = null; Transaction tx = null; Session session = null; try{ // 开启事务 // 提交事务 sessionFactory = HibernateUtils.getSessionFactory(); session = sessionFactory.openSession(); tx = session.beginTransaction(); // 根据id查询出客户对象 Customer customer = session.get(Customer.class, 3); session.delete(customer); // 提交事务 tx.commit(); } catch(Exception e) { // 回滚事务 e.printStackTrace(); tx.rollback(); } finally { // 关闭 session.close(); sessionFactory.close(); }
- 一对多修改操作
- 修改多中的外键
SessionFactory sessionFactory = null;
Transaction tx = null;
Session session = null;
try{
// 开启事务
// 提交事务
sessionFactory = HibernateUtils.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
// 根据id查询联系人(多)
// 根据id查询出客户对象(一)
Customer baidu = session.get(Customer.class, 2);
LinkMan lucy = session.get(LinkMan.class, 1);
// 设置持久态对象的值
baidu.getSetLinkMan().add(lucy);
lucy.setCustomer(baidu);
// 提交事务
tx.commit();
} catch(Exception e) {
// 回滚事务
e.printStackTrace();
tx.rollback();
} finally {
// 关闭
session.close();
sessionFactory.close();
}
- inverse属性
- 因为hibernate双向维护外键,在客户和联系人里面都需要维护外键,修改客户(一)时候修改一次外键,修改联系人(多)时候也修改一次外键,造成效率问题。
- 解决方案:让其中一方不维护外键,一对多里面,让其中的一方放弃外键维护。让客户(一的那一方)放弃维护。例如,一个国家有总统,国家有很多人,总统不认识所有的人,但是国家所有人都可以认识总统。
- 具体实现,在放弃关系维护映射文件中,进行配置,在set标签上使用inverse属性
<!-- 使用set表示所有联系人,set标签的name值为set集合的名称
inverse属性默认值为false 不放弃关系维护,true表示放弃-->
<set name="setLinkMan" inverse="false">
<!-- hibernate中双向维护外键,在一和多的那一方都要配置外键 -->
<key column="clid"></key>
<!-- 联系人的全路径 -->
<one-to-many class="com.eric.demo.entity.LinkMan"/>
</set>
- 修改多中的外键
Hibernate中多对多的操作
多对多映射配置(以用户和角色为例)
- 第一步:创建实体类,用户和角色
- 第二步:让两个实体类之间互相表示
- 一个用户里面表示所有角色,使用set集合
<set name="setRole" table="user_role">
<key column="userid"></key>
<many-to-many class="com.eric.demo.entity.Role" column="roleid"></many-to-many>
</set>
- 一个角色有多个用户,使用set集合
<set name="setUser" table="user_role">
<key column="roleid"></key>
<many-to-many class="com.eric.demo.entity.User" column="userid"></many-to-many>
</set>
- 一个用户里面表示所有角色,使用set集合
- 配置映射关系
在核心配置文件配置
<mapping resource="com/eric/demo/entity/User.hbm.xml"/> <mapping resource="com/eric/demo/entity/Role.hbm.xml"/>
多对多级联保存
根据用户保存角色
// 第一步:在用户的配置文件中set标签进行配置,cascade值save-update // 第二步:写代码实现 sessionFactory = HibernateUtils.getSessionFactory(); session = sessionFactory.openSession(); tx = session.beginTransaction(); // 添加两个用户,为每个用户添加两个角色 User user1 = new User(); user1.setUsername("lucy"); user1.setPassword("123"); User user2 = new User(); user2.setUsername("mary"); user2.setPassword("456"); Role role1 = new Role(); role1.setRole_name("总经理"); role1.setRole_memo("总经理"); Role role2 = new Role(); role2.setRole_name("秘书"); role2.setRole_memo("秘书"); Role role3 = new Role(); role3.setRole_name("保安"); role3.setRole_memo("保安"); // user1-----role1/role2 user1.getSetRole().add(role1); user1.getSetRole().add(role2); // user2-----role2/role3 user2.getSetRole().add(role2); user2.getSetRole().add(role3); session.save(user1); session.save(user2); // 提交事务 tx.commit();
- 多对多级联删除(了解)
- 在cascade配置delete
- 在代码中先查后删
- 维护第三张表关系(重要)
- 用户和角色是多对多的关系,维护关系通过第三张表
- 让某个用户有某个角色
- 第一步:根据id查询用户和角色
- 第二步:把角色对象放到用户set集合中
- 让某个用户没有某个角色
- 第一步:根据id查询用户和角色
- 第二步:从用户里面把角色去掉,从set集合中移除