java · 2025-04-30 0

jpa @GeneratedValue 注解的使用及自动生成的 sql

一、pom 依赖

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.2.18.Final</version>
    <!-- <version>5.6.10.Final</version> -->
</dependency>

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.2.27</version>
</dependency>

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.26</version>
    <scope>provided</scope>
</dependency>

二、java

1.配置文件

新建配置文件 resources/META-INF/persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
             http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">

    <persistence-unit name="myjpa">
        <!-- jpa的实现产品 -->
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <properties>
            <!-- 数据库连接配置 -->
            <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://127.0.0.1:5432/postgres"/>
            <property name="javax.persistence.jdbc.user" value="postgres"/>
            <property name="javax.persistence.jdbc.password" value="123456"/>
            <!-- hibernate的配置 -->
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

2.实体类

1) @Entity:标注在实体类名上。标识为jpa实体类
2) @Table:标注在实体类名上。把该实体类映射到实际的表名,这个其实是非必需的,但一般实体类的名字和表名都不一样,所以认为就是必需的

@Setter
@Getter
@Entity
@Table(name = "t_student")
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    // @GeneratedValue(strategy = GenerationType.SEQUENCE)
    // @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private String name;
}

3.测试类

@Test
public void testPersist() {
    /**
     * 通过 Persistence 获取 EntityManagerFactory, 传入参数对应配置文件中持久化单元 persistence-unit 的 name
     * 通过 EntityManagerFactory 创建 EntityManager 获取 EntityTransaction 开启事务
     */
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("myjpa");
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();

    Student stu = new Student();
    stu.setId(null);
    stu.setName("stu1");

    // 转换为托管状态
    entityManager.persist(stu);

    /**
     * 提交事务 关闭 entityManager 关闭 entityManagerFactory
     */
    transaction.commit();
    entityManager.close();
    entityManagerFactory.close();
}

三、结论

1.无 @GeneratedValue 注解时

@Setter
@Getter
@Entity
@Table(name = "t_student")
public class Student {

    @Id
    // @GeneratedValue(strategy = GenerationType.IDENTITY)
    // @GeneratedValue(strategy = GenerationType.SEQUENCE)
    // @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private String name;
}

生成创建表 sql

create table t_student (
    id int4 not null,
    name varchar(255),
    primary key (id)
)

保存实体时,需要设置 id ,因为 id 是主键,设置 null,会报错

1.执行 Student stu = new Student(null, "stu1"); entityManager.persist(stu)
  1) 报错

2.执行 Student stu = new Student(null, "stu1"); entityManager.merge(stu)
  1) 报错

3.执行 Student stu = new Student(10, "stu1"); entityManager.persist(stu);
  1) 若数据库不存在数据(10),则生成 sql,
     insert into t_student(name, id) values (?, ?);
  2) 数据库存在数据(10, "stu1"),则报错
  3) 数据库存在数据(10, "stu0"),则报错

4.执行 Student stu = new Student(10, "stu1"); entityManager.merge(stu);
  1) 若数据库不存在数据(10),则生成 sql,
     select student0_.id as id1_0_0_, student0_.name as name2_0_0_ from t_student student0_ where student0_.id=?; 
     insert into t_student(name, id) values (?, ?);
  2) 数据库存在数据(10, "stu1"),则生成 sql,
     select student0_.id as id1_0_0_, student0_.name as name2_0_0_ from t_student student0_ where student0_.id=?;
  3) 数据库存在数据(10, "stu0"),则生成 sql,
     select student0_.id as id1_0_0_, student0_.name as name2_0_0_ from t_student student0_ where student0_.id=?; 
     update t_student set name=? where id=?;

2.@GeneratedValue(strategy = GenerationType.IDENTITY)

@Setter
@Getter
@Entity
@Table(name = "t_student")
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    // @GeneratedValue(strategy = GenerationType.SEQUENCE)
    // @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private String name;
}

生成创建表 sql

