首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

JPA 常用实体注解使用总结

JPA常用实体注解使用总结

JPA是JavaPersistence API的简称,即Java持久层API,是SUN公司引入ORM规范,简化了应用开发。目前市面上流行的ORM框架,如Hibernate、OpenJPA、TopLink等都实现了JPA,程序员只需按照JPA来编写代码,具体采用哪个ORM框架,可以依据项目实际情况选择。最近在实现公司项目一个需求时,在实现持久层时用到了JPA,通过查看上网查资料把JPA常用实体注解温习了一遍,决定把这些注解的使用方式记录下,方便后续查阅,快速开发。

1、常用注解

(1)、@Entity

标记被注解的类是实体类,可被ORM框架用于持续化,常与@Table一起使用,指定关联的数据库表。该注解仅包含name属性,用于指明实体的名字,不指定时默认是实体类的名字,实体名可用于查询语句中,如下代码片段:

@Entity(name=”people_entity”)

@Table(name=”people”)

public class People implements Serializable {

private static final long serialVersionUID = 1L;

@Id

@GeneratedValue(strategy = GenerationType.AUTO)

private Integer id;

@Column(name = "name", length = 32)

private String name;

// ……省略getter和setter方法

}

// Hibernate hql查询代码片段

String hql = "from people_entity ";

Query query =this.getSessionFactory().getCurrentSession().createQuery(hql);

List

list = (List

)query.list();

@Entity还可以用于继承层次中,实体类可继承非实体、实体、抽象类,如下实例:

@Entity

public abstract class Employee {

@Id

protected Integer employeeId;

...

}

@Entity

public class FullTimeEmployee extends Employee implementsSerializable {

protected Integer salary;

...

}

@Entity

public class PartTimeEmployee extends Employee implementsSerializable {

protected Float hourlyWage;

}

FullTimeEmployee、PartTimeEmployee实体类分别继承抽象的Employee实体类。抽象的实体类不会实例持久化对象,抽象的实体类可用于查询语句中,返回与具体的查询条件匹配的所有子类实体对象。实体继承时,可以通过@ Inheritance指定实体继承层次映射到数据库表的策略,该注解有一个属性成员strategy,其类型是InheritanceType,有三种可选的策略:

JOINED:父类、子类分别存放在不同的表中,子类对应的数据库表仅存放子类新增的字段,父类和子类通过外健关联;

SINGLE_TABLE:父类和所有子类存放在一张表中,在表中创建一列来单独区分父类和子类对象,可用@DiscriminatorValue注解来标明这一列的字段名和类型,如下实例:

@Entity

@Inheritance(strategy=SINGLE_TABLE)

@DiscriminatorValue(name=” DISCRIMINATOR”,discriminatorType=DiscriminatorType.STRING)

public abstract class Employee {

@Id

protected Integer employeeId;

...

}

@Entity

@DiscriminatorValue(“FullTimeEmployee”)

public class FullTimeEmployee extends Employee implementsSerializable {

protected Integer salary;

...

}

TABLE_PER_CLASS:继承层次中每一个具体的类单独对应一张数据库表,表中的字段为类的所有可持久字段;

实际项目开发中,经常遇到这样的情形:多个实体拥有相同的字段,例如id、创建时间等,这些共有字段可以放到父类中,同时又不希望ORM框架将父类当实体处理,可用@ MappedSuperclass标注父类实体,子类实体映射的数据库表会包含父类字段,如下实例:

@MappedSuperclass

public class Employee {

@Id

protected Integer employeeId;

...

}

@Entity

public class FullTimeEmployee extends Employee implements Serializable {

protected Integer salary;

...

}

(2)、@Table

该属性与@Entity一起使用,用来描述实体对应的数据库表,其name属性指定实体对应的数据库名,name属性用的较多,catalog和schema属性指定数据表所在目录名或数据库名,跟具体使用数据库相关,uniqueConstraints属性用来对数据表列唯一性做限制,index属性用来描述索引字段,实际使用根据具体需求来配置

(3)、@Id

被该属性标注的实体字段被标记为数据表的主键,与@Column, @GeneratedValue一起配合使用用来描述主键字段,如下实例,People类的id被映射成主键,对应字段名为pid,ORM框架依据具体使用的数据库使用对应的主键生成策略:

@Entity(name=”people_entity”)

@Table(name=”people”)

public class People implements Serializable {

private static final long serialVersionUID = 1L;

@Id

@GeneratedValue(strategy = GenerationType.AUTO)

@Column(name=”pid”)

private Integer id;

…….

}

