聊聊Spring Data JPA的注解

2020-01-03  本文已影响0人  shadowCc

阅读本文之前,为了更好的理解,你应该先搭建一个Spring Data JPA的helloword的例子

概念

在说Spring Data JPA(后面简称SDJ)之前,先了解下什么是JPA(java persistence api)。

何为JPA

JPA的规范

JPA规范的对象以及如何规范。通过一些列的注解来标注普通实体对象,以及对象的之间的关系,使指成为Domain Class(域对象)。在此对象封装一层操作API。

  1. @Entity 注解在实体类上,也是JPA的操作对象。
  2. @Table 指定实体类对应的表名。
  3. @Id 指定主键。
  4. @GeneratedValue 主键的生成策略。可选的类型有
    TABLE:使用一个特定的数据库表格来保存主键。一般配合@TableGenerator使用
    SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列,比如oracle。 一般配合@SequenceGenerator使用
    IDENTITY:主键由数据库自动生成(主要是自动增长型)
    AUTO:主键由程序控制。
  5. @Column 可以对实体类的属性起别名,对应表中的字段,以及对该字段添加一些非空等约束。

例子1 User和Heart对象

public class User{
  //主键
  private Long id;
  //心脏
  //@OneToOne
  //@ManyToOne
  private Hear heart;
  //...
}

public class Heart{
  //主键
  private Long id;
  //重量
  private Double weight;
  //...
}
  1. @OneToOne 表示实体类与嵌入式类之间一对一的映射关系。这个注解用在一个实体类包含一个嵌入式的类。比如在在例子1里,这个注解放在User类的Heart属性上。当SDJ生成表的时候,会在User表上生成一个字段名为heart_id的外键。该注解有个级联cascade的属性,可选(ALL,PERSIST,MERGE,REMOVE,REFRESH,DETACH),拿PERSIST说明,当调用Spring Data JPA中的Reponsitory中的save方法保存User对象的时候,如果User对象中含有Heart对象的实例时候,会同时将Heart对象也保存到数据库中。

  2. @ManyToOne、@OneToMany、@ManyToMany 用法都差不多。具体细节。后面会再次说明


  1. @JoinColumn 此注解一般会配合上面的6、7两点中的关系注解一起使用。表示关系拥有者的外键相关。

例子2

public class User{
  //主键
  private Long id;
  //心脏
  @OneToOne
  @ManyToOne(表示多个人对应一个心脏,比如连体人,例子不是那么恰当,大致是这个意思)
  @JoinColumn(name = "heartId",referencedColumnName = "id")
  
  private Hear heart;
  //...
}

public class Heart{
  //主键
  private Long id;
  //重量
  private Double weight;
  //...
}

例子3


public class Country{
  //主键
  private Long id;
  
  @OneToMany
  @JoinColumn(name = "countryId",referencedColumnName = "id")
  
  private List<People> peoples;
  //...
}

public class People{
  //主键
  private Long id;
  //重量
  private String name;
  //...
}

在这个例子里,people对应的表会有个外键,对应着country实体的表的id。

到目前为止,说的都是实体类的单向关系(unidirectional),比如拿上面的例子来说,通过country类 我们知道有哪些people,但是从people类,我并不知道people对应的country。此时若想满足这个需求,就得靠注解形成双向关系(bidirectional)。请看下面的例子。

例子4


public class Country{
  //主键
  private Long id;
  
  @OneToMany(mappedBy="country")
  private List<People> peoples;
  //...
}

public class People{
  //主键
  private Long id;
  //
  private String name;

  @ManyToOne
  private Country country;
  //...
}

可以看出在双向关系中,需要在相互关系的类中配置对应的注解。此时表结构与例子3的表结构一样,在例子4中,@OneToMany的mappedBy注解是只能配置在双向关系中。

  1. @ManyToMany 多对多映射,这种关系肯定会设计到第三张表来存储实体之间的关系。

例子5

public class User{
  private Long id;
  private String name;
  @ManyToMany
  private List<Role> roleList;
}

public class Role{
  private Long id;
  private String name;
}

此时你如果用SDJ自动生成表的话,你会在数据库里面看到一张除了User和Role之外的表。如下

create table if not exists jpa.user_role_list
(
    user_id bigint not null,
    role_id bigint not null,
    constraint FK8hyj0c7rglkeyinrekdeul39
        foreign key (user_id) references jpa.user (id),
    constraint FKofayuingjc8gnn4bkdek0s8sv
        foreign key (role_id) references jpa.role (id)
);

你可以指定生成的表名以及里面的列名,对User修改如下

public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false,length = 12)
    private  String name;

    private Integer sex;

    @ManyToMany
    @JoinTable(name = "t_user_role",joinColumns = {@JoinColumn(name = "userId",referencedColumnName = "id")}
    ,inverseJoinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "id")})
    private List<Role> roleList;

此时生成的关联表结构如下

create table if not exists jpa.t_user_role
(
    user_id bigint not null,
    role_id bigint not null,
    constraint FKjwwimwt7mcivvbosl7rms6q4y
        foreign key (role_id) references jpa.role (id),
    constraint FKm61t2kt35dkh35mbd8t0wjisl
        foreign key (user_id) references jpa.user (id)
);

小结

到目前为止,了解了JPA中这些主要的注解,主要是通过注解来标注实体类(domain class)与表的映射关系以及实体类之间的关系,当然实际也是表之间的关系。回过头看,如果我们的系统中 ORM框架切换到mybatis这种,可能在项目的前期工作转备好之后,我们先设计表,甚至现在都不会建立外键这种约束了,而是会完全由业务代码来维护。而JPA主要让使用者只关心domain class,表之间的关系也不需要使用者去在意,所谓的面向OO,而mybatis这种是面向关系的。听上去OO编程显得更高大上一点,毕竟java就是OO的语言。

下一节 说说Spring Data JPA的使用。

上一篇 下一篇

猜你喜欢

热点阅读