-- org.hibernate:hibernate-core:5.2.18.Final 版本生成为
create table t_student (
    id  serial not null,
    name varchar(255),
    primary key (id)
)

-- org.hibernate:hibernate-core:5.6.10.Final 版本生成为
create table t_student (
   id int4 generated by default as identity,
    name varchar(255),
    primary key (id)
)
1.执行 Student stu = new Student(null, "stu1"); entityManager.persist(stu)
  1) 则生成 sql,
     insert into t_student(name) values (?);

2.执行 Student stu = new Student(null, "stu1"); entityManager.merge(stu)
  1) 则生成 sql,
     insert into t_student(name) values (?);

3.执行 Student stu = new Student(10, "stu1"); entityManager.persist(stu);
  1) 若数据库不存在数据(10),则报错
  2) 数据库存在数据(10, "stu1"),则报错
  3) 数据库存在数据(10, "stu0"),则报错

4.执行 Student stu = new Student(10, "stu1"); entityManager.merge(stu);
  1) 若数据库不存在数据(10),则生成sql,
     select student0_.id as id1_0_0_, student0_.name as name2_0_0_ from t_student student0_ where student0_.id=?; 
     insert into t_student(name) values (?);
  2) 数据库存在数据(10, "stu1"),则生成sql,
     select student0_.id as id1_0_0_, student0_.name as name2_0_0_ from t_student student0_ where student0_.id=?;
  3) 数据库存在数据(10, "stu0"),则生成sql,
     select student0_.id as id1_0_0_, student0_.name as name2_0_0_ from t_student student0_ where student0_.id=?; 
     update t_student set name=? where id=?;

注:当数据库不存在数据(10)时,new Student(10, "stu1") 相当于 new Student(null, "stu1"),id 由数据库生成。

3.@GeneratedValue(strategy = GenerationType.SEQUENCE)

@Setter
@Getter
@Entity
@Table(name = "t_student")
public class Student {

    @Id
    // @GeneratedValue(strategy = GenerationType.IDENTITY)
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    // @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    private String name;
}

生成创建表 sql

create table t_student (
    id int4 not null,
    name varchar(255),
    primary key (id)
)

保存实体时,需要设置 id ,因为 id 是主键,设置 null,会报错

1.执行 Student stu = new Student(null, "stu1"); entityManager.persist(stu)
  1) 则生成 sql,
     select nextval ('hibernate_sequence');
     insert into t_student(name, id) values (?, ?);

2.执行 Student stu = new Student(null, "stu1"); entityManager.merge(stu)
  1) 则生成 sql,
     select nextval ('hibernate_sequence');
     insert into t_student(name, id) values (?, ?);

3.执行 Student stu = new Student(10, "stu1"); entityManager.persist(stu);
  1) 若数据库不存在数据(10),则报错
  2) 数据库存在数据(10, "stu1"),则报错
  3) 数据库存在数据(10, "stu0"),则报错

4.执行 Student stu = new Student(10, "stu1"); entityManager.merge(stu);
  1) 若数据库不存在数据(10),则生成sql,
     select student0_.id as id1_0_0_, student0_.name as name2_0_0_ from t_student student0_ where student0_.id=?; 
     select nextval ('hibernate_sequence');
     insert into t_student(name, id) values (?, ?);
  2) 数据库存在数据(10, "stu1"),则生成sql,
     select student0_.id as id1_0_0_, student0_.name as name2_0_0_ from t_student student0_ where student0_.id=?;
  3) 数据库存在数据(10, "stu0"),则生成sql,
     select student0_.id as id1_0_0_, student0_.name as name2_0_0_ from t_student student0_ where student0_.id=?; 
     update t_student set name=? where id=?;

注:当数据库不存在数据(10)时,new Student(10, "stu1") 相当于 new Student(null, "stu1"),id 由有查询的序列生成。

4.@GeneratedValue 或 @GeneratedValue(strategy = GenerationType.AUTO)

对于 pg,等同于 GenerationType.SEQUENCE