脱管引发出来的知识点
对象的状态:
// 准确的说是Hibernate对象的状态,和session和数据库有微妙关系
瞬时(transient):
持久(persistent):
脱管(detached):
三种状态分析
瞬时状态时对象跟session和数据库都木有关系;session中木有该对象,数据库中木有这条记录对应;生命周期很短;
持久状态时对象保存在session中,他如果有任何变化,数据库都会做出对应修改;
脱管状态时对象是session关闭之后的对象,数据库中有对应的记录,但session中木有了。脱管对象再发生变化,数据库不会再进行对应调整;此时的对象ID是有值的;
个人分析by kang.cunhua:
国外的科技工作者研究工作做得很细致,同时导致了很多抽象名词的产生,加上汉语的博大精深,就会出现一些莫名其妙或高深莫测的翻译;看不懂或者懒得看官方解释的,且看以下数行个人分析;
瞬时,持久和脱管,都是针对的一个对象的三种不同阶段的状态,
- 瞬时状态对应对象的产生和赋值;(对象:啊~,我生在甲骨文,长在Hibernate下。我将接受Hibernate和Java给予我的教育和责任!Hibernate:你要牢记Hibernate和Java赋予你的责任和义务,好好学习,天天向上,争取早日加入hibernate,为Hibernate和Java做贡献!// 注,本来应该是生在SUN的,但最近SUN被甲骨文收购了。)
- 持久状态对应对象进入Hibernate的作用域(Hibernate:现在我罩着你;对象:我光荣的加入了持久层)
- 脱管状态对应对象脱离Hibernate的作用域,已完成持久化的使命,退出持久层的舞台。(Hibernate:祝贺你光荣地从舞台退休了!我代表Hibernate和Java感谢你对持久层做出的贡献!);脱离了Hibernate的舞台,你的所作所为都和持久层木有任何关系了。从现在开始,你要为你自己的行为负全责!
废话罗嗦完了,且看精彩的地方!
Hibernate对对象划分了三种状态,瞬时、持久、和脱管。只有处于持久状态(session开启和木有关闭之前),对象的任何改动都会同步变更到数据库;那么问题来了,我接收到一个参数,是个对象,我怎么知道这个对象是瞬时的还是脱管的?
Hibernate的高明设计:
- hibernate设计了两种方法saveOrUpdate方法和merge方法来自动处理状态不明的Object(对象)参数;hibernate自己去做处理。
- 两者的区别在于,saveOrUpdate方法在于处理完后对象会变成持久的;merge方法处理完之后,对象会变成脱管的;不管对象之前是什么状态;
新问题来了:Hibernate的判断依据是虾米:
根据ID,瞬时对象的id是0,而脱管对象是有值的,且>0。如果id是string,则默认是null;这个id的默认值可以在Hibernate的映射文件如User.hbm.xml中来配置,<id name="id" unsaveed-value="-1">;不推荐自定义;很少用到;
Hibernate会在某个状态将持久状态的对象更新到数据库。现在可以理解为到提交(commit;)的时候。具体是哪个时间点儿,且看后续教程讲解;
对象状态转换图:
来一段代码,说明一下:
/**
* Hibernate简洁调用模板
* @param user
*/
static void addUser1(User user) {
Session s = null;
Transaction tx = null;
try {
s = HibernateUtil.getSession();
tx = s.beginTransaction();
s.save(user);
user.setName("new name"); // 此时的对象是持久对象,此处更新user会对数据库也做更新
user.setBirthday( new Date() );
/**
* 此时又做了一条update,但在Hibernate并不会立即更新数据库。
* 而会做一些优化,比如合并这两条更新为一条update语句,在某个时间点做此更新。
* 所以在控制台可以看到只有一条update语句输出;
* 现在可以理解为提交的时候。后续会详细讲解具体提交的时间点;
*/
tx.commit();
} finally {
if (s != null) {
s.close();
}
}
}
源码列表:
这一讲仅更新了一个文件
Mian.java
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package cn.itcast.hibernate.domain;import cn.itcast.hibernate.HibernateUtil;
import java.util.Date;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;/**
*
* @author kang.cunhua
*/
public class Main {/**
* @param args the command line arguments
*/
public static void main(String[] args) {User user = new User();
user.setBirthday(new Date());
user.setName("谷歌");System.out.println("----- Hibernate标准调用模板演示 -----");
addUser(user);
//addUser1(user); // Hibernate简介调用模板演示
System.out.println("id:" + user.getId());System.out.println("----- 根据ID得到对象:演示get方法; -----");
User u = getUser(user.getId());
System.out.println("name:" + u.getName());System.out.println("----- 根据ID得到对象:演示load方法; -----");
u = getUserByLoad(user.getId());
// System.out.println("name:" + u.getName()); // 此处调用会报错。和懒加载有关系;且看后续讲解
System.out.println(u.getClass().getName());System.out.println("----- 此处演示对象的Hibernate三种状态[瞬时,持久,脱离]以及Hibernate的提交时的优化; -----");
addUserTest(user);
System.out.println("----- 根据ID得到对象:演示get方法; -----");}
/**
* Hibernate标准调用模板
* @param user
*/
static void addUser(User user) {
Session s = null;
Transaction tx = null;
try {
s = HibernateUtil.getSession();
tx = s.beginTransaction();
s.save(user);
tx.commit();
} catch (HibernateException e) { //catch部分可以省略。效果一致;
if (tx != null) {
tx.rollback();
}
throw e; //注意,此处必须抛出异常,而不能捕获异常却不处理!
} finally {
if (s != null) {
s.close();
}
}
}/**
* Hibernate简洁调用模板
* @param user
*/
static void addUser1(User user) {
Session s = null;
Transaction tx = null;
try {
s = HibernateUtil.getSession();
tx = s.beginTransaction();
s.save(user);
tx.commit();
} finally {
if (s != null) {
s.close();
}
}
}static void addUserTest(User user) {
Session s = null;
Transaction tx = null;
try {
s = HibernateUtil.getSession();
tx = s.beginTransaction();
s.save(user);System.out.println("----- 此时调用user.setName,但提交时不会输出对应Update语句; -----");
user.setName("new name"); // 此时的对象是持久对象,此处更新user会对数据库也做更新
System.out.println("----- 此时调用user.setBirthday,但提交时不会输出对应Update语句; -----");
user.setBirthday(new Date());
/**
* 此时又做了一条update,但在Hibernate并不会立即更新数据库。
* 而会做一些优化,比如合并这两条更新为一条update语句,在某个时间点做此更新。
* 所以在控制台可以看到只有一条update语句输出;
* 现在可以理解为提交的时候。后续会详细讲解具体提交的时间点;
*/
System.out.println("----- 此时调用tx.commit(),会输出所有优化后的SQL语句,包括一条更新了两个值的Update语句,而不是两条update语句; -----");
tx.commit();
} finally {
if (s != null) {
s.close();
}
}
}/**
* 根据ID得到对象:演示get方法;
* @param id
* @return
*/
static User getUser(int id) {
Session s = null;
try {
s = HibernateUtil.getSession();
Class userClass = User.class;
User user = (User) s.get(userClass, id);
return user;
} finally {
if (s != null) {
s.close();
}
}
}/**
* 根据ID得到对象:演示load方法;
* @param id
* @return
*/
static User getUserByLoad(int id) {
Session s = null;
try {
s = HibernateUtil.getSession();
Class userClass = User.class;
User user = (User) s.load(userClass, id);
System.out.println("----- ##User getUserByLoad(int id)## start -----");
System.out.println("name:" + user.getName());
System.out.println("----- ##User getUserByLoad(int id)## end -----");
return user;
} finally {
if (s != null) {
s.close();
}
}
}
}
//run:
//----- Hibernate标准调用模板演示 -----
//log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
//log4j:WARN Please initialize the log4j system properly.
//Hibernate: insert into User (name, birthday) values (?, ?)
//id:26
//----- 根据ID得到对象:演示get方法; -----
//Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.birthday as birthday0_0_ from User user0_ where user0_.id=?
//name:谷歌
//----- 根据ID得到对象:演示load方法; -----
//----- ##User getUserByLoad(int id)## start -----
//Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.birthday as birthday0_0_ from User user0_ where user0_.id=?
//name:谷歌
//----- ##User getUserByLoad(int id)## end -----
//cn.itcast.hibernate.domain.User$$EnhancerByCGLIB$$ddacf5c4
//----- 此处演示对象的Hibernate三种状态[瞬时,持久,脱离]以及Hibernate的提交时的优化; -----
//Hibernate: insert into User (name, birthday) values (?, ?)
//----- 此时调用user.setName,但提交时不会输出对应Update语句; -----
//----- 此时调用user.setBirthday,但提交时不会输出对应Update语句; -----
//----- 此时调用tx.commit(),会输出所有优化后的SQL语句,包括一条更新了两个值的Update语句,而不是两条update语句; -----
//Hibernate: update User set name=?, birthday=? where id=?
//----- 根据ID得到对象:演示get方法; -----
//成功生成(总时间:1 秒)