基于Annotations注解的Hibernate关联映射(双向多对一、双向多对多、双向一对一)

本文介绍Hibernate ORM框架下,如何利用注解方式实现不同业务实体间的多对一、多对多及一对一关联映射,包括具体代码示例及单元测试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

双向多对一

Hibernate除了支持映射文件实现关联外,还支持用注解的方式实现映射关系,用注解方式实现关联,不需要我们编写映射文件,只需要编写实体类以及全局文件就可以实现实体和表之间的关联映射,非常方便。

数据库中的表多多少少是有相互关联的,例如商品信息表与商品类型表之间就是一种多对一的关联,即多个商品可以对应一个类型,例如,神州笔记本电脑和惠普台式机电脑对应的类型都是电脑。

除了有数据库表之外,我们还需要开发持久类(POJO)用于与表进行关联,首先开发Type.java实体类,它对应表type,在持久化类Type中,需要定义元素类型为ProductInfo(与product_info表关联的持久类)的关联集合属性pi,再使用@OneToMany注解实现Type到ProductInfo的一对多关联。@OneToMany注解的mappedBy属性作用相当于设置inverse=true,表示将关联的主管权反转,即由ProductInfo管理双方的关联关系。mappedBy属性值为关联的多的一方(ProductInfo类)所定义Type类型的属性type。cascade={CascadeType.REMOVE}指定级联删除。

Type.java

package com.hibernate.entity;

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

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name="type",catalog="zhang")
public class Type { //商品类型表
	private int id;
	private String name;
	//关联属性
	private Set<ProductInfo> pi=new HashSet<ProductInfo>();
	public Type() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Type(String name) {
		super();
		this.name = name;
	}
	
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name="id",nullable=false,unique=true)
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	
	@Column(name="name",nullable=false,length=20)
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	//mappedBy属性值为关联的多的一方(ProductInfo)所定义Type类型的属性,mappedBy相当于inverse="true"控制权反转(多的一方管理关联关系),采用级联删除法
	@OneToMany(mappedBy="type",cascade={CascadeType.REMOVE})
	public Set<ProductInfo> getPi() {
		return pi;
	}
	public void setPi(Set<ProductInfo> pi) {
		this.pi = pi;
	}
	
}

接着开发持久类ProductInfo.java,在该类中需要定义一个Type类型的关联属性type,再使用@ManyToOne和@JoinColumn注解实现ProductInfo到Type的多对一关联。@ManyToOne注解的fetch属性可选择项包括:FetchType.EAGER和FetchType.LAZY,前者表示关联类在主类加载的时候同时加载(立即加载),后者表示关联类在被访问时才加载,在多对一时默认值是FetchType.EAGER,在一对多时默认值是FetchType.LAZY。@JoinColumn(name="tid")指定数据库表product_info的tid字段作为外键与数据库表type的主键关联。

ProductInfo.java

package com.hibernate.entity;

import javax.persistence.Column;import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name="product_info",catalog="zhang")
public class ProductInfo { //商品信息实体类
	private int id;
	private String code;
	private String name;
	//关联属性
	private Type type;
	public ProductInfo() {
		super();
		// TODO Auto-generated constructor stub
	}
	public ProductInfo(String code, String name) {
		super();
		this.code = code;
		this.name = name;
	}
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name="id",nullable=false,unique=true)
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	
	@Column(name="code",nullable=false,length=16)
	public String getCode() {
		return code;
	}
	public void setCode(String code) {
		this.code = code;
	}
	
	@Column(name="name",nullable=false,length=255)
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@ManyToOne(fetch=FetchType.EAGER)//立即加载
	@JoinColumn(name="tid",nullable=false)
	public Type getType() {
		return type;
	}
	public void setType(Type type) {
		this.type = type;
	}
    
}

开发完持久类后,还不能形成映射关系,必须在全局配置文件hibernate.cfg.xml中配置数据库资源,并且引入开发的持久类

hibernate.cfg.xml

<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
		
