hibernate的关联关系

  • 2019-05-16
  • 217
  • 0

hibernate操作实体类

如何让实体类之间明白它们之间的关系? 

  •  如果是1对多的关系? 需要在一的一方有多的一方的集合,在customer类中有linkMan的集合。需求: 查客户以及客户下面所有的联系人?customer: 拿到了客户数据,拿到了联系人数据。
  •  如果是多对多? 在user类中有role类的集合,在role类中有User类的集合,在双方中都有对方的集合。
  • 如果是一对一?在夫类中有妻类的对象,在妻类中有夫类的对象, 在双方中都以对方的对象。

总结: 如果表1对多的关系.当创建这2个实体的时候, 在一的一方定义一个多的一方的集合,在多的一方定义一个一的一方的对象;如果表多对多的关系.当创建这2个实体的时候,在互相中都有对方的集合;如果表一对一的关系.当创建这2个实体的时候
在互相中都有对方的对象。

hibernate的一对多关系建立?

任务:有2张表,有2个实体类,然后通过hibernate创建一对多的关系映射

package com.husaky.bean;

// N
public class Linkman
{
	  private Long lkm_id;// '联系人编号(主键)',
	  private String lkm_name;// '联系人姓名',
	  private String lkm_gender;// '联系人性别',
	  private String lkm_phone;// '联系人办公电话',
	  private String lkm_mobile;// '联系人手机',
	  private String lkm_email;// '联系人邮箱',
	  private String lkm_position;// '联系人职位',
	  private String lkm_memo;// '联系人备注',
	  
	  // 有一个客户的对象
	  private Customer customer;

	 public Customer getCustomer() {
		return customer;
	}
	public void setCustomer(Customer customer) {
		this.customer = customer;
	}
	public Long getLkm_id() {
		return lkm_id;
	}
	...
	  
}
package com.husaky.bean;

import java.util.HashSet;
import java.util.Set;

// 1
public  class Customer 
{

	 private Long cust_id;// '客户编号(主键)',
	 private String cust_name;// '客户名称(公司名称)',
	 private String cust_source;// '客户信息来源',
	 private String cust_industry;//'客户所属行业',
	 private String cust_level;// '客户级别',
	 private String cust_address;// '客户联系地址',
	 private String cust_phone;// '客户联系电话',
	 
	 // 有一个联系人的集合
	 private Set<Linkman> linkmans=new HashSet<Linkman>();

	public Set<Linkman> getLinkmans() {
		return linkmans;
	}
	public void setLinkmans(Set<Linkman> linkmans) {
		this.linkmans = linkmans;
	}
	public Long getCust_id() {
		return cust_id;
	}
	...
}
<?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>
		<!-- 	配置类和表的映射 -->
		<class name="com.husaky.bean.Customer" table="cst_customer">
				<!-- 配置主键和属性的映射 -->
				<id name="cust_id" column="cust_id">
					<!-- 
						 native: 使用都是数据库的自增
						 	 如果用的是mysql: auto_increment
						 	如果用的是oracle: 序列
					
						  uuid: 针对的是字符串类型
						  	   自动给你生成唯一的字符串来保证oid的唯一
					 -->
					<generator class="native"></generator>
				</id>
				
				<!-- 配置其它字段和其它属性的映射 -->
				<property name="cust_name" column="cust_name"></property>
				<property name="cust_source" column="cust_source"></property>
				<property name="cust_industry" column="cust_industry"></property>
				<property name="cust_level" column="cust_level"></property>
				<property name="cust_address" column="cust_address"></property>
				<property name="cust_phone" column="cust_phone"></property>
				
				<!-- 配置一对多的关系   集合(linkmans)-->
				<!-- 
						name:集合的名字
						inverse:true 指定放弃外键的维护权
						cascade: save-update 级联保存
								  delete:级联删除
								  
						lazy: true 默认值 默认使用延迟加载
							  false 不使用延迟加载 立即加载
				 -->
				<set name="linkmans" inverse="true" cascade="save-update,delete" lazy="false">
					<!-- 外键的字段名 -->
					<key column="wj_id" ></key>
					<!-- class:多的一方的全限定名  -->
					<one-to-many class="com.husaky.bean.Linkman"/>
				</set>
				
		</class>