(4)、@Column

用来描述实体属性对应数据表字段,其中name、nullable、unique、length属性用的较多,分别用来描述字段名、字段是否可以null、字段是否唯一、字段的长度,实际开发中需要用其他属性时,可从参考文献获取api文档地址,查阅文档配置。

(5)、@GeneratedValue

用来描述主键生成策略,包含如下策略:

GenerationType.TABLE:ORM框架通过数据库的一张特定的表格来生成主键,该策略一般与另外一个注解@TableGenerator一起使用,@TableGenerator对这张特定的表进行描述,该策略的好处就是不依赖于外部环境和数据库的具体实现,在不同数据库间可以很容易的进行移植,但由于其不能充分利用数据库的特性,一般不会优先使用;

GenerationType.SEQUENCE:

Oracle不支持主键自增长,其提供了一种叫做"序列(sequence)"的机制生成主键,GenerationType.SEQUENCE就可以作为主键生成策略,不足之处是只能使用于部分支持序列的数据库(Oracle,PostgreSQL,DB2),一般与@SequenceGenerator一起使用,@SequenceGenerator注解指定了生成主键的序列,不指定序列时自动生成一个序列SEQ_GEN_SEQUENCE;

GenerationType.IDENTITY:

该策略类同SEQUENCE策略,主键自增策略,需要具体的数据库支持才能使用,mysql支持该策略;

GenerationType.AUTO

ORM框架依据使用的数据库在以上三种主键生成策略中选择其中一种,该策略是默认的策略,比较常用。

(6)、@OneToOne

两实体一对一关系,例如雇员和工作证就是一对一关系,一个雇员只能有一个工作证,一个工作证只能属于一个雇员。

单向关联:查询包含关联属性的实体对象时,能同步从数据库中获取关联的实体对象,反过来不行;

@Entity

@Table(“employee”)

public class Employee implements Serializable {

@Id

privateinteger id;

@OneToOne

private Card card;

……

}

@Entity

@Table()

public class Card implements Serializable {

@Id

privateInteger id;

private String num;

……

}

查询Employee能同步获取到对应的Card,但是查询Card获取不到

双向关联:包含外键定义的实体是拥有关系实体,在关联的非拥有关联实体中,需要用注解的mappedBy属性指明拥有关系实体的关联属性名,如下示例:

@Entity

@Table(“employee”)

public class Employee implements Serializable {

@Id

privateinteger id;

@OneToOne

@OneToOne(mappedBy="employee",fetch=FetchType.LAZY,cascade=)

private Card card;

……

}

@Entity

@Table()

public class Card implements Serializable {

@Id

privateInteger id;

private String num;

@OneToOne

@JoinColumn(name="employee_id")

private Employee employee;

……

}

顺带说明下@OneToOne注解中的fetch、cascade属性的意义,@OneToMany、@ManyToOne、@ManyToMany同样具有这两个属性,意义是相同的。fetch属性指明数据抓取策略,EAGER即立即抓取,LAZY延迟加载,指明关联实体对象获取策略;

cascade属性指明级联特性:

CascadeType.PERSIST:级联持久化操作,当将实体保存至数据库时,其对应的关联实体也会被保存至数据库;

CascadeType.REMOVE:级联删除操作,从数据库删除当前实体时,关联实体也会被删除;

CascadeType.DETACH:级联脱管,当前实体被ORM框架脱管,关联实体也被同步脱管,处于脱管状态的实体,修改操作不能持久化到数据库,如下实例:

Person person = entityManager.find( Person.class, 1L );

Phone phone = person.getPhones().get( 0 );

assertTrue( entityManager.contains( person ));

assertTrue( entityManager.contains( phone ));

entityManager.detach( person );

assertFalse( entityManager.contains( person ));

assertFalse( entityManager.contains( phone ))

CascadeType.MERGE:级联合并操作,脱管实体状态被复制ORM框架管理的对应同一条数据库记录的实体中,关联的实体同样执行复制操作,如下实例:

Phone phone = entityManager.find( Phone.class, 1L );

Person person = phone.getOwner();

person.setName( "John Doe Jr." );

entityManager.clear();

entityManager.merge( person );

person和phone脱管对象的状态并复制到实体管理器管理的对应同一条数据库记录的实体中;

CascadeType.REFRESH:级联刷新,当前实体修改保存至数据库时,关联的实体状态会重新从数据库加载,忽略掉先前的状态,如下实例:

Person person = entityManager.find( Person.class, 1L );

Phone phone = person.getPhones().get( 0 );