<hibernate-configuration>
  <session-factory>
    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="connection.url">jdbc:mysql://localhost/zhang?characterEncoding=utf8</property>
    <!-- 设置方言(HQL转换成哪种数据库的sql语句) -->
    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="show_sql">true</property>
    <property name="connection.username">root</property>
    <property name="connection.password">zwj19970923</property>

  <!-- 注解方式映射的实体类 -->
  <mapping class="com.hibernate.entity.Type"/>
  <mapping class="com.hibernate.entity.ProductInfo"/>
  </session-factory>

</hibernate-configuration>

测试:

编写单元测试,实现对数据的操作

package com.hibernate.test;


import java.util.Iterator;

import com.hibernate.entity.*;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class HibernateTest { //单元测试

	private Session session;
	private Transaction transaction;
	private SessionFactory sessionFactory;

	@Before
	public void init(){//最开始先执行
		System.out.println("before");
		//加载hibernate配置文件
		StandardServiceRegistry registry=new StandardServiceRegistryBuilder().configure().build();
		try{         
		//根据配置文件初始化sessionFactory
		sessionFactory=new MetadataSources(registry).buildMetadata().buildSessionFactory();
	    //创建session
		session=sessionFactory.openSession();
		//通过session对象开始事务
		transaction=session.beginTransaction();
		}catch(Exception e){
			StandardServiceRegistryBuilder.destroy(registry);
		}
	}

        @Test
	public void oneToManySave(){
		//创建商品信息
		ProductInfo pi=new ProductInfo("z321","OPPLE台灯");
		//创建类别
		Type t=new Type("台灯");
		//关联
		pi.setType(t);
		//保存对象
		session.save(t);
		session.save(pi);
	}

        @Test
	public void oneToManyRead(){
		//根据商品类型获取对应的商品信息
	    Type t=(Type)session.get(Type.class, 24);
	    Iterator<ProductInfo> i=t.getPi().iterator();
	    while(i.hasNext()){
	    	ProductInfo p=i.next();
	    	System.out.println(p.getName());
	    } 
	}

        @Test
	public void oneToManyUpdate(){
		//将神州笔记本电脑的类型修改为台灯
		ProductInfo pi = (ProductInfo)session.get(ProductInfo.class, 27);
		Type t=(Type)session.get(Type.class, 23);
		//更改类型
		pi.setType(t);
		//保存数据
		session.save(pi);
	}

        @Test
	public void oneToManyDelete(){//采用级联删除法
		Type t=(Type)session.get(Type.class, 23);
		session.delete(t);
	}


	@After
	public void destory(){//最后才执行
		System.out.println("after");
		//提交事务
		transaction.commit();
		//关闭session
		session.close();
		//关闭sessionFactory
		sessionFactory.close();
		
	}

}

测试效果,首先执行oneToManySave()单元测试,执行完成后数据库中type表新增加了一项记录,名称为台灯,在数据库product_info表中新增了一条记录,名称为OPPLE台灯

接下来执行oneToManyRead,读取类型为电脑的所有商品信息,以下是控制台输出结果。

可见商品类型为电脑的商品有惠普台式电脑、神州笔记本电脑。

执行oneToManyUpdate()将惠普台式电脑的类型修改为台灯,执行后数据库product_info表中惠普台式电脑的tid字段变更为23

 执行oneToManyDelete(),采用级联删除法,删除type表的台灯类型的同时productInfo表与台灯类型关联的数据也会同时删除,即OPPLE台灯、惠普台式电脑数据会同时删除

 

双向多对多 

数据库中的表还存在着多对多的关联关系,通过建立一张中间表,该中间表中存放着相互关联的两个表的主键(是中间表的外键),进而将两个表形成多对多的关联关系,从本质来看,表与中间表之间是一对多的关联关系,从实际来看,两张表通过中间表形成多对多关系。

