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。

相关推荐