关闭

Hibernate之Session

标签: hibernatesession
143人阅读 评论(0) 收藏 举报
分类:
1.什么Session?
(1) Session接口是Hibernate向应用程序提供的操纵数据库的最主要的接口,它提供了基本的保存、更新、删除和加载Java对象的方法。
(2) 每一个Session对象都在内存中维护了一个缓存,位于缓存中的对象称为持久化对象,它和数据库表中的相关记录保持着一种对应关系。通过Session缓存,Hibernate最大限度的减少了应用程序访问数据库的次数,实现了对内存空间更加有效的利用。
(3) Hibernate把持久化类的对象分为4种状态:持久化状态、临时状态、游离状态、删除状态。Session的特定方法能使对象从一个状态转换到另一个状态。

2.session缓存:
(1) 获取缓存:每一次数据操作都需要获取一个session对象: 
     ① sessionFactory.openSession();//每一次都打开一个新的Session,自己管理,自己关闭
     ② sessionFactory.getCurrentSession();//在同一个线程中,多次调用,获取都是同一个Session,从当前线程ThreadLocal中获取的,框架管理,不要自己关闭。
     ③ Session对象本身含有一级缓存:
(2)一级缓存:
     ① 缓存初体验:
@Test
public void testCache(){
Book book = (Book)session.get(Book.class, 1);
System.out.println(book);
System.out.println("-------------------");
book = (Book)session.get(Book.class, 1);
System.out.println(book);
}
Hibernate:
    select
        book0_.BOOK_ID as BOOK_ID1_0_0_,
        book0_.BOOK_NAME as BOOK_NAM2_0_0_
    from
        T_BOOK book0_
    where
        book0_.BOOK_ID=?
Book [bookId=1, bookName=深入分析JavaWeb技术内幕]
-------------------
Book [bookId=1, bookName=深入分析JavaWeb技术内幕]
框架提供了一个Session 缓存,也称为一级缓存。
     作用:通过框架的方法查询数据时,不是立即查询数据库,而是先从缓存中查找数据,如果缓存中有就直接返回;如果缓存中没有,那么会立即发送查询语句,从数据库中加载数据,加载到数据后,会将数据存放到缓存中,给下次访问利用;这样,可以提高访问效率。减少了与数据库频繁交互。
     ② 如何操作缓存
         [1] flush():将缓存数据同步到数据库中
              什么时候会执行flush():执行commit()时会自动执行flush() 或 手动执行flush()
//执行HQL时会自动执行flush():
@Test
     public void testFlush3(){
          //验证执行HQL查询前需要执行flush()操作
          Book book = (Book)session.get(Book.class, 1);
          System.out.println(book);
          book.setBookName("西游记");
          book = (Book)session.createQuery("from Book b where b.bookId=1").uniqueResult();
     }
@Test
     public void testFlush2(){
          Book book = (Book)session.get(Book.class, 1);
          System.out.println(book);
          book.setBookName("深入分析JavaWeb技术内幕");
          session.flush();
     }
           [2] refresh():将数据库中最新数据加载到缓存中          
              将数据库的隔离级别设置为2,另一个事务提交后,当前事务就可以再次读取数据库中最新数据了,这样就可以避免脏读,不可重复读,幻读。
             具体的做法:在主配置文件(hibernate.cfg.xml)中设置如下属性:
<!-- 设置当前数据库事务隔离级别为读已提交 -->
 <property name="hibernate.connection.isolation">2</property>
    refresh(): 从数据库中重新加载最新数据到缓存中:
@Test
     public void testRefresh(){
           //测试Session的refresh()方法
          Book book = (Book) session.get(Book. class, 1);
          System. out.println(book);
           //从数据库中重新加载最新数据到缓存中。
          session.refresh(book);
          System. out.println(book);
     }
          [3] evict():清理缓存中某一个数据
          [4] clear():清理缓存中所有数据
@Test
     public void testClear(){
           //测试clear()
          Book book = (Book) session.get(Book. class, 1);
          System. out.println(book);
           //清理缓存中所有对象
           session.clear();
          //清理缓存中指定的对象
           //session.evict(book);
           //一般是需要重新从数据库中获取最新数据时,需要先清理缓存,再重新查询。
          book = (Book) session.get(Book. class, 1);
          System. out.println(book);
     }
