Jpa注解

最近一直在使用jpa,特此对用到的注解做个记录,方便以后查询

参考:JPA 批注参考

什么是JPA

JPA全称Java Persistence API.JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
JPA由EJB 3.0软件专家组开发,作为JSR-220实现的一部分。但它不囿于EJB 3.0,你可以在Web应用、甚至桌面应用中使用。JPA的宗旨是为POJO提供持久化标准规范.
JPA的总体思想和现有Hibernate、TopLink,JDO等ORM框架大体一致。总的来说,JPA包括以下3方面的技术:
(1)ORM映射元数据
JPA支持XML和JDK 5.0注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中;
(2)JPA 的API
用来操作实体对象,执行CRUD操作,框架在后台替我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。
(3)查询语言
这是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。

@Entity 标注实体类

@Table 默认情况下生成的表名为实体类的名称,通过属性name可以修改表名

@Id 标注实体类中的属性为映射表中的主键

@GeneratedValue 与@Id一起使用,设置主键的生成策略,对于mysql,可以使用@GeneratedValue(strategy=GenerationType.INENTITY)指定主键自增策略;对于Oracle,使用@GeneratedValue(Strategy=GenreationType.SEQUENCE,generator=“seq_tbl_person”)指定序列策略,其中generator表示生成器的名字,而且还要指定@SequenceGenerator(name="seq_tbl_person",sequenceName="seq_tbl_person",allocationSize=1)注解配合使用,其中name指定生成器的名字,对应@GeneratedValue中的generator属性值,sequenceName指定数据库中定义序列的名字,allocationSize指定序列每次增长1,类似于hibernate中的@GeneratedValue(generator="generator")配合@GenericGenerator(name="generator",strategy="native")使用方法

@Column 描述实体类属性映射到数据库表中对应字段的定义

  • 属性name表示数据库表中该字段的名称,默认与实体类的属性名一致;

  • 属性nullable表示该字段是否允许为null,默认为true;

  • 属性unique表示该字段是否允许包含重复值,默认为false,如果不允许该列包含重复值,可以把unique设为true;

  • 属性length表示String类型字段的大小,默认值为255;

  • 属性insertable表示在ORM框架执行插入操作时,该字段是否应出现在INSERT语句中,默认为true,如果该列不应包含在这些语句中,就将insertable设置为false;

  • 属性updateable表示在ORM框架执行更新操作时,该字段是否应该出现在UPDATE语句中,默认为true,如果该列不应包含在这些语句中,就将updateable设置为 false对于一经创建就不可以更改的字段,该属性非常有用,如对于createdAt字段。

  • 属性columnDefinition指定该实体类属性在数据库中的实际类型,通常ORM框架可以根据属性类型自动判断数据库中字段的类型,比如String的默认映射类型为VARCHAR,如果要将String类型映射到特定数据库的BLOB或TEXT字段类型,该属性非常有用。同时,还可以通过该属性设置字段的缺省值,比如@Column(nullable=false,columnDefiniton="int default 0")

@OrderBy 常与@OneToMany 和 @ManyToMany一起使用,指定按一个或多个字段进行排序,属性value默认按关联实体的主键以升序顺序检索 Collection 关联的成员。下面的例子指定方法 getEmployees 应按 Employee 字段lastname 以升序顺序并按 Employee 字段 seniority 以降序顺序返回 Employee 的 List

@ManyToMany
@OrderBy("lastname ASC", "seniority DESC")
public List<Employee> getEmployees(){...}

@Transient 指定ORM框架忽略该属性,不进行映射,ORM框架默认其注解为@Basic,对于那些不需要通过数据库查找,而只需要在运行时临时设置填充的属性,该注解非常有用。

@Enumerated 用于保存枚举常量的序数值或String值到数据库中,属性value默认值为EnumType.ORDINAL,保存序数值,如果需要持久保存枚举常量的 String 值,就将value值设为EnumType.STRING,比如下面的例子

public enum Gender implements BaseEnum {
    MALE(0),
    FEMALE(1),
    SECRET(2);
    
    private int value;

    Gender(int value) {
        this.value = value;
    }

    public int getValue() {
        return this.value;
    }

    public static Gender valueOf(int value){
        for(Gender g : Gender.values()){
            if(g.getValue() == value)
                return g;
        }
        return null;
    }
}

在User实体类中存在属性

@Enumerated(EnumType.ORDINAL)
@Column(nullable = false, columnDefinition = "int default 2")
private Gender gender;

@Temporal 指定为 java.util.Date 和java.util.Calendar 类型的属性持久保存的数据库类型。通过属性value设置相对应的数据库类型,TemporalType.DATE等于java.sql.Date,TemporalType.Time等于java.sql.Time,TemporalType.TIMESTAMP等于java.sql.Timestamp

@Lob 持久化大型对象到数据库中,没有属性,对于基于字符串和字符的类型,默认值为Clob(Oracle中),即字符型大型对象(Character Large Object),与字符集相关,适于存贮文本型的数据(如历史档案、大部头著作等),在其他情况下,默认值为Blob,即二进制大型对象(Binary Large Object),适用于存贮非文本的字节流数据(如程序、图象、影音等)

@OneToOne 一对一关系映射

User类(外键拥有方):

@OneToOne(optional=false,cascade={CascadeType.PERSIST,CascadeType.REMOVE,CascadeType.MERGE,CascadeType.REFRESH}) //可以用CascadeType.ALL替代  @JoinColumn(name="avatar_id")                                   

