一对一关联查询注解@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"
  }
}

  

时间: 2024-11-01 12:16:15

一对一关联查询注解@OneToOne的实例详解的相关文章

Hibernate注解----关联映射注解以及课程总结详解----图片版本

上一篇,记录了Hibernate注解----类级别注解以及属性注解详解 ,我们这一节主要讲解的是Hibernate注解----关联映射注解以及课程总结详解. 本节的主要内容: 第3章 关联映射注解 3-1 本章简介 3-2 实体之间的关系 3-3 一对一单向外键关联(一) 3-4 一对一单向外键关联(二) 3-5 一对一双向外键关联 3-6 一对一单向外键联合主键 3-7 多对一单向外键关联(一) 3-8 多对一单向外键关联(二) 3-9 一对多单向外键关联 3-9 一对多双向外键关联 3-10

实例详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化(一)

在数据库有外键的时候,使用 select_related() 和 prefetch_related() 可以很好的减少数据库请求的次数,从而提高性能.本文通过一个简单的例子详解这两个函数的作用.虽然QuerySet的文档中已经详细说明了,但本文试图从QuerySet触发的SQL语句来分析工作方式,从而进一步了解Django具体的运作方式. 本来打算写成一篇单独的文章的,但是写完select_related()之后发现长度已经有点长了,所以还是写成系列,大概在两到三篇.整个完成之后将会在这里添加上

Spring MVC 3.0.5+Spring 3.0.5+MyBatis3.0.4全注解实例详解(三)

前两章我为大家详细介绍了如何搭建Maven环境.Spring MVC的流程结构.Spring MVC与Struts2的区别以及示例中的一些配置文件的分析.在这一章,我就对示例的层次结构进行说明,以及MyBatis的一些简单介绍. 本文不会对MyBatis作详细说明,大象还是假定阅读本文的朋友对MyBatis(ibatis)有最基本的了解,只有这样才能较好的理解本文的内容.关于MyBatis请查看它的官方文档及其它参考资料,本文不作详细讨论. 一.工程结构图      上面这是典型的Maven项目

Spring MVC 3.0.5+Spring 3.0.5+MyBatis3.0.4全注解实例详解(二)

在上一篇文章中我详细的介绍了如何搭建maven环境以及生成一个maven骨架的web项目,那么这章中我将讲述Spring MVC的流程结构,Spring MVC与Struts2的区别,以及例子中的一些配置文件的分析. 一.Spring MVC 3.0介绍 Spring MVC是一个典型的MVC框架,是Spring内置的Web框架,可以作为应用项目的展示层,继Spring 2.0对Spring MVC进行重大升级后,Spring 2.5又为Spring MVC引入了注解驱动功能,再到3.0时代,全

实例详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化(二)

这是本系列的第二篇,内容是 prefetch_related() 函数的用途.实现途径.以及使用方法. 本系列的第一篇在这里 3. prefetch_related() 对于多对多字段(ManyToManyField)和一对多字段,可以使用prefetch_related()来进行优化.或许你会说,没有一个叫OneToManyField的东西啊.实际上 ,ForeignKey就是一个多对一的字段,而被ForeignKey关联的字段就是一对多字段了. 作用和方法 prefetch_related(

实例详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化(三)

这是本系列的最后一篇,主要是select_related() 和 prefetch_related() 的最佳实践. 第一篇在这里 讲例子和select_related() 第二篇在这里 讲prefetch_related() 4. 一些实例 选择哪个函数 如果我们想要获得所有家乡是湖北的人,最无脑的做法是先获得湖北省,再获得湖北的所有城市,最后获得故乡是这个城市的人.就像这样: >>> hb = Province.objects.get(name__iexact=u"湖北省&

这个贴子的内容值得好好学习--实例详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化

感觉要DJANGO用得好,ORM必须要学好,不管理是内置的,还是第三方的ORM. 最最后还是要到SQL.....:( 这一关,慢慢练啦.. 实例详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化 http://blog.jobbole.com/75435/

一对一关联查询时使用relation连贯操作查询后,调用getLastSql()方法输出的sql语句

如题: 一对一关联查询时使用relation连贯操作查询后,调用getLastSql()方法输出的sql语句不是一条关联查询语句. 例如: $list = $db->relation(true)->where($where)->order('blogid desc')->limit($Page->firstRow.','.$Page->listRows)->select(); $sql = $db->getLastSql(); 输出的sql语句为: SELE

Spring MVC 3.0.5+Spring 3.0.5+MyBatis3.0.4全注解实例详解(一)

Spring更新到3.0之后,其MVC框架加入了一个非常不错的东西——那就是REST.它的开放式特性,与Spring的无缝集成,以及Spring框架的优秀表现,使得现在很多公司将其作为新的系统开发框架.大象根据实际的项目经验,以之前SSH2例子为基础,对其进行一次大改造,详细的为大家讲解如何实现SSM3全注解式的开发. 这次大象将采取两种构建方式,一是很多人喜欢用的MyEclipse,另一个,则是用Eclipse+Maven.这一篇,将主要讲解开发环境设置与Maven构建方式. 1. 开发环境