Hibernate学习笔记

学习途径: 百度搜索”Hibernate注解开发”就可以学到相关的内容

实体类的条件

  • @Entity注解
  • 一个空参构造器
  • 对应的setter、getter方法

操作数据的几种方式

  • entityManager.createNativeQuery()创建原生的sql语句操作
  • 编写JPQL语句进行操作
  • 使用entityManager提供的一些方法进行操作(find、remove、merge)

高级:Panache操作数据库

https://quarkus.io/guides/hibernate-orm-panache
官方文档介绍了使用Panache更方便的操作数据的办法

相关的注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Id —— 注解声明了该实体bean的标识属性(对应表中的主键)。
@Column —— 注解声明了属性到列的映射。该注解有如下的属性
name 可选,列名(默认值是属性名)
unique 可选,是否在该列上设置唯一约束(默认值false
nullable 可选,是否设置该列的值可以为空(默认值false
insertable 可选,该列是否作为生成的insert语句中的一个列(默认值true
updatable 可选,该列是否作为生成的update语句中的一个列(默认值true
columnDefinition 可选,为这个特定列覆盖sql ddl片段(这可能导致无法在不同数据库间移植)
table 可选,定义对应的表(默认为主表)
length 可选,列长度(默认值255
precision 可选,列十进制精度(decimal precision)(默认值0
scale 可选,如果列十进制数值范围(decimal scale)可用,在此设置(默认值0
@GeneratedValue —— 注解声明了主键的生成策略。该注解有如下属性
strategy 指定生成的策略(JPA定义的),这是一个GenerationType。默认是GenerationType. AUTO
GenerationType.AUTO 主键由程序控制
GenerationType.TABLE 使用一个特定的数据库表格来保存主键
GenerationType.IDENTITY 主键由数据库自动生成(主要是自动增长类型)
GenerationType.SEQUENCE 根据底层数据库的序列来生成主键,条件是数据库支持序列。(这个值要与generator一起使用)
generator 指定生成主键使用的生成器(可能是orcale中的序列)。
@SequenceGenerator —— 注解声明了一个数据库序列。该注解有如下属性
name 表示该表主键生成策略名称,它被引用在@GeneratedValue中设置的“gernerator”值中
sequenceName 表示生成策略用到的数据库序列名称。
initialValue 表示主键初始值,默认为0.
allocationSize 每次主键值增加的大小,例如设置成1,则表示每次创建新记录后自动加1,默认为50.

Cascade级联操作(CascadeType.ALL是全都可以操作,最好不要用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CascadeType.PERSIST:级联新增(又称级联保存):对order对象保存时也对items里的对象也会保存。对应EntityManager的presist方法。

例子:只有A类新增时,会级联B对象新增。若B对象在数据库存(跟新)在则抛异常(让B变为持久态)

CascadeType.MERGE:级联合并(级联更新):若items属性修改了那么order对象保存时同时修改items里的对象。对应EntityManager的merge方法 。
例子:指A类新增或者变化,会级联B对象(新增或者变化)

CascadeType.REMOVE:级联删除:对order对象删除也对items里的对象也会删除。对应EntityManager的remove方法。

例子:REMOVE只有A类删除时,会级联删除B类;

CascadeType.REFRESH:级联刷新:获取order对象里也同时也重新获取最新的items时的对象。对应EntityManager的refresh(object)方法有效。即会重新查询数据库里的最新数据。

CascadeType.ALL:以上四种都是。

注:多个级联权限用{}包起来,如:{cascade = CascadeType.MERGE,CascadeType.REMOVE} optional

关系注解(这个搞对了,才能实现返回级联对象,不必手动组装对象返回)

ManyToOne和OneToMany的区别

  • 首先!不要去想数据库!不要去想数据库!不要去想数据库!用了Hibernate,所有的表结构,全部用代码就可以表现
  • 其次,理清多和一,谁是多,谁是一! 以学生和班级举例,学生是多,班级是一
  • 然后,@ManyToOne加在多的一方属性上头,@OnToMany就加在一的那一方的属性头上,一的一方的实体的属性类型肯定是List(这两个注解作用是相同的,其中一方的实体加就可以了)

@JoinColumn()注解中的name属性写什么?

  • name写一的那方的小写+id(比如:banji_id),其实就体现为数据库的外键名

单向和双向

单向关联 :指具有关联关系的实体对象间的加载与访问关系是单向的。即,只有一个实体对象可以加载和访问对方,但对方是看不到另一方的。
双向关联:双向关联是指具有关联关系的实体对象间的加载与访问关系是双向的。即,任何一方均可加载和访问另一方。

Hibernate对象的三种实体状态

Hibernate有三种实体状态,有瞬时态(transiant),持久态(persistent),游离态(detached)。 简单理解就是,瞬时态指的是刚New 新建的一个对象,没有放在Session时,也没有存储在数据库中。 持久态,指这个对象存储在数据库中,并且存在于Session会话中。 而游离态指的是,这个对象存储在数据库中,但已经不存在于Session会话中。

持久化上下文


其实所谓的 Hibernate 持久化上下文指的是 Session 接口或 JPA 的 EntityManager 接口,我们对数据库进行操作都是通过它来实现的。
刚创建的实体类对象的状态是 transient
通过调用 session 的 persist 或 save 方法,实体类对象由 session 管理,它的状态变为了 persistent,此后对该对象的修改操作都会调用 flush 后被同步到数据库中
我们也可以调用 session 的 detach, evict 或 clear 方法把对象移出 session,它的状态变为了 detached,对 detached 对象的操作不会同步到数据库中
如果你想把 detached 对象重新加入到 session 中,我们可以调用 lock, update 或 saveOrUpdate
我们也可以使用 merge 方法把 detached 对象 merge 到 persistent 对象中
我们也可以使用 contains 判断对象是否已经加入 session 中 (persistent 对象)
最后调用 session 的 delete 或 remove 后,它的状态变为 removed

flush 方法用来把对象同步到数据库中
refresh 方法用来把数据库的值同步到对象中

一些注意事项:

  1. 如果你想要实现级联插入操作,那么在定义实体的时候,对应的一方的外键属性不要设置@Column_(nullable = false),否则你插入的时候会报错,你传来的数据肯定是不含有两个实体id(id都是通过数据库自动生成的),但是由于你设置了nullable=false,所以就报错了。_

EntityManager

在各个Resource类中,都会注入EntityManager对象,该对象执行操作数据库的工作

下面的是JPA的官方文档,里面可以看,列出了相关的方法

https://jakarta.ee/specifications/persistence/3.0/apidocs/allclasses.html

总结增删改查:

  • em.persist()
  • em.remove()
  • em.merge()
  • em.find()和em.getReference()

枚举类型映射到数据库

  • 定义实体的时候不加注解

    当不使用任何注解的时候,默认情况下是使用ordinal属性,也就是Enum类型实例在Enum中声明的顺序来完成映射的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    enum Sex{
    FEMALA,
    MALA
    }
    public class Student(){
    @Id
    @GeneratedValue
    private Integer id,
    @Column
    private String name,
    @Column
    private String address,
    @Column
    private Sex sex
    }

    由于使用ordinal所以,hibernate在建表的时候,会把Student表里的sex字段定义成int,FAMALE保存成0,MALE保存成1

  • 使用@Enumerated注解标记对应的字段

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public enum Gender {
    male("男"),
    female("女");

    private String name;
    private Gender(String name){
    this.name = name;
    }

    public String getName(){
    return this.name;
    }
    }
    //注意,这里的注解类,两个枚举被添加了name属性
    public class Student(){
    @Id
    @GeneratedValue
    private Integer id,
    @Column
    private String name,
    @Column
    private String address,
    @Column
    @Enumerated
    private Gender gender,
    }

    使用了@Enumerated的注解之后,数据库的字段类型会变成String对应的varchar,而插入数据时,就会变成对应的字符串,如果插入Gender.male;那么数据库里面就是“男”


Hibernate学习笔记
http://blog.jingxiang.ltd/2023/03/30/Hibernate学习笔记/
作者
yemangran
发布于
2023年3月30日
许可协议