因为SessionFactory是一个重量级对象,最好是只创建一次,所以,将SessionFactory做一个封装,先建立一个工具类把它封装起来.工具类名称设置为HibernateUtils
package net.knight.hibernate.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
/**
* 从hibernate.cfg.xml获取配置文件
* getSessionFactory():获得Session工厂
* getSession():从SessionFactory获得Session
* getTransaction():从Session中获得Transaction
* closeSession():关闭Session
*/
public class HibernateUtils {
private static SessionFactory factory;
/**
* 建立一个static块可以写多条语句.
*/
static {
try {
Configuration cfg = new Configuration().configure();
factory = cfg.buildSessionFactory();
} catch (Exception e) {
e.printStackTrace();
}
}
public static SessionFactory getSessionFactory() {
return factory;
}
public static Session getSession() {
return factory.openSession();
}
public static Transaction getTransaction(Session session) {
return session.beginTransaction();
}
public static void closeSession(Session session) {
if(session != null) {
if(session.isOpen()){
session.close();
}
}
}
}
第一课中是使用的Client类来测试Hibernate_first项目,考虑到如果要测试多个类的时候测试不方便,这个改用junit单元测试工具来测试,也可以学习一下junit的使用方法.步骤如下
1.因为测试类最终发布的时候不会打包,所以把这个测试包文件放在项目外面是一个比较明智的选择.也便于管理.首先在项目中建立一个源码目录,目录名称我建立成test.这个目录和src目录平级.
2.在目录中建立测试类路径,我这里设置的类路径和src中的一致.是否一致都可以,没有什么要求.
3.建立测试类,因为是测试Session,所以建立成SessionTest
package net.knight.hibernate.test;
import junit.framework.TestCase;
/**
* junit单元测试,主要对方法进行测试
* 1.继承TestCase方法
* 2.方法名称要以test开头
* 3.测试方法不能含有参数和返回值
*/
public class SessionTest extends TestCase {
// 公共信息初始化可以放到这个方法里.
@Override
protected void setUp() throws Exception {
super.setUp();
}
public void testHello() {
System.out.println("==========SessionTest.testHello===========");
// 断言的使用方法,前面的参数是预期值,后面的参数是实际值,如果预期值不等于实际值就失败了.
this.assertEquals("", "");
}
// 需要销毁的信息放到这里,类似于C中间的析构函数.
@Override
protected void tearDown() throws Exception {
super.tearDown();
}
}
Session有三种状态
1.Transient,new一个对象的时候就是Transient对象,最显著的特点就是在数据库中还没有与之对应的记录.还没有纳入到Session的管理,随时可以被垃圾回收器回收.
2.Persistent,当Transient对象调用save()方法后就成了Persistent对象,这个对象在数据库中是有与之对应的记录的.它纳入的Session的管理,这个对象是不能被垃圾回收器回收的.
3.Detached,当Persistent对象调用了close()等方法的时候就是Detached对象,调用close()方法后,这个对象只是从缓存里被清除掉了,数据库中的记录是不会被清除的.所以这个对象也没有纳入到Session的管理,但是数据库中是有与之对应的记录的,这个对象也随时可以被垃圾回收处理掉.因为没有任何对象引用它了.
4.因为数据库中有与之对应的记录,所以可以调用update()等方法,当Detached对象调用该类方法时,这个对象又变成了Persistent对象了.当Persistent对象再调用delete()方法时这个对象又变成Transient对象了.
Transient--save()-->Persistent--close()-->Detached--update()-->Persistent--delete()-->Transient
package net.knight.hibernate.test;
import java.util.Date;
import net.knight.hibernate.User;
import net.knight.hibernate.utils.HibernateUtils;
import org.hibernate.Session;
import org.hibernate.Transaction;
import junit.framework.TestCase;
/**
* junit单元测试
* 1.继承TestCase方法
* 2.方法名称要以test开头
*
*/
public class SessionTest extends TestCase {
public void testSession() {
Session session = null;
Transaction ts = null;
User user = null;
try {
session = HibernateUtils.getSession();
ts = HibernateUtils.getTransaction(session);
// Transient状态
user = new User();
user.setName("李四");
user.setPassword("123");
user.setCreateTime(new Date());
user.setExpireTime(new Date());
// Persistent状态.当属性发生改变的时候,hibernate会自动同步数据库
// 生成并执行insert into,此时的数据在缓存中,只是一个快照.
session.save(user);
// 修改user对象后,发生脏数据对比,对数据进行修改
// 生成并执行update,存入数据库.清理缓存
user.setName("王五");
ts.commit();
} catch (RuntimeException e) {
e.printStackTrace();
ts.rollback();
} finally {
HibernateUtils.closeSession(session);
}
// 再修改username,此时就是Detached状态
user.setName("赵六");
try {
// 因为Session已经关闭,则需要重新获取
session = HibernateUtils.getSession();
ts = HibernateUtils.getTransaction(session);
// 获取到session后又转换成Persistent
session.update(user);
ts.commit();
}catch(Exception e) {
e.printStackTrace();
ts.rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
}