hibernate-实体类状态

来源:互联网 发布:微信群淘宝优惠券代理 编辑:程序博客网 时间:2024/06/17 01:45

前言
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

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

原创粉丝点击