以注解的方式实现多对多非常简单,在持久化类AdminInfo中,定义一个元素类型为Function的关联集合fu,再使用@ManyToMany注解和@JoinTable注解实现AdminInfo到Function的多对多关联。@JoinTable注解描述了多对多关系的数据表关系,name属性指定中间表的名称,这里为"power"。joinColumns属性定义中间表power与管理员表admin_info关联的外键列,这里为"aid"。inverseJoinColumn属性定义中间表power与另一端系统功能表function关联的外键列,这里是"fid"。

开发持久化类AdminInfo.java

package com.hibernate.entity;

import java.util.HashSet;
import java.util.Set;
import javax.persistence.JoinColumn;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name="admin_info",catalog="zhang")
public class AdminInfo {
	private int id;
	private String pwd;
	private String name;
	//关联属性
	private Set<Function> fu=new HashSet<Function>();
	public AdminInfo() {
		super();
		// TODO Auto-generated constructor stub
	}
	public AdminInfo(String name,String pwd) {
		super();
		this.pwd = pwd;
		this.name = name;
	}
	
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name="id",nullable=false,unique=true)
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	
	@Column(name="pwd",length=16,nullable=false)
	public String getPwd() {
		return pwd;
	}
	public void setPwd(String pwd) {
		this.pwd = pwd;
	}
	
	@Column(name="name",length=255,nullable=false)
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@ManyToMany
	@JoinTable(name="power",joinColumns={@JoinColumn(name="aid")},inverseJoinColumns={@JoinColumn(name="fid")})
	public Set<Function> getFu() {
		return fu;
	}
	public void setFu(Set<Function> fu) {
		this.fu = fu;
	}
	
}

在持久化类Function中,定义了一个元素类型为AdminInfo的关联集合ais,再使用@ManyToMany注解实现Function到AdminInfo的多对多关联映射。在@ManyToMany注解中,设置属性mappedBy="fu",作用相当于inverse="true",将关联关系控制权反转,即由AdminInfo管理双方关联关系。"fu"是AdminInfo类中定义的元素类型为Function的集合,由于AdminInfo是关联关系的主管方,因此AdminInfo类和Function类的多对多的关联映射是在AdminInfo类中实现的。

持久化类Function.java

package com.hibernate.entity;

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

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

@Entity
@Table(name="function",catalog="zhang")
public class Function {
	private int id;
	private String name;
	//关联属性
	private Set<AdminInfo> ais=new HashSet<AdminInfo>();
	public Function() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Function(String name) {
		super();
		this.name = name;
	}
	
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name="id",nullable=false,unique=true)
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	
	@Column(name="name",length=10,nullable=false)
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	
	@ManyToMany(mappedBy="fu")//控制权反转,由AdminInfo主管关联关系
	public Set<AdminInfo> getAis() {
		return ais;
	}
	public void setAis(Set<AdminInfo> ais) {
		this.ais = ais;
	}
	
}

完成持久化类开发后,就完成了关联映射,但是别忘了在全局配置文件中引入上述两个持久化类

<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
		
<hibernate-configuration>
  <session-factory>
    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="connection.url">jdbc:mysql://localhost/zhang?characterEncoding=utf8</property>
    <!-- 设置方言(HQL转换成哪种数据库的sql语句) -->
    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="show_sql">true</property>
    <property name="connection.username">root</property>
    <property name="connection.password">zwj19970923</property>

  <!-- 注解方式映射的实体类 -->
  <mapping class="com.hibernate.entity.Type"/>
  <mapping class="com.hibernate.entity.ProductInfo"/>
  <mapping class="com.hibernate.entity.AdminInfo"/>
  <mapping class="com.hibernate.entity.Function"/>
  </session-factory>

</hibernate-configuration>

测试:

编写单元测试,主要测试保存管理员以及系统功能对象,以及通过管理员对象获取对应的系统功能

package com.hibernate.test;


import java.util.Iterator;

