您现在的位置是:首页 > 电脑 > 

JPA OneToOne单向和双向测试验证

2025-07-17 23:26:26
JPA OneToOne单向和双向测试验证 原文: 最近学习Jpa,其中的OneToOne等关系映射比较模糊,今天主要尝试写了个OneToOne的demo,当做练手,也加深下理解。  说起OneToOne,就是一对一映射,现实生活中比较常见的例子就是一个人有一个身份证,一个丈夫只

JPA OneToOne单向和双向测试验证

原文:

最近学习Jpa,其中的OneToOne等关系映射比较模糊,今天主要尝试写了个OneToOne的demo,当做练手,也加深下理解。 
说起OneToOne,就是一对一映射,现实生活中比较常见的例子就是一个人有一个身份证,一个丈夫只能有一个老婆,当然一个老婆只能有一个丈夫,以上都是正常情况下的现实场景,作犯科的当然不在考虑了。一个丈夫实例应该仅仅和一个妻子实例一一对应。下面新建工程,基本的测试demo template我会在之后上传。 
由于OneToOne有单向和双向的区别,这里先简单介绍单向的,然后再介绍双向的。这是我的目录结构: 
 
entity包下是对实体的定义, 
repo包下是对数据接入层接口的定义 
service和serviceimpl 是服务的接口定义和实现,在这里不需要,暂时不用管这个包 
test下是自己的测试类,为啥不用Junit嘞?这样自己测试可以方便的看到数据库变化(其实是自己还不熟悉Junit…)

s废话不多说,开始干活

新建Husband类和Wife类

public class Husband implements Serializable {@Id@GeneratedValue(strategy = GenerationType.IDETITY)private Integer hid;@onull@Column(nullable = false)private String name;@OneToOne(targetEntity = )@JoinColumn(name = wife_id,referencedColumname = wid)private Wife wife;public Husband(){}public Husband(String name){ = name;}@Overridepublic String toString() {return Husband{ hid=  hid , name=	  name  	\		 , wife=  wife 	}	;}
}
  • 1
  • 2
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 2
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

public class Wife implements Serializable {@Id@GeneratedValue(strategy = GenerationType.IDETITY)private Integer wid;@onull@Column(nullable = false)private String name;public Wife(){}public Wife(String name){ = name;}@Overridepublic String toString() {return Wife{ wid=  wid , name=	  name  	\		 	}	;}@Overridepublic int hashCode(){return wid;}@Overridepublic boolean equals(Object obj){if(!(obj instanceof Wife))return  false;Wife wife = (Wife) obj;if(wife.getWid() == this.wid)return true;elsereturn false;}
}
  • 1
  • 2
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 2
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 0
  • 1
  • 2
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 40

接下来新建两个数据接入层接口,有人喜欢命名为 ××Dao,有人喜欢命名为 ××Repo,我采用后者, 
HusbandRepo

@Transactional
public interface HusbandRepo extends JpaRepository<Husband,Integer> {public Husband save(Husband husband);public Husband findByame(String name);
}
  • 1
  • 2
  • 4
  • 5
  • 6
  • 7
  • 8

WifeRepo

public interface WifeRepo extends JpaRepository<Wife,Integer> {public Wife save(Wife wife);public Wife findByame(String name);}
  • 1
  • 2
  • 4
  • 5
  • 6
  • 7

关于这两个接口因为继承了JpaRepositiry,很多方法都已经预设好了,相当方便,只需要写两个我们需要的自定义的方法即可。每个Repo都有保存实例和通过名字查实例的方法。

接下来写OneToOneTest测试类

public class One2OneTest {public static void main(String[] args){ApplicationContext conatext = new ClassPathXmlApplicationContext(classpath*:*config.xml);HusbandRepo husbandRepo = conatext.getBean(husbandRepo,);WifeRepo wifeRepo = conatext.getBean(wifeRepo,);//添加测试代码}
}
  • 1
  • 2
  • 4
  • 5
  • 6
  • 7
  • 8

测试新建实例

        Husband husband = new Husband(Jack);Wife wife = new Wife(Rose);husband.setWife(wife);wifeRepo.save(wife);husbandRepo.save(husband);
  • 1
  • 2
  • 4
  • 5

由于Husband和Wife使用各自的Repo进行持久化,Husband是关系维护端且无持久化级联设置,所以只能先wifeRepo.save(wife),把wife纳入实例管理,然后再使用husbandRepo.save(husband)这样才能在数据库到对应的wife进行对应。执行完毕后,数据库表: 
 
两个实例都已存储完成。

然后再考虑另一种情况,绝对的钟情与对方在现实生活中是不可能的,也就是说,作为主导方的Husband,也有可能将别人的妻子据为己有,所以数据库中已经绑定wife是否能被其他Husband绑定呢?