3.POJO对象状态
     POJO对象是被Session缓存所管理的,它存在4种状态

     如何判断一个对象的状态,可以根据是否有OID,是否被缓存管理,是否在数据库中存在记录来进行判断:
(1) 临时状态:
     特点:也叫自由态,只存在于内存中,而在数据库中没有相应数据。用new创建的对象,它没有持久化,没有处于Session中,处于此状态的对象叫临时对象;
     是否存在OID: 一般情况情况下是不存在的,除非自己管理OID的值。
     是否被缓存管理:没有
     是否在数据库中存在:没有
     Book book = new Book(null,"Java核心技术");
(2) 持久化状态
     特点:与session关联并且在数据库中有相应数据。已经持久化,加入到了Session缓存中。如通过hibernate语句保存的对象。处于此状态的对象叫持久对象;
     是否存在OID: 一定存在OID
     是否被缓存管理:有
     是否在数据库中存在:有
     a. 经过save(book);数据库中一定会有一条记录与之对应。
(3) 游离状态
     特点:已经持久化,但不在Session缓存中。处于此状态的对象叫游离对象;
     是否存在OID: 一定有OID
     是否被缓存管理:没有
     是否在数据库中存在:有
     a. 当执行clear(),evict(),session.close()方法,对象由持久化状态变为游离状态。
(4) 删除状态
     特点:数据库的数据删除。
     是否存在OID: 有OID的,但是没有意义,因为数据库数据已经被删除了。主键没有了。对象还保留OID值,没意义。
     是否被缓存管理:没有
     是否在数据库中存在:没有

4.session核心方法:
(1) save()
     ① 将一个临时对象转换为持久化对象
     ② 对于OID:忽略临时对象中的“OID”值,save()方法会将数据库产生的新的OID的值赋值给持久化对象
     ③ 持久化状态的对象的OID的值是不允许修改的。
@Test
     public void test1(){
          Book book = new Book(null ,"设计模式" );
           //如果ID是自增的,保存之后,是不允许修改Id的。
           session.save(book);
     }
(2) persist()
     ① 作用和save()相同
     ② 不允许保存带有OID的对象,会抛异常:org.hibernate.PersistentObjectException
@Test
     public void test2(){
          Book book = new Book(null ,"设计模式" );
           session.persist(book);
     }
(3) get()
     ① 根据OID的值,从数据库中立即加载一个对象到内存中。
     ② 如果调用get()方法时,Session缓存中已经有了一个OID相同的对象,则get()方法会将缓存中的对象返回,不发送SQL语句。
     ③ 如果加载不到OID对象,那么返回null
@Test
     public void test3(){
          Book book = (Book) session.get(Book.class, 1);
          System. out.println(book);
     }
(4) load()
     ① 采用延迟检索策略,在调用load()方法时仅返回一个代理对象,不发送SQL语句,在真正用到非OID属性值时,才发送SQL语句进行查询。
     ② 懒加载初始化异常
      [1] 全类名:org.hibernate.LazyInitializationException
      [2] 产生原因:对一个延迟加载的代理对象进行初始化时,Session缓存中没有对应OID的对象,无法完成初始化。
@Test
     public void test4(){
          Book book = (Book) session.load(Book. class, 1);
          System. out.println(book);
     }
@Test
     public void test5(){
          Book book = (Book) session.load(Book.class, 1);
          tx.commit();
          session.close();
          Session openSession = sessionFactory.openSession();
          tx = openSession.beginTransaction();
          System. out.println(book.getBookName());
     }
(5) update()
     ① 根据游离对象或持久化对象对数据库表进行更新
     ② update()方法更新一个游离对象时,默认情况下无法获知当前游离对象中的数据和数据库表中的数据是否有差异。所以,无论是否有差异都会发送SQL语句。为了避免盲目的发updat语句,可以在hbm配置文件的class元素中设置select-before-update属性的值为true。通常不设置这个属性。
     ③ 使用update()方法更新一个OID不存在的对象会抛出异常:org.hibernate.StaleObjectStateException
     ④ 使用update()方法更新一个游离对象,但此时Session缓存中已经存在了OID相同的持久化对象,会抛出异常:org.hibernate.NonUniqueObjectException
@Test //更新临时状态
     public void test6(){
          Book book = new Book(1,"设计模式 " );
          session.update(book);
     }