import com.hibernate.entity.*;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class HibernateTest { //单元测试

	private Session session;
	private Transaction transaction;
	private SessionFactory sessionFactory;

	@Before
	public void init(){//最开始先执行
		System.out.println("before");
		//加载hibernate配置文件
		StandardServiceRegistry registry=new StandardServiceRegistryBuilder().configure().build();
		try{         
		//根据配置文件初始化sessionFactory
		sessionFactory=new MetadataSources(registry).buildMetadata().buildSessionFactory();
	    //创建session
		session=sessionFactory.openSession();
		//通过session对象开始事务
		transaction=session.beginTransaction();
		}catch(Exception e){
			StandardServiceRegistryBuilder.destroy(registry);
		}
	}

        @Test
	public void manyToManySave(){
		//创建两个管理员对象
		AdminInfo ad_1=new AdminInfo("管理员1","zwj1999");
		AdminInfo ad_2=new AdminInfo("管理员2","a1380");
		//创建3个功能
		Function f1=new Function("订单管理");
		Function f2=new Function("商品管理");
		Function f3=new Function("账户管理");
		//分配不同功能到不同的管理员上
		ad_1.getFu().add(f1);
		ad_1.getFu().add(f2);
		ad_1.getFu().add(f3);
		ad_2.getFu().add(f3);
		//保存功能
		session.save(f1);
		session.save(f2);
		session.save(f3);
		//保存两个管理员
		session.save(ad_1);
		session.save(ad_2);
	}

        @Test
	public void manyToManyRead(){
		//读取管理员1的姓名,并且读其拥有的功能权限
		AdminInfo ai=(AdminInfo)session.get(AdminInfo.class, 9);
		//获取对应的功能
		Iterator<Function> i=ai.getFu().iterator();
	        System.out.printf("%s\n",ai.getName()+"拥有的功能有:");
	        while(i.hasNext()){
	    	Function fu=(Function)i.next();
	    	System.out.printf("%s\n", fu.getName());
	        }
	}


	@After
	public void destory(){//最后才执行
		System.out.println("after");
		//提交事务
		transaction.commit();
		//关闭session
		session.close();
		//关闭sessionFactory
		sessionFactory.close();
		
	}

}

执行manyToManySave()数据库admin_info表增加了两个管理员,function表增加了三个功能

除此之外,中间表power也自动增加了几项记录,从中间表power可见,id为9的管理员拥有id为38、37、39的系统功能,id为10的管理员拥有id为39的系统功能,表之间的多对多也就明显的显示出来了。

执行manyToManyRead()读取管理员1的姓名,以及拥有的系统功能,可见管理员1的id为9,控制台输出结果如下

 

 双向一对一

一对一关联关系的实例很多,例如管理员信息表和管理员详细信息表之间就是一对一关系,一对一关联有基于主键的关联和基于外键的关联,这里主要说明基于主键的关联,首先在数据库中创建admin_detail表,该表用于存放管理员的详细信息,和已经存在的admin_info表形成一对一关系,基于主键的一对一关联必须修改admin_info表的主键生成策略,需要采用外键生成策略来实现,即admin_info表的id字段既是该表的主键,也是该表的外键(admin_detail表的主键),关系图如下。

对持久化类AdminInfo进行修改,增加AdminDetail类型关联属性ad,然后修改主键生成策略,使用@GenericGenerator、@Id、@GeneratedValue和@Column这一组注解将AdminInfo类中定义的AdminDetail类型的属性ad的主键来作为AdminInfo类对象的主键。

其中@GenericGenerator注解声明了一个Hibernate的主键生成策略,支持十三种。该注解的name属性指定生成器名称,strategy属性指定具体生成器的类名(即生成策略),这里选择foreign策略,表示使用另一个关联对象的主键,通常和<one-to-one>联合起来使用。parameters属性得到strategy指定的具体生成器所用到的参数,设置value="ad"表示将当前类AdminInfo中定义的AdminDetail类型的ad属性的主键来作为AdminInfo类对象的主键。

再使用@OneToOne注解实现AdminInfo与AdminDetail的基于主键的一对一关联关系,设置属性mappedBy="ai"作用相当于inverse=true表示将关联关系的控制权反转,即由AdminDetail方管理关联关系,ai为AdminDetail类中定义的AdminInfo类型的关联属性。设置属性optional=false指定关联属性ad不能为空。

