Hibernate——Session方法

Session方法

操作Session缓存:

1.flush()

2.refresh()

3.clear()

flush():使session缓存数据和数据库中一致(可能会调用update)

1.在Transaction 的 commit() 方法中:先调用session的flush方法,在提交事务

2.flush() 方法会执行sql语句,但是不会提交事务

3.在未提交或是显式调用flush之外还有可能调用flush方法

         1)执行HQL或QBC查询,会先进行flush()操作,以得到最新数据(数据库中数据没变,但是Session中已经是最新数据了)

         2)若记录的ID是由底层数据库自增的方式生成的,则在调用save()方法时,就会立即发送insert,因为save方法后,必须保证对象ID是存在的

refresh():会强制发送select语句,即使session缓存数据一致

  注意:数据库的隔离级别会导致数据库即使改变,但数据还是不变

Mysql的默认隔离级别是可重复读,修改其为读已提交,就可以改变

1:读操作未提交(Read Uncommitted)
2:读操作已提交(Read Committed)
4:可重读(Repeatable Read)
8:可串行化(Serializable)

   <property name="connection.isolation">2</property>

 

Clear() :会清理缓存

 可以用以下测试:清除之后会再次发送select语句以获取:

    @Test
    public void testSession(){
        News news=(News)session.get(News.class,1);
        session.clear();
        News news1=(News)session.get(News.class,1);
    }

 

————————————————————————————————

Session核心方法:

  四种持久化状态

   1.持久化状态   存在于Session和数据库种

   2.临时状态      Session和数据库种都不存在

   3.游离状态      只存在于数据库中

   4.删除状态      Session和数据库种都不存在(不该再被使用)

 

Save()——完成Insert操作

  1.使一个临时对象变为持久化对象

  2.为对象分配ID

  3.在flush缓存时会发送insert语句

  4.在save方法之前的setID是无效的

  5.ID是不可改变的

Persist()——完成Insert操作

  和Save区别:

  1.在执行persist()之前已经如果有ID了,则不会进行Insert,并且抛出异常

get(),Load()——根据OID从数据库加载一个对象

区别:

1.执行get方法会立即执行select ; 执行load方法不会立即查询,而返回一个代理对象

2.执行get方法如果没有记录,则会返回null  ;  执行load 如果没有记录,当使用此记录时则出现异常

3.load方法可能会抛出懒加载(LazyInitializationException)异常,因为在需要初始化代理对象之前就已经关闭了Session.

Update()——完成update操作

update方法使一个游离对象(不在Session中)转变为持久化对象,并执行一条update语句

1.若更新一个持久化对象不需要显式的执行update方法,因为在执行commit方法时,会先执行Session的flush方法

2.更新游离对象才需要显式的调用update方法

3.游离对象执行update方法即使对象没有改变,都会发送update语句,持久化对象只有发生改变才会发送语句

4.通过设置select-before-update=true(默认为false) 用于在执行update前先select看是否需要更新

5.update 更新数据库中没有的对象会出异常

6.更新Session中已经存在的OID的对象,会抛出异常,因为Session中不能有二个OID的对象

<class name="com.chenx.hibernate.helloworld.News" table="tb_news" select-before-update="true">

SaveOrUpdate() ——执行Insert或Update

1.若OID不为空,但数据表中没对应的记录,会抛异常

2.OID值等于ID的unsaved-value 属性值的对象,

<id name="id" type="java.lang.Integer" unsaved-value="20">

delete()——执行删除操作

  执行删除操作,只要OID和数据表记录一致,就执行

  1.无论是持久化对象还是游离对象,只要OID一样

  2.删除不存在的记录会抛异常,可以配置使删除之后把持久化对象和游离对象变为临时对象(id置为null):

<property name="use_identifier_rollback">true</property>

Evict()——从session缓存中把指定的持久化对象移除

把session缓存中此对象删除,就会使其变为游离对象,即使set变化后,flush也不会更新,因为没有此对象,无需同步。

    @Test
    public void testSession(){
        News news=session.get(News.class,1);
        news.setAuthor("tt");
        session.evict(news);

    }

 

Session 一级缓存,二级缓存:

一级缓存:

是session级别的缓存,它是属于事务范围内的缓存,这一级别的缓存是由hibernate管理的

根据如下测试可以看出其特点:

    @Test
    public void testSession(){
        Employee employee=session.get(Employee.class,3);
        System.out.println(employee.getName());

 
        Employee employee1=session.get(Employee.class,3);
        System.out.println(employee1.getName());

    }

可以看到执行了二次查询,查询的是同一个employee,但是只发送了一句select语句,因为在用一个事务中,查询第一次的时候把结果存入了session中,第二次查询的时候先从session中查找是否有此对象,有的话就不发送select语句了

