一对一关联查询注解@OneToOne的实例详解
表的关联查询比较复杂,应用的场景很多,本文根据自己的经验解释@OneToOne注解中的属性在项目中的应用。本打算一篇博客把增删改查写在一起,但是在改的时候遇到了一些问题,感觉挺有意思,所以写下第二篇专门讲修改。
一、单向@OneToOne实例详解
假设一个场景,一个人只能领养一只宠物,根据人能够找到宠物,并且查看宠物的信息,关系是单向的。
创建人与宠物的数据表结构。下载地址:Person,Pet数据库建表。
创建实体。
Person.java
package com.my.model; import java.io.Serializable; import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ForeignKey;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table; import org.hibernate.annotations.Cascade;
import org.springframework.beans.factory.annotation.Autowired; @Entity
@Table(name = "person")
public class Person implements Serializable{
@Id
// id自动生成
@GeneratedValue
@Column(name = "id")
private Long id;
@Column(name = "name")
private String name; //cascade:表的级联操作
@OneToOne(fetch=FetchType.LAZY,cascade = CascadeType.ALL) //JPA注释: 一对一 关系 //referencedColumnName:参考列名,默认的情况下是列表的主键
//nullable=是否可以为空,
//insertable:是否可以插入,
//updatable:是否可以更新
// columnDefinition=列定义,
//foreignKey=外键
@JoinColumn(name="pet_id",referencedColumnName="id",nullable=false)
private Pet pet; @Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", pet=" + pet + "]";
} }
Pet.java
package com.my.model; import java.io.Serializable; import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table; @Entity
@Table(name = "pet")
public class Pet implements Serializable{
@Id
// id自动生成
@GeneratedValue
@Column(name = "id")
private Long id;
@Column(name = "pet_name")
private String petName;
@Column(name = "pet_class")
private String petClass; //省略set,get方法。 @Override
public String toString() {
return "Pet [id=" + id + ", petName=" + petName + ", petClass="
+ petClass + "]";
} }
注解@OneToOne的接口定义如下:
public interface OneToOne extends Annotation {
public abstract Class targetEntity();
public abstract CascadeType[] cascade();
public abstract FetchType fetch();
public abstract boolean optional();
public abstract String mappedBy();
public abstract boolean orphanRemoval();
}
注解@OneToOne的属性:
cascade:关联属性,这个属性定义了当前类对象操作了之后,级联对象的操作。本例中定义了:CascadeType.ALL,当前类增删改查改变之后,关联类跟着增删改查。
fetch属性:FetchType类型的属性。可选择项包括:FetchType.EAGER 和FetchType.LAZY。 FetchType.EAGER表示关系类(本例是OrderItem类)在主类加载的时候同时加载,FetchType.LAZY表示关系类在被访问时才加载。默认值是FetchType.LAZY。
mappedBy:拥有关联关系的域,如果关系是单向的就不需要,双向关系表,那么拥有关系的这一方有建立、解除和更新与另一方关系的能力,而另一方没有,只能被动管理,这个属性被定义在关系的被拥有方。双向@OneToOne,双向@OneToMany,双向@ManyToMany。
注解@JoinColumn的接口定义:
public interface JoinColumn extends Annotation {
public abstract String name();
public abstract String referencedColumnName();
public abstract boolean unique();
public abstract boolean nullable();
public abstract boolean insertable();
public abstract boolean updatable();
public abstract String columnDefinition();
public abstract String table();
public abstract ForeignKey foreignKey();
}
注解@JoinColumn的属性:
name属性:外键列的名称,默认情况下是:引用实体的字段名称 +“_”+ 被引用的主键列的名称。一般也可以自定义,一般见名知意,就可以采用默认值。
referencedColumnName属性:参考列,默认值是关联表的主键。例如你可以定义pet_name为参考列,那么就会将pet的name的值关联到这一列。
创建类:TableRelationController
package com.my.controller; import javax.annotation.Resource; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import com.alibaba.fastjson.JSONObject;
import com.my.model.GoodInfoEntity;
import com.my.service.TableRelationService; /**
* 用于测试表的七种对应关系
* @author by_ww
*
*/
@RestController
@RequestMapping(value = "/tableRelation")
public class TableRelationController { @Resource
private TableRelationService tableRelationService; // 增加
@RequestMapping(value = "/save")
public Long save(@RequestBody JSONObject record) throws Exception
{
return tableRelationService.save(record);
}
// 查询
@RequestMapping(value = "/query")
public JSONObject query(@RequestBody JSONObject record) throws Exception
{
return tableRelationService.getPet(record);
}
// 删除
@RequestMapping(value = "/delete")
public Long delete(@RequestBody JSONObject record) throws Exception
{
return tableRelationService.delete(record);
} // 更改
@RequestMapping(value = "/update")
public Long update(@RequestBody JSONObject record) throws Exception
{
return tableRelationService.update(record);
}
}
创建TableRelationService类:
package com.my.service; import javax.annotation.Resource;
import javax.persistence.EntityManagerFactory; import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.my.dao.PersonJPA;
import com.my.dao.PetJPA;
import com.my.model.Person;
import com.my.model.Pet; @Service
public class TableRelationService { @Resource
private PersonJPA personJPA; @Resource
private PetJPA petJPA; private SessionFactory sessionFactory; @Autowired
public void SomeService(EntityManagerFactory factory) {
if(factory.unwrap(SessionFactory.class) == null){
throw new NullPointerException("factory is not a hibernate factory");
}
this.sessionFactory = factory.unwrap(SessionFactory.class);
} public Long save(JSONObject record) { // 组装person
Person person = new Person();
person.setName(record.getString("personName"));
JSONObject petObj = record.getJSONObject("pet");
if (null != petObj) {
Pet pet = new Pet();
pet.setPetName(petObj.getString("petName"));
pet.setPetClass(petObj.getString("petClass")); person.setPet(pet);
}
personJPA.save(person); return 4l;
} public JSONObject getPet(JSONObject record) { Person person = personJPA.findOne(record.getLongValue("id"));
System.out.println(person.toString());
return (JSONObject) JSON.toJSON(person);
} public Long delete(JSONObject record) {
personJPA.delete(record.getLongValue("id"));
return 4l;
}
@Transactional
public Long update(JSONObject record) { Session session = sessionFactory.getCurrentSession();
// Session session = sessionFactory.openSession();
session.beginTransaction(); Person personRecord = session.get(Person.class, record.getLongValue("id")); personRecord.setName(record.getString("personName")); JSONObject petObject = record.getJSONObject("pet"); if (petObject != null) {
// 如果这里的pet为空
Pet petRecord = null;
if (personRecord.getPet() != null) {
petRecord = session.get(Pet.class, personRecord.getPet().getId());
} petRecord.setPetName(petObject.getString("petName"));
petRecord.setPetClass(petObject.getString("petClass")); }
personJPA.save(personRecord);
return 4l;
} }
注意:这里关联表更改的时候要注意,如果没有配置好会出现异常。
org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
这是在spring的事务实现中需要判断当前线程中的事务是否同步,而没有事务的时候,那个判断是否同步的方法会因为get返回初始的null值而返回false,最终导致throw一个Could not obtain transaction-synchronized Session for current thread的异常,解决方法有两个:
1)加事物控制。
@Transactional
2)重新生成session。
Session session = sessionFactory.openSession();
配置文件中:
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext
测试:postMan发送请求:
增加:
{
"personName":"Steven",
"pet" : {
"petName":"旺旺",
"petClass":"dog"
}
}
查询:
{
"id" : 19
}
{
"id": 19,
"pet": {
"id": 19,
"petClass": "dog",
"petName": "旺旺"
},
"name": "Steven"
}
删除:
{
"id" : 19
}
更改:
这里更改了petName,petClass
{
"id" : 19,
"personName":"Steven",
"pet" :{
"petName" : "steven4",
"petClass" : "cow"
}
}
问题:
在更新的时候存在这样的问题,如果刚开是插入数据的时候,没有插入从表Pet的数据。
{
"personName":"King"
}
此时如果想在更新数据,给King添加一个pet数据,那么就会一直插入。
{
"id" : 20,
"personName": "King",
"pet" :{
"petName" : "阿旺",
"petClass" : "cow"
}
}
这是因为程序在执行save操作的时候,默默的执行了下面的语句。
Hibernate: select person0_.id as id1_2_1_, person0_.name as name2_2_1_, person0_.pet_id as pet_id3_2_1_, pet1_.id as id1_3_0_, pet1_.pet_class as pet_clas2_3_0_, pet1_.pet_name as pet_name3_3_0_ from person person0_ inner join pet pet1_ on person0_.pet_id=pet1_.id where person0_.id=?
Hibernate: insert into pet (pet_class, pet_name) values (?, ?)
Hibernate: insert into person (name, pet_id) values (?, ?)
Hibernate: insert into pet (pet_class, pet_name) values (?, ?)
Hibernate: update person set name=?, pet_id=? where id=?
第一条语句查出来是空,所以会执行插入操作。其实这边也没有完全搞懂,欢迎留言!
这个问题的解决方式,请参考双向一对一映射@OneToOne。
一对一关联查询注解@OneToOne的实例详解的更多相关文章
- Hibernate注解----关联映射注解以及课程总结详解----图片版本
上一篇,记录了Hibernate注解----类级别注解以及属性注解详解 ,我们这一节主要讲解的是Hibernate注解----关联映射注解以及课程总结详解. 本节的主要内容: 第3章 关联映射注解 3 ...
- 一对一关联查询时使用relation连贯操作查询后,调用getLastSql()方法输出的sql语句
如题: 一对一关联查询时使用relation连贯操作查询后,调用getLastSql()方法输出的sql语句不是一条关联查询语句. 例如: $list = $db->relation(true) ...
- 免费的HTML5连载来了《HTML5网页开发实例详解》连载(六)媒体查询
响应式设计的另一个重要技术手段是媒体查询.如果只是简单的设计一个流式布局系统,那么可以保证每个网格按比例的放大和缩小,但有可能会使得在小屏幕下(如手机设备)网格太小而严重影响阅读,这样的设计称不上响应 ...
- MyBatis从入门到放弃三:一对一关联查询
前言 简单来说在mybatis.xml中实现关联查询实在是有些麻烦,正是因为起框架本质是实现orm的半自动化. 那么mybatis实现一对一的关联查询则是使用association属性和resultM ...
- MyBatis:一对一关联查询
MyBatis从入门到放弃三:一对一关联查询 前言 简单来说在mybatis.xml中实现关联查询实在是有些麻烦,正是因为起框架本质是实现orm的半自动化. 那么mybatis实现一对一的关联查询则是 ...
- Mybatis学习4——一对一关联查询方法2------实体作为属性
实体order和user采用resultMap order package pojo; import java.util.Date; public class Order { private Inte ...
- Mybatis学习4——一对一关联查询方法1--创建实体
创建一个实体继承两个实体之一,另一个实体作为属性 实体1. order package pojo; import java.util.Date; public class Order { privat ...
- MyBatis关联查询,一对一关联查询
数据库E-R关系 实体类 public class City { Long id; String name; Long countryId; Date lastUpdate; } public cla ...
- mybatis 使用接口增删改查和两表一对一关联查询
导包 总配置文件 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration ...
随机推荐
- db2学习笔记
a.服务端安装 v11.1_win64_expc.zip 官网下载 b.客户端安装 Toad for DB2 Freeware 6.1 百度找找 .建数据库 create database HRA_G ...
- 给自己名字abel.这个好,怎么字母排序都第一
给自己名字abel.这个好,怎么字母排序都第一
- linux(rhel) rescue修复详解
修复linux,先准备好一张安装光盘,光驱安装好后开机,选择从光驱启动.等待安装盘显示操作界面时选择"rescue"选项,如果有光标提示的话,也可以输入:linux rescue进 ...
- Sublime Text webstorm等编译器快速编写HTML/CSS代码的技巧
<!DOCTYPE html> Sublime Text webstorm等编译器快速编写HTML/CSS代码的技巧--summer-rain博客园 xiayuhao 东风夜放花千树. 博 ...
- KbmMW 服务器架构简介
kbmmw 由于文档比较少,很多同学开始用时很难理解.一直准备写一个关于kbmmw 架构的东西. 这几天与红鱼儿(blog)研究服务器线程时,整理了一下,大概画了一下kbmmw (版本4.5)服务器的 ...
- 2018.09.23 bzoj1076: [SCOI2008]奖励关(期望+状压dp)
传送门 一道神奇的期望状压dp. 用f[i][j]f[i][j]f[i][j]表示目前在第i轮已选取物品状态为j,从现在到第k轮能得到的最大贡献. 如果我们从前向后推有可能会遇到不合法的情况. 所以我 ...
- 2018.09.15 hdu3018Ant Trip(欧拉路)
传送门 显然答案等于各个连通分量的笔画数之和. 因此我们dfs每个连通分量计算对答案的贡献. 对于一个连通分量,如果本来就有欧拉回路那么只需要一笔. 否则需要寄点数/2那么多笔才能画完. 知道这个结论 ...
- 2018.08.21 NOIP模拟 unlock(模拟+找规律)
unlock 描述 经济危机席卷全球,L国也收到冲击,大量人员失业. 然而,作为L国的风云人物,X找到了自己的新工作.从下周开始,X将成为一个酒店的助理锁匠,当然,他得先向部门领导展示他的开锁能力. ...
- The remote end hung up unexpectedly
fatal: The remote end hung up unexpectedly 上传一份代码的时候,出现了这个错误,然后就没有成功上传. 背景操作 主要是进行svn转换到git时候出错的,转换的 ...
- HDU1237 简单计算器 2016-07-24 13:34 193人阅读 评论(0) 收藏
简单计算器 Problem Description 读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值. Input 测试输入包含若干测试用例,每个测试用例占一行,每行不超过 ...