        Husband husband = new Husband(Mike);Wife wife = wifeRepo.findByame(Rose);husband.setWife(wife);husbandRepo.save(husband);
  • 1
  • 2
  • 4

新建一个Husband Mike,将Mike的wife设置为Jack的wife Rose,程序竟然没报错,数据库如图: 
 
Jack和Mike的妻子竟然是同一个,Jack的老婆被抢走了竟然不知道这一点,多可怕!!!所以关于OneToOne映射,我的理解是对关系维护端而言的,一个Husband最多有且仅有一个wife,但是被管理的wife而言,对这一切一无所知(最起码在单向OneToOne是这样)。

再考虑如果我们删除掉Husband而保留对应的Wife会怎样?在这里我们新建一对夫妇,老王和老王媳妇儿

        Husband husband = new Husband(老王);Wife wife = new Wife(老王媳妇儿);husband.setWife(wife);wifeRepo.save(wife);husbandRepo.save(husband);
  • 1
  • 2
  • 4
  • 5

然后删除老王

Husband husband = husbandRepo.findByame(老王);husbandRepo.delete(husband.getHid());
  • 1
  • 2

程序未报错,再看数据库 
 
老王已经不在了,而老王媳妇儿还在

下一步,删除wife而保留对应的husband,在执行下面代码之前,先把老王恢复回来吧!

        Wife wife = wifeRepo.findByame(老王媳妇儿);wifeRepo.delete(wife.getWid());
  • 1
  • 2

然后程序提示 

因为老王的外键还保留着老王媳妇儿的主键,你把老王媳妇儿删除了,老王不到媳妇儿了,他表示不开心(一句商量都没有就把媳妇儿丢了),所以为了安抚各方,我们应该把老王的媳妇儿外键给清掉,这样就可以顺利删除老王媳妇儿了,代码很简单,去遍历所有Husband就行了,因为从老王媳妇儿那里无从知晓谁是她丈夫。

        Wife wife = wifeRepo.findByame(小六媳妇儿);List<Husband> list = husbandRepo.findAll();for(int i=0;i<list.size();i){Husband husband = list.get(i);if(husband.getWife().equals(wife)){husband.setWife(null);husbandRepo.save(husband);}}wifeRepo.delete(wife.getWid());
  • 1
  • 2
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1

这样就顺利删除了作为被维护端的Wife,所以在单向的OneToOne中,关系被维护端要负责与被维护端的关系建立,同时也要负责与被维护端的关系解除,而被维护端对这些一无所知。

有没有感觉每次新建一次联系都要先使用wifeRepo.save()再使用husbandRepo.save()比较繁琐?既然使用了框架,为啥还这么麻烦?下一步只需要稍稍改动一个地方即可。修改Husband类

public class Husband implements Serializable {@Id@GeneratedValue(strategy = GenerationType.IDETITY)private Integer hid;@onull@Column(nullable = false)private String name;@OneToOne(targetEntity = ,cascade = {CascadeType.PERSIST,CascadeType.REMOVE})@JoinColumn(name = wife_id,referencedColumname = wid)private Wife wife;public Husband(){}public Husband(String name){ = name;}@Overridepublic String toString() {return Husband{ hid=  hid , name=	  name  	\		 , wife=  wife 	}	;}
}
  • 1
  • 2
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 2
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

仔细对比,发现仅仅是在@OneToOne注解后加了cascade策略,CascadeType.PERSIST代表级联保存,CascadeType.REMOVE代表级联删除,所以现在可以在保存Husband的时候保存Wife,在删除Husband时候删除Wife了

        //加入级联持久化,Husband可以直接把Wife保存,不需要先保存WifeHusband husband = new Husband(Tom);Wife wife = new Wife(Jerry);husband.setWife(wife);husbandRepo.save(husband);//加入级联删除,删除HusbandHusband husband = husbandRepo.findByame(Tom);husbandRepo.delete(husband.getHid());
  • 1
  • 2
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

OK,单向OneToOne的主要问题已经解决,下面是对双向OneToOne的一些测试。

双向OneToOne 
双向OneToOne其实是在原来单向的基础上,使得被维护端也可以知道与自己有关那一方的信息,在原来单向的工程的基础上只需修改一点,打开Wife类,为其增加一个字段Husband,

