【教程】Hibernate 多表操作

表与表关系的回顾

一对一

  • 一夫一妻制
  • 通常一张表就能表达

一对多(客户和联系人)

  • 分类和商品的关系,一个分类有多个商品而一个商品只能属于一个分类
  • 例子:客户:与公司有业务往来;联系人:公司里面的员工,百度里面有很多的员工,联系员工就能练习客户,类似于公司和公司员工的关系
  • 建表时通过外键建立关系,一为主表,多为从表

多对多(用户和角色)

  • 订单和商品的关系,一个订单可以有多个商品且一个商品可以属于多个订单
  • 建表时通过维护第三张表建立关系

Hibernate 一对多操作

一对多映射配置

  • 第一步 创建实体类,客户(一) and 联系人(多)
  • 第二步 让这两个实体类之间互相表示
    (1)在客户实体类中表示多个联系人:一个客户里面有多个联系人
    (2)在联系人实体类里面表示所属客户:一个联系人只能属于一个客户
    //hibernate 要求使用集合表示多的数据,使用set集合
    //set集合是无序的,可有重复元素
    
    //在客户实体类中加上下列属性以及相应set和get方法
    //表示一个客户中有多个联系人
    private Set<LinkMan> setLinkMan = new HashSet<LinkMan>();
    
    //在联系人实体类中加上下列属性以及相应set和get方法
    //表示一个联系人只有一个客户
    private Customer customer;
    
  • 第三步 配置映射关系
    (1)一个实体类对应一个映射文件
    (2)把映射的最基本配置完成
    (3)在映射文件中配置一对多关系(重点)
    <!-- Customer.hbm.xml -->
    <!-- 在客户映射文件中表示所有联系人 -->
    
    <?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">
    <hibernate-mapping>
    	<!-- 1 配置类和表对应 
    		class标签
    		name属性:实体类全路径
    		table属性:数据库表名称
    	-->
    	<class name="cn.itcast.entity.Customer" table="t_customer">
    		<id name="cid" column="cid">
    			<generator class="native"></generator>
    		</id>
    		<property name="custName" column="custName"></property>
    		<property name="custLevel" column="custLevel"></property>
    		<property name="custSource" column="custSource"></property>
    		<property name="custPhone" column="custPhone"></property>
    		<property name="custMobile" column="custMobile"></property>
    		
    		<!-- 在客户映射文件中,表示所有联系人 
    			使用set标签表示所有联系人
    			set标签里面有name属性:
    			属性值写在客户实体类里面表示联系人的set集合名称
    			 inverse属性默认值:false不放弃关系维护
    			                true表示放弃关系维护
    		-->
    		<set name="setLinkMan" inverse="true">
    			<!-- 一对多建表,有外键
    				hibernate机制:双向维护外键,在一和多那一方都配置外键	
    				column属性值:外键名称
    			 -->
    			<key column="clid"></key>
    			<!-- 客户所有的联系人,class里面写联系人实体类全路径 -->
    			<one-to-many class="cn.itcast.entity.LinkMan"/>
    		</set>
    	</class>
    </hibernate-mapping>
    
    
    <!-- LinkMan.hbm.xml -->
    <!-- 在联系人映射文件中表示一个客户 -->
    
    <? 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">
    <hibernate-mapping>
    	<!-- 1 配置类和表对应 
    		class标签
    		name属性:实体类全路径
    		table属性:数据库表名称
    	-->
    	<class name="cn.itcast.entity.LinkMan" table="t_linkman">
    		<id name="lkm_id" column="lkm_id">
    			<generator class="native"></generator>
    		</id>
    		<property name="lkm_name" column="lkm_name"></property>
    		<property name="lkm_gender" column="lkm_gender"></property>
    		<property name="lkm_phone" column="lkm_phone"></property>
    		
    		<!-- 表示联系人所属客户 
    			name属性:因为在联系人实体类使用customer对象表示,写customer名称
    			class属性:customer全路径
    			column属性:外键名称
    		-->
    		<many-to-one name="customer" class="cn.itcast.entity.Customer" column="clid"></many-to-one>
    	</class>
    </hibernate-mapping>
    
    
    
  • 第四步 创建核心配置文件,把映射文件引入核心配置文件
    <!-- hibernate.cfg.xml -->
    <mapping resource="../../../LinkMan.hbm.xml"/>
    
  • 测试:运行 HibernateUtils 工具类,检查是否报错以及是否创建了两个表格即可