持久化类AdminInfo.java

package com.hibernate.entity;

import java.util.HashSet;
import java.util.Set;
import javax.persistence.GeneratedValue;
import javax.persistence.JoinColumn;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;

@Entity
@Table(name="admin_info",catalog="zhang")
public class AdminInfo {
	private int id;
	private String pwd;
	private String name;
	//关联属性
	private AdminDetail ad;
	private Set<Function> fu=new HashSet<Function>();
	public AdminInfo() {
		super();
		// TODO Auto-generated constructor stub
	}
	public AdminInfo(String name,String pwd) {
		super();
		this.pwd = pwd;
		this.name = name;
	}
	
	@GenericGenerator(name="generator",strategy="foreign",parameters=@Parameter(name="property",value="ad"))//外键生成主键策略
	@Id
	@GeneratedValue(generator="generator")
	@Column(name="id",nullable=false,unique=true)
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	
	@Column(name="pwd",length=16,nullable=false)
	public String getPwd() {
		return pwd;
	}
	public void setPwd(String pwd) {
		this.pwd = pwd;
	}
	
	@Column(name="name",length=255,nullable=false)
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	@ManyToMany
	@JoinTable(name="power",joinColumns={@JoinColumn(name="aid")},inverseJoinColumns={@JoinColumn(name="fid")})
	public Set<Function> getFu() {
		return fu;
	}
	public void setFu(Set<Function> fu) {
		this.fu = fu;
	}
	
	@OneToOne(mappedBy="ai",optional=false) //optional设置关联的属性不能为空
	public AdminDetail getAd() {
		return ad;
	}
	public void setAd(AdminDetail ad) {
		this.ad = ad;
	}
	
}

在持久化类AdminDetail中,首先定义了AdminInfo类型的关联属性ai,再使用@OneToOne和@PrimaryKeyJoinColumn注解实现AdminDetail与AdminInfo的基于主键的一对一关联。设置cascade=CascadeType.REMOVE表示级联删除。@PrimaryKeyJoinColumn注解表示两个实体类通过主键关联。

package com.hibernate.entity;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;

@Entity
@Table(name="admin_detail",catalog="zhang")
public class AdminDetail {
	private int id;
	private String realName;
	private String address;
	//关联属性
	private AdminInfo ai;
	
	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name="id",unique=true,nullable=false)
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	
	@Column(name="realName",nullable=false,length=255)
	public String getRealName() {
		return realName;
	}
	public void setRealName(String realName) {
		this.realName = realName;
	}
	
	@Column(name="address",nullable=true,length=20)
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	
	@OneToOne(cascade=CascadeType.REMOVE)//级联删除法
	@PrimaryKeyJoinColumn //表示两个实体通过主键关联
	public AdminInfo getAi() {
		return ai;
	}
	public void setAi(AdminInfo ai) {
		this.ai = ai;
	}
	public AdminDetail() {
		super();
		// TODO Auto-generated constructor stub
	}
	public AdminDetail(String realName) {
		super();
		this.realName = realName;
	}
	public AdminDetail(String realName, String address) {
		super();
		this.realName = realName;
		this.address = address;
	}
	
}

最后也是最重要,最容易被忽略的,就是在全局配置文件中引入注解的持久化类

<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
		
<hibernate-configuration>
  <session-factory>
    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="connection.url">jdbc:mysql://localhost/zhang?characterEncoding=utf8</property>
    <!-- 设置方言(HQL转换成哪种数据库的sql语句) -->
    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="show_sql">true</property>
    <property name="connection.username">root</property>
    <property name="connection.password">zwj19970923</property>

  <!-- 注解方式映射的实体类 -->
  <mapping class="com.hibernate.entity.Type"/>
  <mapping class="com.hibernate.entity.ProductInfo"/>
  <mapping class="com.hibernate.entity.AdminInfo"/>
  <mapping class="com.hibernate.entity.Function"/>
  <mapping class="com.hibernate.entity.AdminDetail"/>
  </session-factory>