    @OneToOne(mappedBy = wife)private Husband husband;
  • 1
  • 2

mappedBy表明了关系被维护端,这样我们就可以通过Wife得到对应的husband。

下面进行测试 
先来一组夫妻的新建:

        Husband husband = new Husband(Jack);Wife wife = new Wife(Rose);husband.setWife(wife);husbandRepo.save(husband);
  • 1
  • 2
  • 4

可以发现每次新建都是通过关系维护端Husband来保存Wife,能不能通过Wife来保存Husband呢?编写代码

        Husband husband = new Husband(Barney);Wife wife = new Wife(Robin);wife.setHusband(husband);wifeRepo.save(wife);
  • 1
  • 2
  • 4

结果如图 
 
可见二者都可以保存,但是Husband方的外键无值,也就是说Barney和Robin并未建立夫妻的联系。后来想到如果在Wife加上级联操作会不会能成功,所以做了如下改变:

给Wife添加级联

@OneToOne(mappedBy = wife,cascade = {CascadeType.PERSIST,CascadeType.REMOVE})private Husband husband;
  • 1
  • 2

测试代码

        Husband husband = new Husband(Marshall);Wife wife = new Wife(Lily);wife.setHusband(husband);wifeRepo.save(wife);
  • 1
  • 2
  • 4

结果如图 
 
仍然不能建立关系,所以关系的建立还是要依赖关系维护端来操作。

最后一个问题,既然关系被维护端可以知道对应的维护端,那么如果两个Husband来共同映射一个Wife会怎样?

        Husband husband = new Husband(Ted);     this is fineWife wife = new Wife(Tracy);husband.setWife(wife);husbandRepo.save(husband);wife = wifeRepo.findByame(Tracy);husband = wife.getHusband();print(Tracy	s wife is husband);husband = husbandRepo.findByame(Barney);husband.setWife(wife);husbandRepo.save(husband);husband = husbandRepo.findByame(Barney);Wife wife1 = husband.getWife();println(Barney	s wife is wife1);
  • 1
  • 2
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 14
  • 15
  • 16

我们先建立一对夫妻Ted和Tracy,然后设置Barney的妻子也为Tracy

然后从Wife获得Husband信息

        wife = wifeRepo.findByame(Tracy);husband = wife.getHusband();print(Tracy	s wife is husband);
  • 1
  • 2

结果 

错误信息指出,有多个行的Wife外键是4,所以多个Husband绑定一个Wife在双向OneToOne中会爆出错误。

总结上述

