hibernate-实体类状态

前言
hibernate 拿起来用简单,但是用起来很扎心,经常报一些不能理解的错误。很大因素是我不理解 hibernate。hibernate 中的实体类有三大状态:瞬时状态(transient),持久化状态(persistent),游离状态(detached)。理解了这三个状态,就可知道调用一个方法,究竟发了几条 sql ,干了些什么。

瞬时状态: 不在 session 缓存中,没有保存在数据库中
持久化状态: 在 session 缓存中(被 session 托管),保存在数据库中
游离状态:不在 session 缓存中,保存在数据库中(离线状态)

PS: hibernate 二级缓存(session 缓存)是默认开启的,在向数据库查询时先查看会缓存中有没有。

各种状态转换:
enter description here

结论
1.瞬时状态,游离状态,相当于一个普通对象,没有被 session 托管,操作不影响数据库。
2.持久化状态,在 session 缓存中,被 session 托管,相关操作会影响数据库

enter description here

测试
实体类

@Entity
@Table(name = "t_user")
public class UserEntity {

    private Long id;
    private String name;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long getId() {
        return id;
    }
    public String getName() {
        return name;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public void setName(String name) {
        this.name = name;
    }

}

1.如何维护 GenerationType.IDENTITY 策略 (主键自增ID)

插入一个 user ,不设置主键ID值,发出sql: Hibernate: insert into t_user (name) values (?)

 Session session = HibernateUtil.openSession();
 session.beginTransaction();

 UserEntity userEntity = new UserEntity();
 userEntity.setName("xioamo");
 session.save(userEntity);

 session.getTransaction().commit();

插入一个 user , 设置主键ID值,发出 sql: Hibernate: insert into t_user (name) values (?)

Session session = HibernateUtil.openSession();
 session.beginTransaction();

 UserEntity userEntity = new UserEntity();
 userEntity.setName("xiaoming");
 userEntity.setId(100);
 session.save(userEntity);

 session.getTransaction().commit();

通过测试可以知道,无论是都指定主键ID的值,都不会把id 值拼接到 sql 中,也就是说主键自增ID策略,完全交给 mysql 自己来处理。你无法指定特定的主键ID。

2.瞬时状态,离线状态对象通过 setters 方法修改对象属性,不会更新到数据库。持久化状态通过通过 setters 方法修改对象属性,会更新到数据库。

userEntity 为瞬时状态,调用setters 控制台没有发出 sql

Session session = HibernateUtil.openSession();
session.beginTransaction();

UserEntity userEntity = new UserEntity();
userEntity.setName("xiaomo");

session.getTransaction().commit();

save(userEntity) 后 userEntity 转为持久化状态。发出sql: Hibernate: insert into t_user (name) values (?)

Session session = HibernateUtil.openSession();
session.beginTransaction();

UserEntity userEntity = new UserEntity();
userEntity.setName("xiaomo");
session.save(userEntity);

session.getTransaction().commit();

在 save 后 userEntity 是持久状态,修改属性,发现发出一条 update sql
sql:
Hibernate: insert into t_user (name) values (?)
Hibernate: update t_user set name=? where id=?

Session session = HibernateUtil.openSession();
session.beginTransaction();

UserEntity userEntity = new UserEntity();
userEntity.setName("xiaomo");
session.save(userEntity);
userEntity.setName("xiaoming");

session.getTransaction().commit();

相对于上面的例子在事务提交前调用 clear 清除缓存,转换为游离状态,发现没有再发出 update sql。
sql:
Hibernate: insert into t_user (address, email, name) values (?, ?, ?)

Session session = HibernateUtil.openSession();
session.beginTransaction();

UserEntity userEntity = new UserEntity();
userEntity.setName("xiaomo");
session.save(userEntity);
userEntity.setName("xiaoming");
session.clear();

session.getTransaction().commit();   

通过对比上面例子可以说明,在事务提交前 hibernate 会比对持久化状态的对象,发现当前对象内容反生改变(实际上当前对象和 session 缓存的对象是同一个,至于如何发现对象内容发生改变还没有理解清楚),则会以当前对象为准更新到数据库。而对于瞬时状态和游离状态的对象则不作处理。

3.在会话中多次save 或 update ,其运行结果:
Hibernate: insert into t_user (name) values (?)
UserEntity{id=15, name=’xiaomo’}
UserEntity{id=15, name=’xiaohong’}
Hibernate: update t_user set name=? where id=?

 Session session = HibernateUtil.openSession();
 session.beginTransaction();

 UserEntity userEntity = new UserEntity();

 userEntity.setName("xiaomo");
 session.save(userEntity);
 System.out.println(session.get(UserEntity.class,userEntity.getId()));

 userEntity.setName("xiaoming");
 session.save(userEntity);

 userEntity.setName("xiaohong");
 session.update(userEntity);

 System.out.println(session.get(UserEntity.class,userEntity.getId()));
 session.getTransaction().commit();

从上面的测试可以发现只发出了两条 sql ,对于持久化状态的对象,调用 save 或 update 是不起作用的,而是在事务提交前检查对象是否改变,若改变则更新到数据库,通过这样来维护数据库与 session 缓存对象的一致性,大概更高效吧。

4.执行 update(),只会把对象由非持久状态(如果是非持久状态)转换为持久化状态,真正的 update sql 是在事务提交时发出的。
结果:
before update run
after update run
Hibernate: update t_user set name=? where id=?

Session session = HibernateUtil.openSession();
session.beginTransaction();

UserEntity userEntity = new UserEntity();

userEntity.setId(2l);
System.out.println("before update run");
session.update(userEntity);
System.out.println("after update run");

session.getTransaction().commit();

小结:当前被操纵的 java 实体类对象,如果是瞬时状态或者游离状态,则此时没有与数据库关联,如果是持久化状态,该对象(其实就是session缓存的对象)与session 相关联,改变对象属性会更新到数据库。更新到数据库是发生在事务提交的时候。

enter description here

以上是单表的测试,可以合理猜测在关联表中,实体类,关联实体类的都几个状态转换与含义都一样的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值