person.setName( "John Doe Jr." );

entityManager.refresh( person );

// “John Doe”为person实体对应的数据库记录的name字段值

assertEquals( "John Doe", person.getName() );

尽管只将person对象保存数据库,但是关联phone对象需要重新从数据库load下;

CascadeType.ALL:包含上述所有级联操作。

(7)、@OneToMany和@ManyToOne

两实体一对多关系,例如人和电话就是一对多关系,一个人可以有多个电话,一个电话只能属于一个人。

单向关联:例如电话实体类包含人实体类属性,在查询电话实体对象时,能获取到对应的人实体,相反是不行的,查询人实体对象时不能获取到其电话实体;

@Entity

@Table(name=”people”)

public class People implements Serializable {

@Id

private Integer id;

……

}

@Entity

@Table(name=”phone”)

public class Phone implements Serializable {

@Id

private Integer id;

@ManyToOne

@JoinColumn(name=”people_id”)

private People people;

……

}

当实体间关系是双向的:每个实体类都有一个属性指向关联的实体对象,one端实体可以用@OneToMany注解many端实体属性,many端实体可以通过@ManyToOne注解one端实体属性,如下例:

@Entity

@Table(name=”people”)

public class People implements Serializable {

@Id

private Integer id;

@OneToMany(mappedBy="people",fetch=FetchType.LAZY,cascade=)

@OrderBy(“number”)

private List

phones;

……

}

@Entity

@Table(name=”phone”)

public class Phone implements Serializable {

@Id

private Integer id;

@ManyToOne

@JoinColumn(name=”people_id”)

private People people;

private String number;

……

}

在People实体端用@OneToMany注解了phones属性,即人对应的电话列表,同@OneToOne,需要用mappedBy指出many实体端指向one端的属性;

(8)、@ManyToMany

两实体多对多关系,例如学生和所选课程的关系,一个学生可选多个课程,一个课程可被多个学生选,单向关联类同@OneToOne、@OneToMany,查询拥有关系的实体时,才能获取关联实体对象,反之不行;双向关联,任何一方都可以成为关系拥有方法,非关系拥有方需要用mapped属性标明关系拥有方实体对应属性字段,ManyToMany关系数据库层是通过关联表的方式连接两实体对应的数据表,在用@ManyToMany时,可同步用@JoinTable注解指明关联表名及其字段,如下Student和Course实例:

@Entity

@Table(name=”student”)

public class Student implementsSerializable {

@Id

private Integerid;

……

@ManyToMany(fetch=FetchType.LAZY, cascade=)

@JoinTable(name="student_course",

joinColumns=

@JoinColumn(name="student_id",referencedColumnName="id"),

inverseJoinColumns=

@JoinColumn(name="course_id",referencedColumnName="ID")

)

privateSet courses;

}

@Entity

@Table(name=”course”)

public class Course implements Serializable{

@Id

private Integerid;

……

@ManyToMany(mappedBy="courses ")

privateSet students;

}

(9)、@Temporal

用于将java.util.Date和java.util.Calendar的实体属性的持久化,其属性参数value包含如下三种取值:

TemporalType.DATE,持久化时按照java.sql.Date类型来持久化,即只保存年月日yyyy-MM-dd;

TemporalType.TIME,持久化时按照java.sql.Time类型来持久化,即只保存时分秒HH:MM:SS;

TemporalType.TIMESTAMP,持久化时按照java.sql.Timestamp类型来持久化,即保存年月日时分秒yyyy-MM-dd hh:MM:ss;

(10)、@Transient

指定不进行持久化的实体属性,即不映射到数据表的字段。

2、实例

这里采用Spring MVC +Hibernate + JQuery EasyUI搭建了一个小的测试用例,实例中用前面讲到的大部分注解实现了一个OneToOne关系的实体对象存储、更新和删除操作,以下直接贴代码和运行结果图供大家参考,OneToMany、ManyToMany关系都是类似的:

(1)、测试工程代码文件截图:

(2)、基类BaseEntity代码截图:

(3)、Employee实体代码截图:

(4)、Card实体代码截图:

(5)、新增员工及查询工卡信息:

(6)、删除员工和查询工卡信息截图:

3、参考文献

1、https://docs.oracle.com/javaee/5/tutorial/doc/bnbqa.html

2、https://docs.oracle.com/javaee/7/api/javax/persistence/package-summary.html

3、http://www.objectdb.com/java/jpa/persistence/advanced

4、Hibernate ORM 5.2.10.Final User Guide

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180119G0CIWP00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券