  1. 无论单向还是双向,关系的保存都需要关系维护段来进行操作
  2. 所谓一对一映射,其实是关系维护端的映射关系,关系维护端确实只关联一个被维护端,但是被维护端和几个维护段关联就不得而知了
  3. 关系维护端可以主动修改关系,而被维护端只能被动接受

#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格

本文地址:http://www.dnpztj.cn/diannao/905358.html

相关标签:无
上传时间: 2024-06-03 22:04:04
留言与评论(共有 18 条评论)
本站网友 二手房个人所得税
14分钟前 发表
  由于OneToOne有单向和双向的区别,这里先简单介绍单向的,然后再介绍双向的
本站网友 后沙峪二手房出售
8分钟前 发表
下面进行测试  先来一组夫妻的新建: Husband husband = new Husband(Jack);Wife wife = new Wife(Rose);husband.setWife(wife);husbandRepo.save(husband);124 可以发现每次新建都是通过关系维护端Husband来保存Wife,能不能通过Wife来保存Husband呢?编写代码 Husband husband = new Husband(Barney);Wife wife = new Wife(Robin);wife.setHusband(husband);wifeRepo.save(wife);124 结果如图    可见二者都可以保存,但是Husband方的外键无值,也就是说Barney和Robin并未建立夫妻的联系
本站网友 天津渤海银行
25分钟前 发表
接下来写OneToOneTest测试类 public class One2OneTest {public static void main(String[] args){ApplicationContext conatext = new ClassPathXmlApplicationContext(classpath*
本站网友 钱氏中医院
23分钟前 发表
把wife纳入实例管理,然后再使用husbandRepo.save(husband)这样才能在数据库到对应的wife进行对应
本站网友 北京租房114
4分钟前 发表
有没有感觉每次新建一次联系都要先使用wifeRepo.save()再使用husbandRepo.save()比较繁琐?既然使用了框架,为啥还这么麻烦?下一步只需要稍稍改动一个地方即可
本站网友 广州求职
29分钟前 发表
然后再考虑另一种情况,绝对的钟情与对方在现实生活中是不可能的,也就是说,作为主导方的Husband
本站网友 昆明美食
1分钟前 发表
*config.xml);HusbandRepo husbandRepo = conatext.getBean(husbandRepo
本站网友 大全
13分钟前 发表
JPA OneToOne单向和双向测试验证 原文: 最近学习Jpa,其中的OneToOne等关系映射比较模糊,今天主要尝试写了个OneToOne的demo,当做练手,也加深下理解
本站网友 感冒药停用停产
23分钟前 发表
也有可能将别人的妻子据为己有,所以数据库中已经绑定wife是否能被其他Husband绑定呢? Husband husband = new Husband(Mike);Wife wife = wifeRepo.findByame(Rose);husband.setWife(wife);husbandRepo.save(husband);124 新建一个Husband Mike,将Mike的wife设置为Jack的wife Rose,程序竟然没报错,数据库如图:    Jack和Mike的妻子竟然是同一个,Jack的老婆被抢走了竟然不知道这一点,多可怕!!!所以关于OneToOne映射,我的理解是对关系维护端而言的,一个Husband最多有且仅有一个wife,但是被管理的wife而言,对这一切一无所知(最起码在单向OneToOne是这样)
本站网友 windows7官方
13分钟前 发表
CascadeType.REMOVE})private Husband husband;12 测试代码 Husband husband = new Husband(Marshall);Wife wife = new Wife(Lily);wife.setHusband(husband);wifeRepo.save(wife);124 结果如图    仍然不能建立关系,所以关系的建立还是要依赖关系维护端来操作
本站网友 十里铺二手房
7分钟前 发表
这是我的目录结构:    entity包下是对实体的定义,  repo包下是对数据接入层接口的定义  service和serviceimpl 是服务的接口定义和实现,在这里不需要,暂时不用管这个包  test下是自己的测试类,为啥不用Junit嘞?这样自己测试可以方便的看到数据库变化(其实是自己还不熟悉Junit…) s废话不多说,开始干活 新建Husband类和Wife类 public class Husband implements Serializable {@Id@GeneratedValue(strategy = GenerationType.IDETITY)private Integer hid;@onull@Column(nullable = false)private String name;@OneToOne(targetEntity = )@JoinColumn(name = wife_id
本站网友 宫颈癌预防针
23分钟前 发表
referencedColumname = wid)private Wife wife;public Husband(){}public Husband(String name){ = name;}@Overridepublic String toString() {return Husband{ hid=  hid 
本站网友 中国基础教育研究会
18分钟前 发表
Wife wife = wifeRepo.findByame(小六媳妇儿);List<Husband> list = husbandRepo.findAll();for(int i=0;i<list.size();i){Husband husband = list.get(i);if(husband.getWife().equals(wife)){husband.setWife(null);husbandRepo.save(husband);}}wifeRepo.delete(wife.getWid());124567891011121 这样就顺利删除了作为被维护端的Wife,所以在单向的OneToOne中,关系被维护端要负责与被维护端的关系建立,同时也要负责与被维护端的关系解除,而被维护端对这些一无所知
本站网友 铜陵化学工业集团有限公司
17分钟前 发表
最后一个问题,既然关系被维护端可以知道对应的维护端,那么如果两个Husband来共同映射一个Wife会怎样? Husband husband = new Husband(Ted); this is fineWife wife = new Wife(Tracy);husband.setWife(wife);husbandRepo.save(husband);wife = wifeRepo.findByame(Tracy);husband = wife.getHusband();print(Tracy s wife is husband);husband = husbandRepo.findByame(Barney);husband.setWife(wife);husbandRepo.save(husband);husband = husbandRepo.findByame(Barney);Wife wife1 = husband.getWife();println(Barney s wife is wife1);124567891011121141516 我们先建立一对夫妻Ted和Tracy,然后设置Barney的妻子也为Tracy 然后从Wife获得Husband信息 wife = wifeRepo.findByame(Tracy);husband = wife.getHusband();print(Tracy s wife is husband);12 结果  错误信息指出,有多个行的Wife外键是4,所以多个Husband绑定一个Wife在双向OneToOne中会爆出错误
本站网友 血型减肥
29分钟前 发表
);WifeRepo wifeRepo = conatext.getBean(wifeRepo
本站网友 新蔡在线
16分钟前 发表
*config.xml);HusbandRepo husbandRepo = conatext.getBean(husbandRepo
本站网友 iso是什么文件
3分钟前 发表
执行完毕后,数据库表:    两个实例都已存储完成