</hibernate-mapping>   
<?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>
			<class name="com.husaky.bean.Linkman" table="cst_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>
				<property name="lkm_mobile" column="lkm_mobile"></property>
				<property name="lkm_email" column="lkm_email"></property>
				<property name="lkm_position" column="lkm_position"></property>
				<property name="lkm_memo" column="lkm_memo"></property>
				
				
				<!-- 配置一对多的关系  对象(customer) -->
				<!-- 
					 name:在自己里面一的一方对象的属性名
					 class: 一的一方的全限定名
					 column: 指定外键字段名
				 -->
				<many-to-one name="customer" class="com.husaky.bean.Customer" column="wj_id" cascade="save-update,delete"></many-to-one>
			</class>
</hibernate-mapping>

 一对多的配置: 固定方式,在多的一方(Linkman)

<many-to-one name="customer" class="cn.itcast.domain.Customer" column="wj_id"></many-to-one>
		  name: 自己里面一的一方对象的属性名 :customer	
		  class: 一的一方的全限定名
		  column: 指定外键名

  在一的一方(Customer)

<set name="linkmans">
			<key column="wj_id"></key>
			<one-to-many class="cn.itcast.domain.Linkman"/>
		</set>

		set:配置集合
		   name:自己里面多的一方的集合属性名 linkmans
		   column: 指定外键名
		   class: 多的一方的全限定名

测试

package com.husaky.utils;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtils 
{
		static Configuration configuration =null;
		static SessionFactory sessionFactory = null;
		static
		{
			// 加载一次配置文件
			configuration = new Configuration();
			configuration.configure();
			
			// 获取一个sessionFactory
			sessionFactory=configuration.buildSessionFactory();
			
		}
		
		// 从连接池获取的
		public static Session openSession()
		{
			return sessionFactory.openSession();
		}
		
		// 从当前线程中获取绑定的session 
		// 好处: 在多层之间调用方法获取的都是同一个session
		public static Session getCurrentSession()
		{
			/*特点: 1 默认是关闭的 需要配置开启
				   2 会自动给你关闭连接*/
			Session session = sessionFactory.getCurrentSession();
			return session;
		}
}

@Test
	/**
	 * 保存客户,同时保存客户关联联系人
	 * 必须同时保存两边对象,不能只保存一边,会出现异常
	 */
	public void demo1(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		// 创建一个客户 和两个联系人
		Customer customer = new Customer();
		customer.setCust_name("郝宝强");
		
		LinkMan linkMan1 = new LinkMan();
		linkMan1.setLkm_name("宋喆");
		
		LinkMan linkMan2 = new LinkMan();
		linkMan2.setLkm_name("马蓉");
		
		customer.getLinkMans().add(linkMan1);
		customer.getLinkMans().add(linkMan2);
		linkMan1.setCustomer(customer);
		linkMan2.setCustomer(customer);
		
		session.save(customer);
		session.save(linkMan1);
		session.save(linkMan2);
		
		transaction.commit();
	}

保存的时候,确实保存成功 但是出现了一些冗余的sql语句,我们说这些冗余的sql语句(update)不影响我们的程序,但是影响了性能,产生原因: 一级缓存

解决冗余SQL语句的问题

  因为现在2方都知道外键的存在 那么2方都会维护外键,让其中一方放弃外键的维护即可, 约定:让一的一方放弃外键的维护权 (customer), 在一的一方设定标签 :inverse=”true” ,放弃外键的维护权,上面的配置文件已经配置了

