表的关联查询比较复杂,应用的场景很多,本文根据自己的经验解释@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;@Overridepublic 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方法。@Overridepublic 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 {@Resourceprivate 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;@Servicepublic class TableRelationService {@Resourceprivate PersonJPA personJPA;@Resourceprivate 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) {// 组装personPerson 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;} ?@Transactionalpublic 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" ???}}
一对一关联查询注解@OneToOne的实例详解
原文地址:http://www.cnblogs.com/boywwj/p/8092915.html