@Test //更新持久化对象
     public void test7(){
          Book book = (Book) session.get(Book.class,1);
          book.setBookName( "设计模式 " );
          session.update(book);
     }
@Test  //会抛出一个异常
     public void test8(){
          Book book = (Book) session.get(Book.class,1);
          Book book1 = new Book(1,"设计模式");
          session.update(book1);
     }
(6) saveOrUpdate()
     ① 兼具保存和更新两种功能。传入临时对象执行保存,传入游离对象执行更新。
     ② 判断执行INSERT语句还是UPDATE语句的依据
         [1] 根据OID的值,如果为null则执行保存,否则执行更新
@Test
     public void test9(){
          Book book = new Book(1,"设计模式");
          session.saveOrUpdate(book);
          System. out.println(book);
     }
(7) delete()
     ① 执行删除操作
     ② 删除对象后将OID的值置空:在Hibernate配置文件中加入如下配置(在主配置文件中配置):
          <property name="hibernate.use_identifier_rollback" >true </property>
@Test
     public void test10(){
          Book book1 = (Book) session.get(Book.class,3);
          session.delete(book1);
          System.out.println(book1);
     }
(8) doWork()
     ① 用于在Hibernate环境下执行原生的JDBC代码
     ② 示例代码
@Test
public void testWork() {
     session.doWork(new Work() {
          @Override
          public void execute(Connection connection) throws SQLException {
          //使用传入的Connection对象实现原生的JDBC操作...
          }
     });
}
5.session管理
(1) 手动管理Session
          Session sesison = sessionFactory.openSession();
          session.close()
          每一次调用,都会重新创建一个新的Session,Session使用后必须自己手动进行关闭
(2) 框架管理Session
     Session session = sessionFactory.getCurrentSession();
     每一次调用,从当前线程ThreadLocal中获取,如果存在就直接返回使用。
     如果不存在,框架会创建一个Session,与当前线程进行绑定,然后返回使用。
     好处:在同一个线程中,多次调用这个方法,获取到的是同一个session.使用后不需要我们自己手动关闭,框架来关闭(事务提交后,不管成功与失败,都将session进行关闭)。
              每一个session需要基于一个特定的事务,如果不开始事务,那么就不开启session.一个事务对应一个sesison 
(3) 框架管理Session如何实现
     ① 需要进行一个属性配置:
<!-- 设置session的上下文:
     thead : 表示框架会在每一个线程中绑定Session对象,然后,可以通过getCurrentSession()方法获取Session对象。
-->
     <property name="hibernate.current_session_context_class">thread</property>
     ② 在测试类中:
package junit.test;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.Before;
import org.junit.Test;

public class TestSession {

     SessionFactory sessionFactory;

     @Before
     public void setUp() {
           Configuration cfg = new Configuration();
           cfg.configure();
           ServiceRegistryBuilder srb = new ServiceRegistryBuilder();
           srb.applySettings(cfg.getProperties());
           ServiceRegistry serviceRegistry = srb.buildServiceRegistry();
           sessionFactory = cfg.buildSessionFactory(serviceRegistry);

     }

     @Test
     public void testSession(){
           Session session = sessionFactory.openSession();
           Session session2 = sessionFactory.openSession();
           System.out.println(session == session2);
     }

     @Test
     public void testSession2(){
           //多个Dao操作数据库使用使用同一个session
           Session session = sessionFactory.getCurrentSession();
           Session session2 = sessionFactory.getCurrentSession();
           System.out.println(session == session2);
     }

}

0
0

猜你在找
【直播】机器学习&数据挖掘7周实训--韦玮
【套餐】系统集成项目管理工程师顺利通关--徐朋
【直播】3小时掌握Docker最佳实战-徐西宁
【套餐】机器学习系列套餐(算法+实战)--唐宇迪
【直播】计算机视觉原理及实战--屈教授
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之矩阵--黄博士
【套餐】微信订阅号+服务号Java版 v2.0--翟东平
【直播】机器学习之凸优化--马博士
【套餐】Javascript 设计模式实战--曾亮
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:7563次
    • 积分:662
    • 等级:
    • 排名:千里之外
    • 原创:58篇
    • 转载:2篇
    • 译文:0篇
    • 评论:3条
    最新评论