java · 2025-04-30 0

jpa 实体四种状态

一、pom 依赖

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.2.18.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(null, "stu1");

    // 转换为托管状态
    // 只要事务不提交,数据库中的数据可以随时跟随托管状态实体类的值变化
    // PERSISTENT, TRANSIENT, DETACHED, DELETED
    // TRANSIENT 到 PERSISTENT
    entityManager.persist(stu);
    stu.setName("stu2");
    entityManager.persist(stu);

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

@Test
public void testMerge1() {
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("myjpa");
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();

    Student stu = new Student(null, "stu1");

    // 转换为托管状态
    // 只要事务不提交,数据库中的数据可以随时跟随托管状态实体类的值变化
    // 由于实体类状态不是托管状态,所以merge之后 改变实体类值并不会自动同步数据,但merge会返回一个托管状态的实体类
    entityManager.merge(stu);
    stu.setName("stu2");

    transaction.commit();
    entityManager.close();
    entityManagerFactory.close();
}

@Test
public void testMerge2() {
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("myjpa");
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();

    Student stu = new Student(null, "stu1");

    // 返回托管状态的实体类
    // 只要事务不提交,数据库中的数据可以随时跟随托管状态实体类的值变化
    // 由于实体类状态不是托管状态,所以merge之后 改变实体类值并不会自动同步数据,但merge会返回一个托管状态的实体类
    Student newStudent = entityManager.merge(stu);
    newStudent.setName("stu2");

    transaction.commit();
    entityManager.close();
    entityManagerFactory.close();
}

@Test
public void testFind() {
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("myjpa");
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();

    // 返回托管状态的实体类
    // 只要事务不提交,数据库中的数据可以随时跟随托管状态实体类的值变化
    Student student = entityManager.find(Student.class, 1);
    student.setName("stu2");

    transaction.commit();
    entityManager.close();
    entityManagerFactory.close();
}

@Test
public void testDetach() {
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("myjpa");
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();

    // 返回托管状态的实体类
    // 只要事务不提交,数据库中的数据可以随时跟随托管状态实体类的值变化
    Student student = entityManager.find(Student.class, 1);
    // 变成游离态
    entityManager.detach(student);
    // clear 也可以,是把整个上下文中托管态的都变成游离态,所以要慎用
    // entityManager.clear();
    student.setName("stu2");
    // 能提交到数据库,但 student 依然是游离态
    entityManager.merge(student);
    // 无法自动更新数据
    student.setName("stu3");;

    transaction.commit();
    entityManager.close();
    entityManagerFactory.close();
}

@Test
public void testDetach1() {
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("myjpa");
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();

    // 返回托管状态的实体类
    // 只要事务不提交,数据库中的数据可以随时跟随托管状态实体类的值变化
    Student student = entityManager.find(Student.class, 1);
    // 变为游离态
    entityManager.detach(student);
    // 游离态不能 persist
    // javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: org.example.entity.Student
    entityManager.persist(student);

    transaction.commit();
    entityManager.close();
    entityManagerFactory.close();
}

@Test
public void testRemove() {
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("myjpa");
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();

    // 返回托管状态的实体类
    // 只要事务不提交,数据库中的数据可以随时跟随托管状态实体类的值变化
    Student student = entityManager.find(Student.class, 1);
    // 通过 persist,删除态再次变为托管态,此时提交事务就不会删除了
    entityManager.persist(student);

    transaction.commit();
    entityManager.close();
    entityManagerFactory.close();
}

四、其他

jpa

瞬时态(Transient):指新创建的实体对象,没有被赋值 ID,也未与任何 EntityManager 关联
它的状态依然取决于它是否与持久化上下文(通过 EntityManager)关联。

瞬时态(Transient):如果你新创建了一个实体对象,并手动设置了其 ID 值,但在将其传递给 EntityManager 进行管理之前,这个对象仍然是瞬时态。这意味着该对象并未与数据库中的任何记录关联,JPA 不会认为它是数据库中已存在实体的一部分。