@Test
	/**
	 * 双向维护产生多余的SQL
	 */
	public void demo7(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		// 查询2号客户
		Customer customer = session.get(Customer.class, 2l);
		// 查询2号联系人
		LinkMan linkMan = session.get(LinkMan.class, 2l);
		customer.getLinkMans().add(linkMan);
		linkMan.setCustomer(customer);
		
		transaction.commit();
	}

一对多的级联保存操作

级联:操作一个对象的时候,是否操作其关联对象。级联操作是有方向性:

@Test
	/**
	 * 级联保存操作:
	 * 	* 保存客户级联保存联系人
	 *  在Customer.hbm.xml中<set>上配置cascade="save-update"
	 */
	public void demo2(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		// 创建一个客户 和两个联系人
		Customer customer = new Customer();
		customer.setCust_name("郝宝强");
		
		LinkMan linkMan1 = new LinkMan();
		linkMan1.setLkm_name("宋喆");
		
		customer.getLinkMans().add(linkMan1);
		linkMan1.setCustomer(customer);
		
		session.save(customer);
		// session.save(linkMan1);
		
		transaction.commit();
	}

	保存联系人级联保存客户
	@Test
	/**
	 * 级联保存操作:
	 * 	* 保存联系人级联保存客户在LinkMan.hbm.xml中<many-to-one>上配置cascade="save-update"
	 */
	public void demo3(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		// 创建一个客户 和两个联系人
		Customer customer = new Customer();
		customer.setCust_name("郝强勇");
		
		LinkMan linkMan1 = new LinkMan();
		linkMan1.setLkm_name("马蓉");
		
		customer.getLinkMans().add(linkMan1);
		linkMan1.setCustomer(customer);
		
		//session.save(customer);
		session.save(linkMan1);
		
		transaction.commit();
	}

 一对多的级联删除操作

	删除客户级联删除联系人
	@Test
	/**
	 * 级联删除操作:
	 * 	* 删除客户级联删除联系人
	 * 		在Customer.hbm.xml中<set>上配置cascade="delete"
	 */
	public void demo4(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		Customer customer = session.get(Customer.class, 1l);
		session.delete(customer);
		
		transaction.commit();
	}

Hibernate中的多对多关系映射

