1-m:多的一方为关系维护端,关系维护端负责外键纪录的更新,关系被维护端没有权力更新外键纪录.
拥有mappedBy注解的实体类为关系被维护端,另外的实体类为关系维护端的。顾名思意,关系的维护端对关系(在多对多为中间关联表)的CRUD做操作。关系的被维护端没有该操作,不能维护关系。
@ManyToOne表示一个多对一的映射,该注解标注的属性通常是数据库表的外键
optional:是否允许该字段为null,该属性应该根据数据库表的外键约束来确定,默认为true
fetch:表示抓取策略,默认为FetchType.EAGER(一的一端默认为立即加载,多的一端默认为懒加载)
cascade:表示默认的级联操作策略,可以指定为ALL,PERSIST,MERGE,REFRESH和REMOVE中的若干组合,默认为无级联操作
targetEntity:表示该属性关联的实体类型.该属性通常不必指定,ORM框架根据属性类型自动判断targetEntity.
@JoinColumn
@JoinColumn 和 @Column类似,指明此属性描述的不是一个简单字段,而是一个关联字段
name:该字段的名称(指定关联关系中的维护端对应的表中和被维护端的主键进行关联的字段的名称)
referencedColumnName:属性指定关联关系中的被维护端与关联关系中的维护端对应的表之间形成关联关系的字段名称,通常用于关联关系中的被维护端的关联字段不是自己的主键的情况
@OneToMany(fetch=FetchType,cascade=CascadeType)
@OneToMany描述一个一对多的关联,该属性应该为集体类型,在数据库中并没有实际字段.
维护端注解
@ManyToOne(cascade = {CascadeType.MERGE, CascadeType.REFRESH }, optional = false)
@JoinColumn(name = "order_id")
被维护端注解
@OneToMany(cascade = {CascadeType.PERSIST, CascadeType.REFRESH,
CascadeType.MERGE, CascadeType.REMOVE },
fetch = FetchType.EAGER,
mappedBy = "order")
@Entity
@Table(name = "order_info")
public class OrderInfo {
privateInteger id;
privateString name;
privateSet<OrderItem> items = newHashSet<OrderItem>();
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
publicInteger getId() {
returnid;
}
public voidsetId(Integer id) {
this.id =id;
}
publicString getName() {
returnname;
}
public voidsetName(String name) {
this.name =name;
}
@OneToMany(cascade = { CascadeType.PERSIST,CascadeType.REFRESH,
CascadeType.MERGE, CascadeType.REMOVE }, fetch =FetchType.EAGER,
mappedBy = "order")
publicSet<OrderItem> getItems() {
returnitems;
}
public voidsetItems(Set<OrderItem> items){
this.items =items;
}
public voidaddOrderItem(OrderItem orderItem) {
orderItem.setOrder(this);
this.items.add(orderItem);
}
}
@Entity
@Table(name = "order_item")
public class OrderItem {
privateInteger Id;
privateString name;
privateOrderInfo order;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
publicInteger getId() {
returnId;
}
public voidsetId(Integer id) {
Id =id;
}
@Column(length = 20, nullable = true)
publicString getName() {
returnname;
}
public voidsetName(String name) {
this.name =name;
}
@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.REFRESH },optional = false)
@JoinColumn(name = "order_id")
publicOrderInfo getOrder() {
returnorder;
}
public voidsetOrder(OrderInfo order) {
this.order =order;
}
}
JPA多对多双向
维护端注解
@ManyToMany (cascade = CascadeType.REFRESH)
@JoinTable (//关联表
name = "student_teacher" , //关联表名
inverseJoinColumns= @JoinColumn (name = "teacher_id" ),//被维护端外键
joinColumns = @JoinColumn (name= "student_id"))//维护端外键
被维护端注解
@ManyToMany(
cascade = CascadeType.REFRESH,
mappedBy = "teachers",//通过维护端的属性关联
fetch = FetchType.LAZY)
@Entity
public class Student {
privateInteger id;
privateString name;
privateSet<Teacher> teachers = newHashSet<Teacher>();
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
publicInteger getId() {
returnid;
}
public voidsetId(Integer id) {
this.id =id;
}
@Column(nullable = false, length = 16)
publicString getName() {
returnname;
}
public voidsetName(String name) {
this.name =name;
}
@ManyToMany(cascade = CascadeType.REFRESH)
@JoinTable(name = "student_teacher", inverseJoinColumns =@JoinColumn(name = "teacher_id"), joinColumns = @JoinColumn(name ="student_id"))
publicSet<Teacher> getTeachers() {
returnteachers;
}
public voidsetTeachers(Set<Teacher> teachers){
this.teachers = teachers;
}
public voidaddTeacher(Teacher teacher) {
this.teachers.add(teacher);
}
public voidremoveTeachers(Teacher teacher) {
this.teachers.remove(teacher);
}
}
@Entity
public class Teacher {
privateInteger id;
privateString name;
privateSet<Student> students = newHashSet<Student>();
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
publicInteger getId() {
returnid;
}
public voidsetId(Integer id) {
this.id =id;
}
@Column(nullable = false, length = 16)
publicString getName() {
returnname;
}
public voidsetName(String name) {
this.name =name;
}
@ManyToMany(cascade = CascadeType.REFRESH, mappedBy = "teachers",fetch = FetchType.LAZY)
publicSet<Student> getStudents() {
returnstudents;
}
public voidsetStudents(Set<Student> students){
this.students = students;
}
}
JPA双向一对一
@OneToOne 注释
public @interface OneToOne
{
ClasstargetEntity( ) default void.class;
CascadeType[] cascade( ) default {};
FetchTypefetch( ) default EAGER;
booleanoptional( ) default true;
StringmappedBy( ) default "";
}
@Entity
public class Person {
@Id@GeneratedValue
private intid;
@Column(nullable=false)
privateString name;
@OneToOne(cascade=CascadeType.ALL,optional=false)
@JoinColumn(name="idCard_id")//关系维护端设置外键
privateIDCard idCard;
//省略gettersetter...
}
@Entity
public class IDCard {
@Id@GeneratedValue
private intid;
@Column(length=18,nullable=false)
privateString idNumber;
@OneToOne(mappedBy="idCard",cascade={CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH},optional=false,fetch=FetchType.EAGER)
privatePerson person;//被维护端,idCard为维护端里的属性,optional=false不允许为null
//省略gettersetter...
}
JPA复合主键映射
一个实体的主键可能同时构成,当且仅当多个字段的值完全相同时,才认为是相同的实体对象。
复合主键映射时,通常构成将复合主键的多个字段单独抽取出来建一个类作为符合主键类。
符合主键类必须满足以下几点要求
必须实现Serializable接口。
必须有默认的public无参数的构造方法。
必须覆盖equals和hashCode方法。equals方法用于判断两个对象是否相同,EntityManger通过find方法来查找Entity时,是根据equals的返回值来判断的。
@Embeddable
public class AirLinePK implements Serializable {
@Column(nullable=false,length=3,name="LEAVECITY")
privateString leavecity;
@Column(nullable=false,length=3,name="ARRIVECITY")
privateString arrivecity;
publicAirLinePK(){}
publicAirLinePK(String leavecity, String arrivecity) {
this.leavecity = leavecity;
this.arrivecity = arrivecity;
}
@Override
public inthashCode() {
int hash = 0;
hash += (this.leavecity!=null &&this.arrivecity!=null ? (this.leavecity+ "-"+this.arrivecity).hashCode() : 0);
return hash;
}
@Override
publicboolean equals(Object object) {
if (!(object instanceof AirLinePK)) {
return false;
}
AirLinePK other = (AirLinePK)object;
if (this.leavecity != other.leavecity&& (this.leavecity == null ||!this.leavecity.equalsIgnoreCase(other.leavecity))) returnfalse;
if (this.arrivecity != other.arrivecity&& (this.arrivecity == null ||!this.arrivecity.equalsIgnoreCase(other.arrivecity))) returnfalse;
return true;
}
//省略gettersetter...
}
@Entity
public class AirLine implements Serializable {
@EmbeddedId
privateAirLinePK id;
@Column(length=15)
privateString airLineNum;
publicAirLine(){}
@Override
public inthashCode() {
int hash = 0;
hash += (this.id != null ? this.id.hashCode() : 0);
return hash;
}
@Override
publicboolean equals(Object object) {
if (!(object instanceof AirLine)) {
return false;
}
AirLine other = (AirLine)object;
if (this.id != other.id && (this.id== null || !this.id.equals(other.id))) return false;
return true;
}
//省略gettersetter...
}
复合主键映射还有另一种映射方式
public class AirLinePK implements Serializable {
@Column(length=3)
privateString leavecity;
@Column(length=3)
privateString arrivecity;
publicAirLinePK(){}
publicAirLinePK(String leavecity, String arrivecity) {
this.leavecity = leavecity;
this.arrivecity = arrivecity;
}
@Override
public inthashCode() {
int hash = 0;
hash += (this.leavecity!=null &&this.arrivecity!=null ? (this.leavecity+ "-"+this.arrivecity).hashCode() : 0);
return hash;
}
@Override
publicboolean equals(Object object) {
if (!(object instanceof AirLinePK)) {
return false;
}
AirLinePK other = (AirLinePK)object;
if (this.leavecity != other.leavecity&& (this.leavecity == null ||!this.leavecity.equalsIgnoreCase(other.leavecity))) returnfalse;
if (this.arrivecity != other.arrivecity&& (this.arrivecity == null ||!this.arrivecity.equalsIgnoreCase(other.arrivecity))) returnfalse;
return true;
}
//省略gettersetter
}
@Entity
@IdClass(AirLinePK.class)
public class AirLine implements Serializable {
@Id private String leavecity;
@Id private String arrivecity;
@Column(length=15) private String airLineNum;
publicAirLine(){}
//省略getter setter
}
常见异常
1、异常信息:org.hibernate.hql.ast.QuerySyntaxException: person is notmapped
异常环境:查询
异常原因:查询语句中Person类没有大写
2、java.lang.ClassCastException: [Ljava.lang.Object; cannot be castto java.lang.String
异常环境:查询、遍历显示
异常原因:转型出错
3、javax.persistence.NonUniqueResultException: result returns morethan one elements
异常环境:查询、getSingleResult
异常原因:getSingleResult只能获取一条数据,而查询语句返回的是多条数据
4、 org.hibernate.PropertyValueException: not-null propertyreferences a null or transient value:com.sunyard.entities.Person.name
异常环境:数据插入
异常原因:JPA的Entity中一个属性定义为nullable=false,插入数据该字段为null
5、 执行添加没反应、没异常
异常原因:没有开启事务、没有提交事务
6、javax.persistence.PersistenceException:org.hibernate.PersistentObjectException: detached entity passed topersist: com.sunyard.entities.Person
异常环境:OneToOne 共享主键关联
异常原因:一对一中,一个提供主键、另一个共享其主键,共享主键的对象可以set 提供主键的对象 然后添加到数据库中方向弄反了后果就是没人提供主键
7、org.hibernate.TransientObjectException: object references anunsaved transient instance - save the transient instance beforeflushing:
异常环境:多对一添加
异常原因:在多的一端维护 ,没有添加级联
8、javax.persistence.PersistenceException: [PersistenceUnit: JPA]Unable to configure EntityManagerFactory
异常原因:很多、实体管理器Factory没有成功创建,是注解的问题
9、org.hibernate.MappingException:Unable to find column with logical name: sid inorg.hibernate.mapping.
异常环境:添加表做多对一关联映射
异常原因:表字段写反了,name添加表字段名referencedColumnName指向本表字段名