Hibernate的对象操作方法
四种: 持久化状态, 临时状态, 游离状态, 删除状态. Session 的特定方法能使对象从一个状态转换到另一个状态.
1. 临时对象(Transient): 在使用代理主键的情况下, OID 通常为 null 不处于 Session 的缓存中 在数据库中没有对应的记录
2. 持久化对象(也叫”托管”)(Persist): OID 不为 null 位于 Session 缓存中 若在数据库中已经有和其对应的记录, 持久化对象和数据库中的相关记录对应 Session 在 flush 缓存时, 会根据持久化对象的属性变化, 来同步更新数据库 在同一个 Session 实例的缓存中, 数据库表中的每条记录只对应唯一的持久化对象
3. 删除对象(Removed): 在数据库中没有和其 OID 对应的记录 不再处于 Session 缓存中 一般情况下, 应用程序不该再使用被删除的对象
4. 游离对象(也叫”脱管”) (Detached): OID 不为 null 不再处于 Session 缓存中 一般情况需下, 游离对象是由持久化对象转变过来的, 因此在数据库中可能还存在与它对应的记录
修改News.hbm.xml: <generator class="hilo" />
1. save() 方法
* 1). 使一个临时对象变为持久化对象
* 2). 为对象分配 ID.
* 3). 在 flush 缓存时会发送一条 INSERT 语句.
* 4). 在 save 方法之前的 id 是无效的
* 5). 持久化对象的 ID 是不能被修改的!
@Test
public void testSave() {
News news = new News();
news.setTitle("Java");
news.setAuthod("Peter");
news.setDate(new Date());
news.setId(101); // 在save方法执行之前设置id是无效的
System.out.println(news);
session.save(news);
System.out.println(news);
//news.setId(1002); // 因为执行了save方法, 该news对象就是持久化对象, 而持久化对象的主键是不能被修改的
}
后台打印:
News [id=null, title=Java, authod=Peter, date=Tue Mar 14 16:11:13 CST 2017]
Hibernate: select next_hi from hibernate_unique_key for update
Hibernate: update hibernate_unique_key set next_hi = ? where next_hi = ?
News [id=65536, title=Java, authod=Peter, date=Tue Mar 14 16:11:13 CST 2017]
Hibernate: insert into NEWS (TITLE, AUTHOD, DATE, ID) values (?, ?, ?, ?)
2. persist(): 也会执行 INSERT 操作
和 save() 的区别 : 在调用 persist 方法之前, 若对象已经有 id 了, 则不会执行 INSERT, 而抛出异常
3. get VS load:
* 1. 执行 get 方法: 会立即加载对象.
* 执行 load 方法, 若不适用该对象, 则不会立即执行查询操作, 而返回一个代理对象
* get 是 立即检索, load 是延迟检索.
* 2. load 方法可能会抛出 LazyInitializationException 异常: 在需要初始化时候, 代理对象之前已经关闭了 Session
* 3. 若数据表中没有对应的记录, Session 也没有被关闭.
get 返回 null
load 若不使用该对象的任何属性, 没问题; 若需要初始化了, 抛出异常. 因为load方法会返回一个代理对象, 如果load之后发现找不到这个对象, 所以会抛异常
4. update() 方法
使一个游离对象转变为持久化对象, 并且计划执行一条 update 语句.
update:
* 1. 若更新一个持久化对象, 不需要显示的调用 update 方法. 因为在调用 Transaction
* 的 commit() 方法时, 会先执行 session 的 flush 方法.
-----------------> 测试:
@Test
public void test() {
News news = (News) session.get(News.class, 65536); // 这是一个持久化对象
news.setAuthod("Tom"); // 试图更新一个持久化对象的记录
}
后台:
Hibernate: select news0_.ID as ID1_0_0_, news0_.TITLE as TITLE2_0_0_, news0_.AUTHOD as AUTHOD3_0_0_, news0_.DATE as DATE4_0_0_ from NEWS news0_ where news0_.ID=?
Hibernate: update NEWS set TITLE=?, AUTHOD=?, DATE=? where ID=?
* 2. 更新一个游离对象, 需要显式的调用 session 的 update 方法. 可以把一个游离对象
* 变为持久化对象
@Test
public void test() {
News news = (News) session.get(News.class, 65536); // 这是一个持久化对象
session.close(); // session关闭, news对象变为了游离对象(不在session缓存中)
session = sessionFactory.openSession(); // 重新打开session, news已经不在缓存中
transaction = session.beginTransaction(); // 重新开启事务
news.setAuthod("Lucy");
session.update(news); // 需要显示调用update, 会发送UPDATE语句, 这时候数据库中的记录会更新
}
* 需要注意的:(必须是游离对象, 如果是持久化对象, 那么不会盲目发送update语句, 因为在update之前会flush以下, 如果一致就不发送)
* 1. 无论要更新的游离对象和数据表的记录是否一致, 都会发送 UPDATE 语句.
* 如何能让 updat 方法不再盲目的出发 update 语句呢 ? 在 .hbm.xml 文件的 class 节点设置
* select-before-update=true (默认为 false). 但通常不需要设置该属性. 因为设置这个属性之后, 虽然不发送update语句, 但是会多发一条select语句,
* 效率并没有得到提高, 所以在没有和触发器协同工作的时候, 可以不用设置这个属性(因为触发器是根据udpate语句来触发的
*
* 2. 若数据表中没有对应的记录, 但还调用了 update 方法, 会抛出异常
*
* 3. 当 update() 方法关联一个游离对象时,
* 如果在 Session 的缓存中已经存在相同 OID 的持久化对象, 会抛出异常. 因为在 Session 缓存中
* 不能有两个 OID 相同的对象!
5. saveOrUpdate()
如果对象是游离对象, 就会调用其中的update方法,
如果对象是临时对象, 就会调用其中的save方法, 把对象转成持久化对象
6. delete()
只要 OID 和数据表中一条记录对应, 就会准备执行 delete 操作, 但是其在数据库中的id并没有被删除,
如果这时候对已经删除的对象但是数据库中还存在其id的对象进行save或者update操作就会则抛出异常, 导致误判,
可以通过设置 hibernate 配置文件 hibernate.use_identifier_rollback 为 true, 使删除对象后, 把其 OID 置为 null, 此属性在开发中用的不多
7. evict()
从 session 缓存中把指定的持久化对象移除
8. doWork()
@Test
public void testDoWork(){
session.doWork(new Work() {
@Override
public void execute(Connection connection) throws SQLException {
System.out.println(connection);
//调用存储过程.
}
});
}
调用存储过程:
9. 动态更新和动态插入
@Test
public void test() {
News news = (News) session.get(News.class, 32768);
session.update(news);
}
后台打印:
Hibernate:
select
news0_.ID as ID1_0_0_,
news0_.TITLE as TITLE2_0_0_,
news0_.AUTHOD as AUTHOD3_0_0_,
news0_.DATE as DATE4_0_0_
from
NEWS news0_
where
news0_.ID=?
Hibernate:
update
NEWS
set
TITLE=?,
AUTHOD=?,
DATE=?
where
ID=?
问题: 只修改了一个字段却修改了三个字段, 说明发的不是动态sql, 如果想只修改对应的字段, 可以在News.hbm.xml中的class节点添加属性
dynamic-update="true"
测试: 只修改了authod这个字段
Hibernate:
update
NEWS
set
AUTHOD=?
where
ID=?