Hibernate3.2(四)生命周期示例、CRUD操作、Junit 3单元测试
抽时间 总结junit3和junit4的相关测试方法 ,junit4采用的是annotations
junit3 命名规范: 测试类 xxxTest 测试方法void testxxx() ,方法中可以用断言assertEquals(expected, actual).
测试类需要继承TestCase , 在工程中新建一个source folder,在其中建好包,包名最好和要测的类所在的包一样。
1.用Junit 3 编写一个测试类SessionTest来测试 & 探索Hibernate 三种对象的生命周期
熟悉hibernate的CRUD操作,主要方法有:get()、load()、save()、delete()、update()
package com.wyx.hibernate;
import java.util.Date;
import junit.framework.TestCase;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.wyx.hibernate.utils.HibernateUtils;
/**
* 使用junit做测试多个方法比较方便,junit中还有setup()和Deardown(),用来初始化和销毁
* setup()一般放的是
* @author bird
*/
public class SessionTest extends TestCase{
//public 无return
public void testHello(){
System.out.println("----------SessionTest.testHello()----------");
//throw new java.lang.RuntimeException();
//this.assertEquals("hello", "no hello");
}
public void testSession(){
Session session = HibernateUtils.getSession();
Transaction ts = session.beginTransaction();
User u = new User();
try {
//Transient状态
//uid不需要赋值,自动赋值
u.setName("李四");
u.setPassword("123");
u.setCreateTime(new Date());
u.setExpireTime(new Date());
session.save(u);//单步调试表明,在执行完save()后,uid的值才产生
System.out.println("---------mark-----------");
//save()后变成persistent状态
u.setName("王五");
//persistent状态的时候,不需要手动update,hibernate会自动和数据库同步
//session.update(u);
ts.commit();
} catch (HibernateException e) {
e.printStackTrace();
ts.rollback();
}finally{
HibernateUtils.closeSession(session);
}
//Detached状态
u.setName("张三");
try {
session = HibernateUtils.getSession();
session.beginTransaction();
session.update(u);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
ts.rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
}运行结果:
----------SessionTest.testHello()----------
---------mark-----------
Hibernate:insertintoUser(name,password,createTime,expireTime,id)values(?,?,?,?,?)
Hibernate:updateUsersetname=?,password=?,createTime=?,expireTime=?whereid=?
Hibernate: update User set name=?, password=?, createTime=?, expireTime=? where id=?运行结果表明,一个对象处于Persistent状态时,当属性发生改变的时候,Hibernate会自动和数据库同步,Hibernate只是把这些数据放在缓存中处理,而且是在commit()提交的时候才执行所有的数据库操作。
产生多条sql语句的原因是:hibernate在修改数据之前要先照一个快照,接下来修改了对象u.setName("王五"),在commit的时候,需要清理缓存(内从中的对象),脏数据是指没有提交的数据,commit()之前清理缓存的这个过程中要执行脏数据对比,脏数据对比的主要工作是处理哪些数据要发成insert,哪些数据要发成update语句。
当session关闭的时候,session已经不再管理u对象,u对象虽然变成了Detached状态,但是数据库中该条记录依然存在,当执行update的时候,数据库中u对应的那条记录name字段又变成了“张三”,update之后,该u对象又变成了Persistent状态的。
接着在SessionTest中写一个方法,运行:
public void testReadByGetMethod(){
Session session = HibernateUtils.getSession();
try {
session.beginTransaction();
//将数据库中对应id的那条记录取出来存在User对象中,此时立即产生sql语句
User u =(User)session.get(User.class, "402881fa2edaffe9012edaffea5c0001");
System.out.println("-------------mark----------------");
//修改u , persistent状态的时候,不需要手动update,hibernate会自动和数据库同步
u.setName("jeff");
session.getTransaction().commit();
} catch (HibernateException e) {
session.getTransaction().rollback();
e.printStackTrace();
}finally{
HibernateUtils.closeSession(session);
}
}运行结果:
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.password as password0_0_, user0_.createTime as createTime0_0_, user0_.expireTime as expireTime0_0_ from User user0_ where user0_.id=?
-------------mark----------------
Hibernate: update User set name=?, password=?, createTime=?, expireTime=? where id=?public void testReadByGetMethod1(){
Session session = HibernateUtils.getSession();
try {
session.beginTransaction();
User u =(User)session.get(User.class, "adfsafa");
session.getTransaction().commit();
} catch (HibernateException e) {
session.getTransaction().rollback();
e.printStackTrace();
}finally{
HibernateUtils.closeSession(session);
}
}运行结果:Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.password as password0_0_, user0_.createTime as createTime0_0_, user0_.expireTime as expireTime0_0_ from User user0_ where user0_.id=?调试跟踪表明,u对象值为null,但是单元测试没有报错,所以采用get()加载数据,如果数据中不存在相应的数据,返回null。
public void testReadByLoadMethod1(){
Session session = HibernateUtils.getSession();
try {
session.beginTransaction();
//不会发出查询sql,因为load方法实现了lazy()
//懒加载 or 延迟加载,真正使用这个对象的时候,才加载(发出sql语句)
//hibernate延迟加载实现原理是代理方式
User u =(User)session.load(User.class, "402881e62ed3df84012ed3df85510001");
System.out.println("----------mark------------");
System.out.println("u.name: " + u.getName());
session.getTransaction().commit();
} catch (HibernateException e) {
session.getTransaction().rollback();
e.printStackTrace();
}finally{
HibernateUtils.closeSession(session);
}
}运行结果:
----------mark------------
Hibernate:selectuser0_.idasid0_0_,user0_.nameasname0_0_,user0_.passwordaspassword0_0_,user0_.createTimeascreateTime0_0_,user0_.expireTimeasexpireTime0_0_fromUseruser0_whereuser0_.id=?
u.name: jeff代理类是使用CGLIB工具生成代理类,代理类继承了User。
public void testReadByLoadMethod2(){
Session session = HibernateUtils.getSession();
try {
session.beginTransaction();
//采用load加载数据,如果数据库中没有相应数据,
//那么抛出ObjectNotFoundException的异常
User u =(User)session.load(User.class, "adadfafdf");
System.out.println("----------mark------------");
System.out.println("u.name: " + u.getName());
session.getTransaction().commit();
} catch (HibernateException e) {
session.getTransaction().rollback();
e.printStackTrace();
}finally{
HibernateUtils.closeSession(session);
}
}运行结果:
----------mark------------
Hibernate:selectuser0_.idasid0_0_,user0_.nameasname0_0_,user0_.passwordaspassword0_0_,user0_.createTimeascreateTime0_0_,user0_.expireTimeasexpireTime0_0_fromUseruser0_whereuser0_.id=?
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.wyx.hibernate.User#adadfafdf]从上述get和load的测试方法可见:
1. get()不支持lazy, load()是支持lazy的(懒加载);
2. get()查询数据的时候,查不到返回null。而load()抛出org.hibernate.ObjectNotFoundException。注意,执行load方法的时候是不会报错的,在调用保存load的那个对象时才会抛出异常。
测试update():
public void testUpdate1(){
Session session = HibernateUtils.getSession();
try {
session.beginTransaction();
//虽然是我们自己new出来的,但是id在数据库中存在,所以这属于手动构造的 Detached 对象
User u = new User();
u.setId("402881e62ed40ec1012ed40ec2f10001");
u.setName("小明");
u.setPassword("123");
session.update(u);
session.getTransaction().commit();
} catch (HibernateException e) {
session.getTransaction().rollback();
e.printStackTrace();
}finally{
HibernateUtils.closeSession(session);
}
}测试结果:
Hibernate: update User set name=?, password=?, createTime=?, expireTime=? where id=?
虽然手动构造的Detached对象可以update到数据库,但是,万一有字段没setvalue就会更新空数据进DB,所以最好的做法还是操作一个从数据库get或load的对象,因为该对象已经填充了值。
测试Delete():
public void testDelete(){
Session session = HibernateUtils.getSession();
try {
session.beginTransaction();
User u = (User)session.load(User.class, "402881e62ed40ec1012ed40ec2f10001");
session.delete(u);
session.getTransaction().commit();
} catch (HibernateException e) {
session.getTransaction().rollback();
e.printStackTrace();
}finally{
HibernateUtils.closeSession(session);
}
}测试结果:
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_, user0_.password as password0_0_, user0_.createTime as createTime0_0_, user0_.expireTime as expireTime0_0_ from User user0_ where user0_.id=?Hibernate: delete from User where id=?
在删除一条记录的时候,操作的也是对象,所以把对象根据id用get或load获取到,然后session.delete(u);
小结:
transient状态的特征:
1. 在数据库中没有与之匹配的记录;
2. 没有纳入session的管理;
Persistent状态的特征:
1. 对象在数据库中有与之匹配的记录;
2. 纳入了session的管理;
3. 在清理缓存(脏数据检查)的时候,会和数据库同步(内存检查、清理缓存的目的是:看缓存发生有没有变化,从而判断到底发什么hql语句,eg:在save完了后,修改了对象,发了两条:一条insert一条update,这就是脏数据检查的好处);
Detached状态的特征:
1. 在数据库中有与之匹配的记录;
2. 没有纳入session的管理;
在实际应用中,我们经常需要根据表中的非id字段查询一个对象(一条记录),或者全部的数据,就要用到HQL。