一对多级联保存

  • 添加一个客户,为该客户添加多个联系人
  • 复杂版本
    public void tesdAddDemo1(){
    	Session session = null;
    	Transaction tx = null;
    	try{
    		//获得session
    		session = HibernateUtils.getSessionObject();
    		//开启事务
    		tx = session.beginTransaction();
    		//添加一个客户,并为这个客户添加联系人
    		//1 创建对象
    		Customer customer = new Customer();
    		customer.setCustName("DEMO1");
    		customer.setCustPhone("999");
    		
    		LinkMan l = new LinkMan();
    		l.setLinkManName("demo1");
    		l.setLinkManPhone("911");
    		//2 在客户表示联系人,在联系人表示客户
    		//建立两个实体类对象之间的关系
    		//2.1 把联系人对象放入到客户实体类对象中的set集合里面
    		customer.getSetLinkMan().add(l);
    		//2.2 把客户对象放入到联系人里
    		l.setCustomer(customer);
    		
    		//3 保存
    		session.save(customer);
    		session.save(l);
    		
    		//提交
    		tx.commit();
    	}catch(Exception e){
    		//回滚
    		tx.rollback();
    	}
    }
    
  • 简化版本
    一般根据客户添加联系人,底层实现就是根据配置文件替代了建立关系的过程
    (1)在客户映射文件中进行配置:在客户映射文件里的set标签进行配置,添加一个cascade属性
    <set name="setLinkMan" cascade="save-update">
    
    (2)创建客户和联系人对象,只需要把联系人放到客户里面,最终只需要保存客户
    public void tesdAddDemo2(){
    	Session session = null;
    	Transaction tx = null;
    	try{
    		//获得session
    		session = HibernateUtils.getSessionObject();
    		//开启事务
    		tx = session.beginTransaction();
    		//添加一个客户,并为这个客户添加联系人
    		//1 创建对象
    		Customer customer = new Customer();
    		customer.setCustName("DEMO2");
    		customer.setCustPhone("111");
    		
    		LinkMan l = new LinkMan();
    		l.setLinkManName("demo2");
    		l.setLinkManPhone("222");
    		//2 把联系人放到客户里面
    		customer.getSetLinkMan().add(l);
    		//3 保存
    		session.save(customer);
    		
    		//提交
    		tx.commit();
    	}catch(Exception e){
    		//回滚
    		tx.rollback();
    	}
    }
    

一对多级联删除

  • 删除一个客户,就要把该客户的联系人都删除
  • 实现步骤
    (1)在客户映射文件的 set 标签进行配置,把cascade 中的值加上 delete
    <set name="setLinkMan" cascade="save-update,delete">
    
    (2)在代码中直接删除客户(查询后用delete方法删除)
public void testDeleteDemo(){
	Session session = null;
	Transaction tx = null;
	try{
		//获得session
		session = HibernateUtils.getSessionObject();
		//开启事务
		tx = session.beginTransaction();
		//1 根据id查询客户对象
		Customer c = session.get(Customer.class,3);
		//2 调用方法删除
		session.delete(c);
		
		//提交
		tx.commit();
	}catch(Exception e){
		//回滚
		tx.rollback();
	}
}
  • Hibernate级联删除步骤
    (1)根据id查询客户
    (2)根据外键id值查询联系人
    (3)把联系人外键设置为null
    (4)删除联系人和客户

一对多修改

  • a联系人所属的客户c改成另外一个c1
  • 主要就是修改联系人表的外键
public void testDeleteDemo(){
	Session session = null;
	Transaction tx = null;
	try{
		//获得session
		session = HibernateUtils.getSessionObject();
		//开启事务
		tx = session.beginTransaction();
		//1 根据id查询出联系人,根据id查询出客户
		Customer c1 = session.get(Customer.class,1);
		LinkMan a = session.get(LinkMan.class,2);
		//2 设置持久态对象的值,持久太对象会自动提交
		//把联系人放到客户
		c1.getSetLinkMan().add(a);
		//把客户放到联系人里
		a.setCustomer(c1);
		//提交
		tx.commit();
	}catch(Exception e){
		//回滚
		tx.rollback();
	}
}
  • inverse 属性
    (1) 在操作时会对外键值更改两次,原因:Hibernate中,外键是双向维护的,在两个对象中都会维护外键,因此在修改其中一个对象时会修改一次,修改另一个对象也会再修改一次。
    (2) 多次的修改操作对数据库会有性能影响
    (3) 解决方法:让其中一方放弃外键维护,在一对多的关系中,放弃维护外键的是一的那一方,因为对于多的那一方,是一对一的关系
    (4) 实现:在放弃关系维护映射文件中进行配置,在set标签上使用inverse属性
    <!-- inverse 的默认属性值是FALSE,表示不放弃关系维护;
    	因此TRUE则表示放弃关系维护 -->
    <set name="setLinkMan" inverse="false">
    