先在其中提交事务,并开启一个新的事务,观察其是否执行二次select语句,关闭session后会清空其缓存:

    @Test
    public void testSession(){
        Employee employee=session.get(Employee.class,3);
        System.out.println(employee.getName());
        transaction.commit();
        session.close();
        session=sessionFactory.openSession();
        transaction=session.beginTransaction();
        Employee employee1=session.get(Employee.class,3);
        System.out.println(employee.getName());
    }

二级缓存:

二级缓存是SessionFactory级别的缓存,它是属于进程范围的缓存

在此我们将使用Ehcache:

-> Ehcache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认CacheProvider。Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP api等特点。

-> 要使用Ehcache,首先需要加入三个jar包:

ehcache-core-2.4.3.jar

hibernate-ehcache-4.3.11.Final.jar

slf4j-api-1.6.1.jar

->接着配置二级缓存:

    <property name="cache.use_second_level_cache">true</property>
    <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>

还需要配置其作用在哪些类上:

①配置在cfg.xml中:<class-cache class="com.chenx.hibernate.HQL.Employee" usage="read-only"></class-cache>

②配置在hbm.xml中:<cache usage="read-write"></cache>

->最后还需加入ehcache的xml配置文件

集合级别的二级缓存配置:

我们在department中有一个集合的属性,一个Employee的集合,现要达到获取集合存入sessionfactory,达到同样效果

配置需要注意:不但要把集合属性对应的配置缓存,还需要配置此类的二级缓存:

    <class-cache class="com.chenx.hibernate.HQL.Department" usage="read-write"></class-cache>
    <collection-cache collection="com.chenx.hibernate.HQL.Department.employeeSet" usage="read-write"></collection-cache>
    <class-cache class="com.chenx.hibernate.HQL.Employee" usage="read-write"></class-cache>

如果只配置了集合,没有配置其类的话,反而会更加麻烦,因为配置了集合就会把employee的id存下来,但是没有存储其别的参数,当再次查询的时候,要初始化employee,原本可以统一的初始化,现在因为有每个ID,要一个一个的select获取

同样也可以在hbm.xml中配置:

        <set name="employeeSet" table="tb_employee" >
            <cache usage="read-write"></cache>
            <key column="DepartmentID"></key>
            <one-to-many class="com.chenx.hibernate.HQL.Employee"></one-to-many>
        </set>

ehcache.xml 配置文件解析:

<?xml version="1.0" encoding="UTF-8"?><ehcache
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
        updateCheck="false">

    <diskStore path="C:\\Users\\chenx\\Desktop\\yy"/>

    <defaultCache
            maxElementsInMemory="20000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
    />
    <cache name="com.chenx.hibernate.HQL.Department.employeeSet"
           maxElementsInMemory="1"
           eternal="true"
           overflowToDisk="true"
           diskPersistent="false"
           timeToLiveSeconds="0"
           diskExpiryThreadIntervalSeconds="120"
    />
</ehcache>

.........

通过设置配置,使HQL和SQL查询也可使用:(查询缓存依赖于二级缓存)

    <property name="cache.use_query_cache">true</property>

 还需在使用时调用setCacheable(true);

    @Test
    public void testSession(){
        
        String hql="from Employee";
        org.hibernate.Query query= session.createQuery(hql);
        query.setCacheable(true);
        List<Employee> list=query.list();
        System.out.println(list.size());

        list=query.list();
        System.out.println(list.size());
        
    }

时间戳缓存:

    @Test
    public void testSession(){

        String hql="from Employee";
        org.hibernate.Query query= session.createQuery(hql);
        query.setCacheable(true);
        List<Employee> list=query.list();
        System.out.println(list.size());
        
        
        Employee employee=(Employee) session.get(Employee.class,4);
        employee.setSalary(11);
        
        list=query.list();
        System.out.println(list.size());

    }

如上测试,会发送三个语句,因为中间执行了更新,Ehcache会在存储更新或删除操作的时间戳,根据此来判断缓存数据的值是否过期,再执行操作

Query接口的iterate() 方法:

从上得知我们使用HQL语句可以用查询缓存对其优化,现在同样使用HQL,SQL语句,使用query的iterate():

    @Test
    public void testSession(){

        Department department=(Department) session.get(Department.class,10);
        System.out.println(department.getEmployeeSet().size());

        Query query=session.createQuery("from Employee e where e.department.id=10");
        Iterator<Employee> employees=query.iterate();
        while ((employees.hasNext())){
            System.out.println(employees.next().getName());
        }

   
    }

测试看出,iterate没有额外发送语句,而是从缓存中直接获取到了数据,但是经过测试发现,如果缓存中没有数据,他则根据返回的id一个一个再次从表中获取完整数据,所以iterate有时可以优化,有时候反而更差

发布了73 篇原创文章 · 获赞 14 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/daguniang123/article/details/93907200