一、持久化对象的状态
1.瞬时对象(Transient Objects)
或临时对象,使用new操作符初始化的对象不是立刻就持久化的。它们的状态是瞬时的,也就是说它们没有任何跟数据库表相关联的行为,只要应用不再引用这些对象(不再被任何其它对象所引用),它们的状态将会丢失,并由垃圾回收机制回收。没有纳入Session的管理。2.持久化对象(Persistent Objects)
持久化实例是任何具有数据库标识的实例。它有持久化管理器Session统一管理,持久化实例是在事务中进行操作的-它们的状态在事务结束时同数据库集进行同步。当事务提交时,通过执行sql的insert、update和delete语句把内存中的状态同步到数据库中。纳入到Session的管理,在清零缓存(脏数据检查)的时候,会和数据库同步。3.离线对象(Detached Objects)
Session关闭后,持久化对象就变成离线对象。离线表示这个对象不能再与数据库保持同步,它们不再受Hibernate管理。在数据库中有与之匹配的数据(和瞬时对象的主要区别,如瞬时对象就不能进行如updata操作),但是没有纳入Session的管理。
示例:(工程hibernate_session
)
由于Session对象是一个重量级对象,所以我们采用单例模式:
HibernateUtils.java
package cn.itcast.util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
private static SessionFactory factory;
static{
try{
//读取配置文件
Configuration cfg = new Configuration().configure();
//初始化SessionFactory
factory = cfg.buildSessionFactory();
}catch(Exception e){
e.printStackTrace();
}
}
public static SessionFactory getSessionFactory(){
return factory;
}
public static Session getSession(){
//Session由工厂产生
return factory.openSession();
}
public static void closeSession(Session session){
if(session != null){
if(session.isOpen()){
session.close();
}
}
}
}
其他文件和上个例子基本一样,我们在这里新建一个数据库hibernate_session
,然后使用类ExportDB.java
自动生成数据库表。
测试:
SessionTest.java
package junit.test;
import java.util.Date;
import java.util.UUID;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import cn.itcast.model.User;
import cn.itcast.util.HibernateUtils;
public class SessionTest {
@Test
public void testSave1(){
Session session = null;
Transaction transaction = null;
User user = null;
try{
//得到Session
session = HibernateUtils.getSession();
//开启事务
transaction = session.beginTransaction();
//Transient状态(临时状态)
user = new User();
user.setId(UUID.randomUUID().toString());
user.setName("zhang");
user.setPassword("1111");
user.setCreateTime(new Date());
user.setExpireTime(new Date());
//persistent状态,当属性发生改变的时候,hibernate会自动和数据库同步
session.save(user);
user.setName("tom");
session.update(user);
transaction.commit();
}catch(Exception e){
e.printStackTrace();
transaction.rollback();
}finally{
HibernateUtils.closeSession(session);
}
//detached状态(离线状态)
user.setName("jack");
try{
session = HibernateUtils.getSession();
session.beginTransaction();
//persistent状态
session.update(user);
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
}
说明:可以看到当执行save方法之后对象变为了persistent状态,此时会发出insert语句,同时此时的状态下,如果我们修改对象,在提交事务的时候会清理缓存(或叫脏数据检查),会将新的对象存到数据库中,发出update语句。而当Session关闭之后,对象变成了离线状态,此时如果我们想修改数据库中对象的值,那么需要重新获取Session并开启事务,最后提交。
测试get方法:
@Test
public void testReadByGetMethod1(){
Session session = null;
try{
session = HibernateUtils.getSession();
session.beginTransaction();
//会立即发出查询语句,加载User对象,此时对象是persistent状态
User user = (User) session.get(User.class, "61bb68a4-5835-4825-8fa5-a93c41f2987f");
System.out.println("user.name = " + user.getName());
//persistent状态下改变对象会自动和数据库同步
user.setName("tom");
session.getTransaction().commit();
}catch(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
说明:其中get方法的第二个参数是上个测试例子中存入数据的id,试验可知,当使用get方法时会立即发出查询语句,对象称为persistent状态,此时改变对象会在事务提交的时候清理缓存,发出修改语句。但是,如果我们给出的id号在数据库中不存在,那么get方法返回null。
测试load方法:
@Test
public void testReadByLoadMethod1(){
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
//执行load方法时不会立即发出查询语句,而是在要使用此对象的时候才会发出,比如下面的打印语句
//因为load方法实现了lazy方法(懒加载或延迟加载)
User user = (User) session.load(User.class, "61bb68a4-5835-4825-8fa5-a93c41f2987f");
//执行下面这条语句的时候才会发出查询语句
System.out.println("user.name = " + user.getName());
user.setName("jack");
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
说明:这里要注意load方法和get方法的区别,load方法采用的是延迟加载,只有当要使用对象的时候才会去数据库中查询。同时如果我们给出的id号在数据库中不存在,则会抛出ObjectNotFoundException
异常。
测试update方法:
@Test
public void testUpdate1(){
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
//手动构造的detached对象
User user = new User();
user.setId("61bb68a4-5835-4825-8fa5-a93c41f2987f");
user.setName("德华");
user.setPassword("2222");
session.update(user);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
说明:手动构造detached状态对象时我们给出的id必须是数据库中存在的,不然会抛出异常。同时表明detached对象可以update。虽然这里的对象是我们new出来的,但是在数据库中是有与之对应的主键的,所以是detached状态对象。
测试delete方法:
@Test
public void testDelete1(){
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
User user = (User) session.load(User.class, "61bb68a4-5835-4825-8fa5-a93c41f2987f");
session.delete(user);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
//删除之后称为Transient状态
}
说明:这里我们可以看到从数据库中删除数据之后对象成为了Transient状态。本来对象是persistent状态,删除之后就变为Transient状态。
最后:
- get和load方法的区别是get不支持lazy,而load支持;采用get加载数据,如果没有与之匹配的数据返回null,而load则抛出异常。
- Transient状态的特征是:在数据库中没有与之匹配的数据,没有纳入Session的管理。
- detached的特征是:在数据库中有与之匹配的数据,也没有纳入Session的管理。
- get和load方法都只能根据主键进行查询,即单一查询。
二、Query接口入门
我们可以使用Query接口发送hql语句进行查询。
QueryTest.java
package junit.test;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.junit.Test;
import cn.itcast.model.User;
import cn.itcast.util.HibernateUtils;
public class QueryTest {
@Test
public void testQuery(){
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Query query = session.createQuery("from User");
//查询从哪里开始
query.setFirstResult(0);
//查询出多少条数据
query.setMaxResults(2);
//查询出的数据Query接口会自动帮我们存入到一个List集合中
List<User> list = query.list();
for(User user : list){
System.out.println(user.getId());
System.out.println(user.getName());
}
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally{
HibernateUtils.closeSession(session);
}
}
}
说明:这里我们可以使用hql语句将所有数据都查询出来,同时还可以进行分页,对于hql语句,它是针对对象的查询语句,所以对于对象名是区分大小写的。查询出来都 数据Query接口会自动帮我们存入到一个List集合中。在后面我们还会详细说明。