Hibernate多对多操作

以用户和角色为例

多对多映射配置

  • 第一步 创建实体类,用户和角色
  • 第二步 让两个实体类之间互相表示(两端都是用set集合)
    (1)一个用户里面有多个角色
    (2)一个角色里面有多个用户
    private Set<Role> setRole = new HashSet<Role>();
    private Set<User> setUser = new HashSet<User>();
    
  • 第三步 配置映射关系
    (1)基本配置(详细代码查看一对多关系中的基本配置)
    (2)配置多对多关系
    <!-- User.hbm.xml -->
    <!-- 使用set标签
    	 name:角色set集合的名称
    	 table:第三张表名称
    	-->
    <set name="setRole" table="user_role">
    	<!-- key标签里面配置当前映射文件在第三张表外键名称
    		 表示User在第三张表的外键名称
    		-->
    	<key column="userid"></key>
    	<!-- class:实体类全路径
    		 column:在第三张表外键的名称
    		-->
    	<many-to-many class="cn.itcast.manytomany.Role" column="roleid"></many-to-many>
    </set>
    
    
    <!-- Role.hbm.xml -->
    <set name="setUser" table="user_role">
    	<key column="roleid"></key>
    	<many-to-many class="cn.itcast.manytomany.Role" column="userid"></many-to-many>
    </set>
    
  • 第四步 在核心配置文件中引入映射文件
    <mapping resource="User.hbm.xml"/>
    <mapping resource="Role.hbm.xml"/>
    

多对多级联保存

  • 第一步 在用户配置文件中的set标签进行配置,cascadesave-update
<set name="setRole" table="user_role" cascade="save-update">
  • 第二步 代码实现: 创建用户和角色对象,把角色放到用户里面,最终保存就可以了
public void testCascadeSave(){
	Session session = null;
	Transaction tx = null;
	try{
		//获得session
		session = HibernateUtils.getSessionObject();
		//开启事务
		tx = session.beginTransaction();
		
		//1 创建对象并设置相应的属性值
		User user1 = new User();
		User user2 = new User();
		Role r1 = new Role();
		Role r2 = new Role();
		Role r3 = new Role();
		//2 建立关系
		//user1 ---- r1&r2
		user1.getSetRole().add(r1);
		user1.getSetROle().add(r2);
		//user2 ---- r2&r3
		user2.getSetRole().add(r2);
		user2.getSetROle().add(r3);
		//3 保存
		session.save(user1);
		session.save(user2);
		
		//提交
		tx.commit();
	}catch(Exception e){
		//回滚
		tx.rollback();
	}
}

多对多级联删除

  • 第一步 set标签配置cascade值为delete
<set name="setRole" table="user_role" cascade="save-update,delete">
  • 第二步 删除用户代码实现
//删除操作
User user = session.get(User.class,1);
session.delete(user);

多对多一般不用级联删除,因为一旦级联删除,可能会把别的关系也给删除了,而且两边的关系通过第三张表维护,因此如要删除关系,直接在第三张表操作即可。

维护第三张表

  • 用户和角色多对多的关系是通过第三张表维护
  • 让某个用户有某个角色
    第一步 根据 id 查询用户和角色
    第二步 把角色放到用户里面(set集合的add方法)
  • 让某个用户没有某个角色
    第一步 根据 id 查询用户和角色
    第二步 从用户里面把角色去掉(set集合的remove方法)
// 让C用户拥有A角色
User c = session.get(User.class,1);
Role a = session.get(Role.class,1);
c.getSetRole().add(a);//把角色放到用户的set集合中

// 让C用户失去B角色
User c = session.get(User.class,1);
Role b = session.get(Role.class,1);
c.getSetRole().remove(b);//从用户的set集合中去掉该角色
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值