CREATE TABLE `sys_user` (
  `user_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '用户id',
  `user_code` varchar(32) NOT NULL COMMENT '用户账号',
  `user_name` varchar(64) NOT NULL COMMENT '用户名称',
  `user_password` varchar(32) NOT NULL COMMENT '用户密码',
  `user_state` char(1) NOT NULL COMMENT '1:正常,0:暂停',
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

CREATE TABLE `sys_role` (
  `role_id` bigint(32) NOT NULL AUTO_INCREMENT,
  `role_name` varchar(32) NOT NULL COMMENT '角色名称',
  `role_memo` varchar(128) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

CREATE TABLE `sys_user_role` (
  `role_id` bigint(32) NOT NULL COMMENT '角色id',
  `user_id` bigint(32) NOT NULL COMMENT '用户id',
  PRIMARY KEY (`role_id`,`user_id`),
  KEY `FK_user_role_user_id` (`user_id`),
  CONSTRAINT `FK_user_role_role_id` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`role_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `FK_user_role_user_id` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`user_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

用户端

<?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>
	<!-- 建立类与表映射 -->
	<class name="com.itheima.hibernate.domain.User" table="sys_user">
		<!-- 建立oid与表的主键映射 -->
		<id name="user_id" column="user_id">
			<generator class="native"/>
		</id>
		<!-- 建立属性与表字段映射 -->
		<property name="user_code"/>
		<property name="user_name"/>
		<property name="user_password"/>
		<property name="user_state"/>
		
		<!-- 建立用户与角色的映射关系 -->
		<!-- 
			set标签:
				name属性:角色集合属性名称
				table属性:中间表的名称
		 -->
		<set name="roles" table="sys_user_role">
			<!-- 用户端的在中间表的外键的名称 -->
			<key column="user_id"/>
			<!-- 
				配置多对多映射 
				many-to-many标签
					* class	:另一端的实体类的全路径
					* column:另一端在中间表外键的名称
			-->
			<many-to-many class="com.itheima.hibernate.domain.Role" column="role_id"/>
		</set>
	</class>
</hibernate-mapping>

角色

<?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>
	<!-- 建立类与表映射 -->
	<class name="com.itheima.hibernate.domain.Role" table="sys_role">
		<!-- 建立oid与表的主键映射 -->
		<id name="role_id" column="role_id">
			<generator class="native"/>
		</id>
		<!-- 建立属性与表字段映射 -->
		<property name="role_name"/>
		<property name="role_memo"/>
		<!-- 建立关联关系映射 -->
		<set name="users" table="sys_user_role">
			<key column="role_id"/>
			<many-to-many class="com.itheima.hibernate.domain.User" column="user_id"/>
		</set>
	</class>
</hibernate-mapping>

测试

@Test
	/**
	 * 保存数据
	 */
	public void demo1(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		User user1 = new User();
		user1.setUser_name("小王");
		
		User user2 = new User();
		user2.setUser_name("小勇");
		
		Role role1 = new Role();
		role1.setRole_name("Java教研部");
		Role role2 = new Role();
		role2.setRole_name("前台");
		Role role3 = new Role();
		role3.setRole_name("学工部");
		
		user1.getRoles().add(role1);// 1 1
		user1.getRoles().add(role3);
		user2.getRoles().add(role3);
		
		role1.getUsers().add(user1);// 1 1
		role3.getUsers().add(user1);
		role3.getUsers().add(user2);
		
		session.save(user1);
		session.save(user2);
		session.save(role1);
		session.save(role2);
		session.save(role3);
		
		transaction.commit();
	}

多对多其他相关操作

 给用户选择角色
	@Test
	/**
	 * 给1号用户选择1号和2号角色
	 */
	public void demo6(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		User user = session.get(User.class, 1l);
		
		Role role1 = session.get(Role.class, 1l);
		
		Role role2 = session.get(Role.class, 2l);
		
		user.getRoles().add(role1);
		user.getRoles().add(role2);
		
		transaction.commit();
	}
	给用户删除角色
	@Test
	/**
	 * 给1号删除2号角色
	 */
	public void demo7(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		User user = session.get(User.class, 1l);
		
		Role role = session.get(Role.class, 2l);
		
		user.getRoles().remove(role);
		
		transaction.commit();
	}
	给用户改选角色

	@Test
	/**
	 * 给1号用户的1号角色修改为2号角色
	 */
	public void demo8(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		
		User user = session.get(User.class, 1l);
		
		Role role1 = session.get(Role.class, 1l);
		
		Role role2 = session.get(Role.class, 2l);
		
		user.getRoles().remove(role1);
		user.getRoles().add(role2);
		
		transaction.commit();
	}	


总结hibernate的查询:

  •   OID查询  根据主键查询一条对象的数据
  •   HQL查询  全查 条件查 分页查 投影查 单列查 多列查 聚合查 排序查
  •   QBC查询  
  •   对象导航查询:当你在查customer数据的时候 会把customer中的集合linkman数据也全查了

延迟加载:提高hibernate效率,决定发送sql的时机.

分类:

  1. 类级别的延迟加载 (单表数据查询)  Load
  2. 关联级别的延迟加载  默认:查一个对象中关联的集合或则对象的时候 默认使用的延迟加载,只有在用到这个集合或则是对象数据的时候 才会立马去查

在set标签上有一个属性 lazy 用来配置关联级别是否延迟加载的
常用的值:

  • true:使用延迟加载 默认值
  • false:不使用延迟加载

查询客户的同时,立马发送sql查询联系人 ,在many-to-one标签上也有一个属性 lazy  用来配置是否延迟加载的
常用的值:

  • false:不使用延迟加载 

查询联系人的时候,立马发送sql查询客户

评论

还没有任何评论,你来说两句吧

粤ICP备17155863号

- 友情链接 - Theme by Qzhai