</hibernate-configuration>

测试:

编写单元测试,代码如下:

package com.hibernate.test;


import java.util.Iterator;

import com.hibernate.entity.*;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class HibernateTest { //单元测试

	private Session session;
	private Transaction transaction;
	private SessionFactory sessionFactory;

	@Before
	public void init(){//最开始先执行
		System.out.println("before");
		//加载hibernate配置文件
		StandardServiceRegistry registry=new StandardServiceRegistryBuilder().configure().build();
		try{         
		//根据配置文件初始化sessionFactory
		sessionFactory=new MetadataSources(registry).buildMetadata().buildSessionFactory();
	    //创建session
		session=sessionFactory.openSession();
		//通过session对象开始事务
		transaction=session.beginTransaction();
		}catch(Exception e){
			StandardServiceRegistryBuilder.destroy(registry);
		}
	}

        @Test
	public void oneToOneSave(){
        //创建两个管理员
		AdminInfo ai_1=new AdminInfo("管理员1","1234");
		AdminInfo ai_2=new AdminInfo("管理员2","1234555");
		//创建两个管理员详细信息
		AdminDetail ad_1=new AdminDetail("张三","广东广州");
		AdminDetail ad_2=new AdminDetail("李四","广东惠州");
		//管理员设置详细信息
		ai_1.setAd(ad_1);
		ai_2.setAd(ad_2);
		ad_1.setAi(ai_1);
		ad_2.setAi(ai_2);
		//保存数据
		session.save(ad_1);
		session.save(ad_2);
		session.save(ai_1);
		session.save(ai_2);
	}
	
	@Test
	public void testOneToOneRead(){
		//读取管理员信息
		AdminInfo ai=(AdminInfo)session.get(AdminInfo.class, 3);
		System.out.println(ai.getName());
		//从管理员信息中读取管理员详细信息
		AdminDetail ad=(AdminDetail)ai.getAd();
		System.out.println(ad.getRealName());
	}
	
	@Test
	public void testOneToOneUpdate(){
		//读取管理员详细信息
		AdminDetail ad=session.get(AdminDetail.class, 3);
		//获取与管理员详细信息关联的管理员信息
		AdminInfo ai=(AdminInfo)ad.getAi();
		System.out.println(ai.getName());
		//更改管理员信息中的管理员名称
		ai.setName("管理员10");
		//更新
		session.save(ai);
	}
	
	@Test
	public void testOneToOneDelete(){
		//采用级联方法删除管理信息
		AdminDetail ad=session.get(AdminDetail.class, 3);
		session.delete(ad);
	}



	@After
	public void destory(){//最后才执行
		System.out.println("after");
		//提交事务
		transaction.commit();
		//关闭session
		session.close();
		//关闭sessionFactory
		sessionFactory.close();
		
	}

}

测试结果:

执行oneToOneSave()方法,设置一对一关联关系,向admin_info表和admin_detail表插入数据,执行后admin_info表如下

admin_detail表数据如下

插入操作成功,接下来执行testOneToOneRead()进行数据的读取,这里读取的是管理员1和管理员1的真实姓名,执行单元测试后控制台输出结果如下:

接下来进行数据更新,执行testOneToOneUpdate()单元测试,获取id为3的详细信息,修改对应的管理员姓名为管理员10,详细信息id为3对应的管理员为管理员1,修改后admin_info表中管理员1应该变更为管理员10,执行结果如下:

接下来进行删除操作,由于持久化类AdminDetail中@OneToOne注解内配置了cascade=CascadeType.REMOVE的属性,即使用级联删除方法,因此,在删除admin_detail表中数据的同时,在admin_info表中与该记录有关联关系的数据将会同时删除,以上单元测试testOneToOneDelete()删除的是admin_detail表中id为3的记录,那么执行操作后admin_info表中id为3(即管理员10)的记录将会同时被删除,执行结果如下:

admin_detail表

 admin_info表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值