private Avatar avatar;

 Avatar类(被拥有方):

@OneToOne(optional=false,mappedBy="avatar")

private User user;

  • fetch 获取策略,默认为FetchType.EAGER即时加载,可以将fetch设置为FetchType.LAZY懒加载
  • cascade 级联操作, 默认为空数组,不进行任何级联操作,可以将 cascade设置为一个或多个 CascadeType 实例,其中包括:
  1. CascadeType.PERSIST 级联保存, 保存User实体时,也会保存关联的Avatar实体
  2. CascadeType.REMOVE 级联删除,删除User时,也会删除关联的Avatar
  3. CascadeType.MERGE 级联更新(合并),当User中的数据改变时,也会更新Avatar中的数据
  4. CascadeType.REFRESH 级联刷新,那么和级联更新有什么区别呢,先来假设一个场景:有一个订单,订单里面关联了许多商品,这个订单可以被很多人操作,假设这个时候A对此订单和关联的商品进行了修改,与此同时,B也进行了相同的操作,但是B先一步比A保存了数据,那么当A保存数据的时候,就需要先刷新订单信息及关联的商品信息后,再将订单及商品保存。而对于MERGE呢,jpa中的实体拥有四种状态:瞬时状态(transient),就是一个普通的java对象,和持久化上下文无关联,数据库中也没有数据与之对应;持久状态(persistent),使用EntityManager进行persist操作返回的对象,此时该对象已经处于持久化上下文中;游离状态(detached),当事务提交后,处于持久状态的对象就转变为了游离状态。此时该对象已经不处于持久化上下文中,因此任何对于该对象的修改都不会同步到数据库中;删除状态 (deleted),当调用EntityManger对实体进行remove后,该实体对象就处于删除状态。参考另一篇博文从detached entity passed to persist到JPA EntityManager: Why use persist() over merge()?回到最初的话题,假如当前实体处于游离状态,就应该使用merge,否则会报异常..同样,做级联的时候执行merge操作,CasCadeType.Merge也会对关联实体生效。
  5. CascadeType.ALL包含上面4中,但是慎用!慎用!慎用!
  • optional 表示对象是否允许为空,默认为true
  • mappedBy jpa默认会从被引用的对象类型推断出关联的目标实体,如果无法推断就将关联的相反(非拥有)方上的 mappedBy 元素设置为拥有此关系的字段或属性的 String 名称
  • targetEntity jpa默认从被引用的对象类型推断出关联的目标实体,若无法推断,将关联的拥有方上的targetEntity 元素设置为作为关系目标的实体的 Class

@OneToMany 一对多关系映射,标注集体类型,在数据库中并没有实际字段

@ManyToOne  多对一关系映射,标注的属性通常是数据库的外键

@OneToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}, mappedBy = "user")
private List<Note> notes; //User类中

@ManyToOne(cascade = {CascadeType.REFRESH}, optional = false) 
@JoinColumn(name = "user_id")
private User user; //Note类中

@ManyToMany 多对多关系映射,一般很少用,遇到了都是拆分成两个一对多,比如一个用户可以喜欢很多的文章,一篇文章又可以被很多的用户喜欢,二者之间的关系就是多对多的关系,一般我们会创建一个新的实体类UserLikeNote,设计如下:

@OneToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.REMOVE}, mappedBy = "user")
private List<UserLikeNote> userLikeNotes; //User类中 
@OneToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.REMOVE}, mappedBy = "note")
private List<UserLikeNote> userLikeNotes = new ArrayList<>(); //Note类中 
@ManyToOne(cascade = {CascadeType.REFRESH},optional = false)
private User user; //UserLikeNote类中
@ManyToOne(cascade = {CascadeType.REFRESH},optional = false)
private Note note; //UserLikeNote类中

仔细想想,这个例子可能不太恰当,举个典型的多对多应用吧,用户和角色

@ManyToMany(cascade = {CascadeType.REFRESH}, fetch = FetchType.EAGER)
@JoinTable(name = "t_user_role", joinColumns = @JoinColumn(name = "user_id"),
                                 inverseJoinColumns = @JoinColumn(name = "role_id"))
private List<Role> roles; //User类中
@ManyToMany(mappedBy = "roles")
private List<User> users; //Role类中

安利一个trick,@OneToMany和@ManyToMany(以Many结尾的fetch默认值都是FetchType.LAZY),而@OneToOne和@ManyToOne(fetch的默认值为FetchType.EAGER)

看一下这几个注解的源码:

@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface OneToMany {
    Class targetEntity() default void.class;

    CascadeType[] cascade() default {};

    FetchType fetch() default FetchType.LAZY;

    String mappedBy() default "";

    boolean orphanRemoval() default false;
}
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ManyToMany {
    Class targetEntity() default void.class;

    CascadeType[] cascade() default {};

    FetchType fetch() default FetchType.LAZY;

    String mappedBy() default "";
}
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface OneToOne {
    Class targetEntity() default void.class;

    CascadeType[] cascade() default {};

    FetchType fetch() default FetchType.EAGER;

    boolean optional() default true;

    String mappedBy() default "";

    boolean orphanRemoval() default false;
}
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ManyToOne {
    Class targetEntity() default void.class;

    CascadeType[] cascade() default {};

    FetchType fetch() default FetchType.EAGER;

    boolean optional() default true;
}
参考博文:

JPA实体类中的注解

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值