Hibernate之CRUD与实例状态
在上一篇《初识Hibernate》中简单介绍了在Hibernate如何加载对象和持久化对象,以及Hibernate中对象实例状态。本文将继续介绍Hibernate简单的增删改查方法和对对象实例状态的理解(查询方法暂不提及)。
一、HibernateのCRUD操作
1.1 HibernateのCreate
@Test public void testCreate() { Session session = HibernateUtils.getSession(); User user = new User(); user.setId(3); user.setUserName("Sandy"); user.setPassWord("aaa"); session.save(user); }
注意:Hibernate事务默认是关闭的,执行后不会报错,但是数据并没有成功插入数据库。
控制台输出:Schema update complete
解决办法:手动设置事务提交
@Test public void testCreate() { Session session = HibernateUtils.getSession(); Transaction tx = session.beginTransaction(); User user = new User(); user.setId(3); user.setUserName("Sandy"); user.setPassWord("aaa"); session.save(user); tx.commit(); }
控制台输出:Hibernate: insert into tbl_user (username, password, id) values (?, ?, ?)
save()方法把一个临时对象加入到Session缓存中,并持久化该临时对象,计划执行一个insert语句。
1.2 HibernateのRead
这里的查询准确来说应该称为对象加载。
Hibernate中session.get()
方式获取被称为对象加载,只能从数据库中加载出唯一一条记录。查询多条数据Hibernate另提供了API。
@Test public void testRead() { Session session = HibernateUtils.getSession(); Transaction tx = session.beginTransaction(); User user = (User)session.get(User.class, 3); System.out.println(user); tx.commit(); }
控制台输出:Hibernate: select user0_.id as id1_8_0_, user0_.username as username2_8_0_, user0_.password as password3_8_0_ from tbl_user user0_ where user0_.id=?
User{id=3, userName='Sandy', passWord='aaa'}
get()和load() 试图从数据库加载一个实体对象时,Session先判断对象是否存在,如果存在就不到数据库中检索。返回的对象都位于Session缓存中,接下来修改了持久化对象的属性后,当Session清理缓存时,会根据持久化对象的属性变化来同步更新数据库。
区别:
(1)当数据库中不存在与OID对应的记录时,load()方法抛出ObjectNotFoundException异常,而get()方法返回null.
(2)两者采用不同的检索策略。
默认情况下,load()方法采用延迟检索策略(Hibernate不会执行select语句,仅返回实体类的代理类实例,占用内存很少);而get()采用立即检索策略(Hibernate会立即执行select语句)。
使用场合:
(1)如果加载一个对象的目的是为了访问它的各个属性,可以用get();
(2)如果加载一个对象的目的是为了删除它,或者建立与别的对象的关联关系,可以用load() ;
1.3 HibernateのUpdate
更新操作并没有使用session.update()
方法,直接tx.commit()
便能够成功更新数据。session.upate()
方法另有作用。
@Test public void testUpdate() { Session session = HibernateUtils.getSession(); Transaction tx = session.beginTransaction(); User user = (User)session.get(User.class, 3); user.setUserName("Bob"); user.setPassWord("123"); // 脏数据(Dirty Data) // 过时数据检测(前提是该对象是持久态) tx.commit(); }
控制台输出:Hibernate: select user0_.id as id1_8_0_, user0_.username as username2_8_0_, user0_.password as password3_8_0_ from tbl_user user0_ where user0_.id=?
Hibernate: update tbl_user set username=?, password=? where id=?
Session在清理缓存的时候会自动进行脏检查(dirty-check),如果发现Session缓存中的对象与数据库中相应的记录不一致,就会同步数据库。
1.4 HibernateのDelete
@Test public void testDelete() { Session session = HibernateUtils.getSession(); Transaction tx = session.beginTransaction(); User user = (User)session.get(User.class, 3); user.setUserName("Bob"); user.setPassWord("123"); session.delete(user); tx.commit(); }
控制台输出:Hibernate: select user0_.id as id1_8_0_, user0_.username as username2_8_0_, user0_.password as password3_8_0_ from tbl_user user0_ where user0_.id=?
Hibernate: delete from tbl_user where id=?
计划执行一个delete语句,把对象从Session缓存中删除。
1.5 saveOrUpdate
同时包含了save()和update()方法的功能。如果传入的是临时对象,就调用save()方法;如果传入的是游离对象,就调用update()方法如果传入的是持久化对象,就直接返回。
@Test public void testSaveOrUpdate() { Session session = HibernateUtils.getSession(); Transaction tx = session.beginTransaction(); User user = new User(); user.setId(5); user.setUserName("Sandy"); user.setPassWord("123"); session.saveOrUpdate(user); User user2 = (User)session.get(User.class, 1); user2.setUserName("Andy"); user2.setPassWord("apple"); session.saveOrUpdate(user2); tx.commit(); session.close(); }
控制台输出:Hibernate: select user_.id, user_.username as username2_8_, user_.password as password3_8_ from tbl_user user_ where user_.id=?
Hibernate: select user0_.id as id1_8_0_, user0_.username as username2_8_0_, user0_.password as password3_8_0_ from tbl_user user0_ where user0_.id=?
Hibernate: insert into tbl_user (username, password, id) values (?, ?, ?)
Hibernate: update tbl_user set username=?, password=? where id=?
update()方法把游离对象加入当前Session缓存中,计划执行update语句。当update()方法关联一个游离对象时,如果session缓存中已经有一个同类型且ID相同的持久化对象,那么update()方法会抛出NonUniqueException异常。当update()方法关联一个持久化对象时,该方法不起作用。close():清空session缓存。
二、Hibernateの实例状态
Hibernate中的对象有3中状态,瞬时对象(TransientObjects)、持久化对象(PersistentObjects)和离线对象(DetachedObjects也叫做脱管对象)。
Java对象在Hibernate持久化层的状态:
- 瞬时(transient)状态:刚用new语句创建,还没有被持久化,并且不处于session缓存中(处于临时状态的对象成为临时对象)。
- 持久化(Persistent)状态:已经被持久化,并且加入到session缓存中。处于持久化状态的对象称为持久化对象。
- 游离(Detached)状态:已经被持久化,但不再处于session缓存中。处于游离状态的对象称为游离对象。
- 删除状态:不再处于session缓存中,并且session已经计划将其从数据库中删除。
@Test public void testState() { Session session = HibernateUtils.getSession(); Transaction tx = session.beginTransaction(); // 持久态对象 // 1.在数据库中有唯一一条记录关联 2.必须跟一个session关联(必须纳入Hibernate容器) User user = (User)session.get(User.class, 1); // 临时态 // User user = new User(); user.setUserName("Fancy"); user.setPassWord("abc"); // 脏数据(Dirty Data)过时数据检测(前提是该对象是持久态) tx.commit(); // 关闭session session.close(); // 游离态(Detached) // 1.在数据库中有唯一一条记录对应 2.当前user没有跟Hibernate的session关联(曾经跟Hibernate关联,现在没有) // 无法进行脏数据检测 System.out.println(user); //把游离态对象变为持久态(再次纳入Hibernate容器管理,再跟一个session关联起来) Session session2 =HibernateUtils.getSession(); Transaction tx2 = session2.beginTransaction(); user.setUserName("Kathy"); user.setPassWord("good"); //把游离态对象同一个session关联,将对象状态变为持久态 session2.update(user); tx2.commit(); } }
控制台输出:Hibernate: select user0_.id as id1_8_0_, user0_.username as username2_8_0_, user0_.password as password3_8_0_ from tbl_user user0_ where user0_.id=?
User{id=1, userName='Fancy', passWord='abc'}
Hibernate: update tbl_user set username=?, password=? where id=?