hibernate的缓存问题

又到了写总结的时候了,今天来扒拉扒拉hibernate的缓存问题,顺便做了几个小测试,算是学习加上复习吧,下面开始。

1.综述

  首先为什么要有缓存这项技术,详细原因呢我也不知道,唯一知道的一点就是web应用在和数据库打交道时,查询数据库的次数越少越好,可能说的也不太准确吧,什么意思呢,就是尽量减少查询数据库的次数,但是有时候一样的数据我们又需要查询很多次,怎么办呢?这时候就是缓存大展身手的时候了,可以把查询的数据先缓存下来,需要的时候从缓存里面来拿,如果缓存里面没有需要的数据再从数据库去查,这样就可以减少查询数据库的次数,提高应用的查询速度的同时减轻数据库的压力。

2.hibernate缓存

  hibernate的缓存机制大概可以分为一级缓存和二级缓存,有时候还会用到查询缓存,一级缓存是默认开启的,一级缓存是session共享的,因此可以叫做session缓存或者叫做事务缓存,save,update,saveOrUpdate,load,get,list,iterate这些方法都会把对象放在一级缓存中,但是一级缓存不能控制缓存的数量,所以在操作大批量数据时有可能导致内存溢出,可以使用clear,evict方法来清空一级缓存,一级缓存依赖于session,session的生命周期结束了,一级缓存也会跟着结束。

  hibernate的二级缓存是可插拔的,要启用二级缓存需要第三方支持,hibernate内置了对EhCache,OSCache,TreeCache,SwarmCache的支持,可以通过实现CacheProvider和Cache接口加入。

session的save(不适合native方式生成的主键),update,saveOrUpdate,list,iterator,get,load,以及Query, Criteria都会填充二级缓存,但查询缓存时,只有Session的iterator,get,load会从二级缓存中取数据。Query,Criteria由于命中率较低,所以hibernate缺省是关闭的。Query查询命中低的一方面原因就是条件很难保证一致,且数据量大,无法保证数据的真实性。

  hibernate的二级缓存是sessionFactory级别,也就是跨session的,由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此Hibernate二级缓存是进程范围或者集群范围的缓存,有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。

(上述两段引自:http://www.cnblogs.com/shiyangxt/archive/2008/12/30/1365407.html,我自己可能说的没有那么清晰,所以就引用一下大神们的话)

  

3.ehcache实现hibernate二级缓存

  ehcache是用的比较多的一个二级缓存框架,当然还有OSCache等很多二级缓存框架,我暂时就会用ehcache,所以就用ehcache做了个demo,下面详细说一下:

3.1 新建项目

  新建一个java项目,当然建web项目也可以,只是用不到页面而已,测试都是在junit中进行的。给项目添加hibernate支持,然后添加eacache的jar包,因为要和数据库打交道,数据库驱动包也是少不了的,junit的包也是需要的,下面是项目结构截图:

  

  hibernate的版本是4.1版本,环境是myeclipse10.7,jdk是1.7版本,其他的就没有什么了,需要的两个配置文件分别是hibernate的配置文件和ehcache的配置文件,实体类使用了注解的方式。

3.2 配置二级缓存

  如果要使用二级缓存,需要先配置二级缓存,首先在hibernate的配置文件中配置如下信息:

<!-- 开启二级缓存 -->
        <property name="hibernate.cache.use_second_level_cache">true</property>
        <!-- 二级缓存提供类 -->
        <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
        <!-- 二级缓存配置文件位置 -->
        <property name="hibernate.cache.provider_configuration_file_resource_path">ehcache.xml</property>

关于二级缓存的提供类还有另外一种写法,<property name="hibernate.cache.provider_class"> org.hibernate.cache.EhCacheProvider </property>,这种方式是hibernate3的版本使用的,hibernate4版本不推荐使用,但是如果使用的是hibernate3版本的话也可以使用这个。

  开启二级缓存并且加入二级缓存提供类之后就需要ehcache的配置文件了,配置文件详细如下:

<diskStore path="java.io.tmpdir"/>
    <defaultCache
            maxElementsInMemory="10000"
            eternal="true"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="true"
            diskExpiryThreadIntervalSeconds="120"
            />

  diskStore中的path路径可以设置为硬盘路径,也可以使用如上的设置方式,表示默认存储路径。

  defaultCache为默认的缓存设置,maxElementsInMemory : 在內存中最大緩存的对象数量。

                  eternal : 缓存的对象是否永远不变。

                   timeToIdleSeconds :可以操作对象的时间。

                  timeToLiveSeconds :缓存中对象的生命周期,时间到后查询数据会从数据库中读取。

                  overflowToDisk :内存满了,是否要缓存到硬盘。

其他的属性可以在ehcache的core包中的chcache-failsafe.xml文件中找到,我就不一一列举出来了。

  上面的配置是默人配置,如果不指定缓存的对象,那么所有的二级缓存都是使用的默认配置,如果设置了缓存对象,那么则使用置顶的缓存对象配置,置顶缓存对象中没有配置的信息继承默认配置的。

 <cache
    name="modal.User"
    maxElementsInMemory="200" eternal="false"
    timeToIdleSeconds="50"
    timeToLiveSeconds="60"
    overflowToDisk="true"
    />

  上面的就是指定缓存对象的配置,注意name中要把类的包名带上。

上面的工作做完之后就是开启二级缓存了,如果是注解形式的,那么使用如下的方式开启:

@Entity
@Table(name="t_class")
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY)
@Cacheable
public class User {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    private String name;

  可以设置二级缓存的类型,READ_ONLY表示只读,二级缓存一般设置为只读形式的,因为效率最高,READ_WRITE表示读写,效率低但是可以保证并发正确,nonstrict-read-write:非严格的读写,效率较高,不用加锁,不能保证并发正确性。例如帖子浏览量。transactional:事务性缓存,可回滚缓存数据,一般缓存框架不带有此功能,实现很复杂。

  如果是hbm.xml形式的,那么使用如下的方式开启:

    <cache usage="read-only"/>

3.3 测试

  配置完成了我们来做下测试:

先看下数据库数据,数据库就三条数据:

3.3.1

先做第一个测试,在两个session中加载一条数据,观察控制台的sql语句:

@Test
    public void test() {
        Session session = null;
        try {
            session = HibernateSessionFactory.getSession();
            User u1 = (User)session.load(User.class, 1);
            System.out.println("------------"+u1.getName());
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

        try {
            session = HibernateSessionFactory.getSession();
            User u1 = (User)session.load(User.class, 1);
            System.out.println(u1.getName()+"--------");
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

    }

sql语句:

Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_ from t_class user0_ where user0_.id=?
------------301
301--------

  通过上面的代码和sql语句以及结果可以看到,在一个sessionFactory的两个session中查询一条记录时,只发出了一条sql语句,说明此时二级缓存是好使的。

下面看一个报错的情况:

@Test
    public void test() {
        Session session = null;
        try {
            session = HibernateSessionFactory.getSession();
            User u1 = (User)session.load(User.class, 1);
            System.out.println("------------"+u1.getName());
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

        try {
            session = HibernateSessionFactory.getSession();
            User u1 = (User)session.load(User.class, 1);
            System.out.println(u1.getName()+"--------");

            session.beginTransaction();
            u1.setName("222");
            session.beginTransaction().commit();
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

    }

  看控制台:

  这时候控制台报错了,什么情况呢?因为我们前面设置的二级缓存类型为只读类型,但是我们这里却修改了查询出来的数据,这是不允许的,所以报错了。

3.3.2

  上面是查询一个对象 ,但是有时候我们查询的并不是对象,而是使用HQL查询对象中的一个或者几个属性,这时候二级缓存好使吗?拭目以待吧:

@Test
    public void testQueryHql2() {
        Session session = null;

        try {
            session = HibernateSessionFactory.getSession();
            List<User> list = session.createQuery("from User u where u.name like ? ").setParameter(0, "%"+3+"%").list();
            System.out.println("---------------"+list.size());
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

        try {
            session = HibernateSessionFactory.getSession();
            List<User> list = session.createQuery("from User user where user.name like ?").setParameter(0, "%"+1+"%").list();
            System.out.println(list.size()+"---------------");
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

    }

  上面是测试代码,HQL语句是一样的,只是参数不一样,测试一下结果如下:

Hibernate: select user0_.id as id0_, user0_.name as name0_ from t_class user0_ where user0_.name like ?
---------------3
Hibernate: select user0_.id as id0_, user0_.name as name0_ from t_class user0_ where user0_.name like ?
1---------------

  可以看到,发出了两条sql语句,说明二级缓存没有起作用,那么当参数一样的时候二级缓存能起作用吗?看测试代码:

@Test
    public void testQueryHql2() {
        Session session = null;

        try {
            session = HibernateSessionFactory.getSession();
            List<User> list = session.createQuery("from User u where u.name like ? ").setParameter(0, "%"+3+"%").list();
            System.out.println("---------------"+list.size());
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

        try {
            session = HibernateSessionFactory.getSession();
            List<User> list = session.createQuery("from User user where user.name like ?").setParameter(0, "%"+3+"%").list();
            System.out.println(list.size()+"---------------");
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

    }

直接上结果:

Hibernate: select user0_.id as id0_, user0_.name as name0_ from t_class user0_ where user0_.name like ?
---------------3
Hibernate: select user0_.id as id0_, user0_.name as name0_ from t_class user0_ where user0_.name like ?
3---------------

  可以看到即使条件一样也是发出了两条sql语句,此时二级缓存也没有起作用。

结论:通过上面两个测试,我们可以知道二级缓存缓存的仅仅是对象,对于属性是不会进行缓存的。

  再来个测试,如果要查询的属性在实体类中的构造方法中呢,此时能不能进行缓存呢?看测试:

public class User {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    private String name;

    public User() {

    }
    public User(String name) {
        super();
        this.name = name;
    }

  将User添加两个构造方法之后发现还是发出两条sql语句,说明添加构造方法也不能进行二级缓存。

3.3.3

  关于上面的hql查询属性不能进行二级缓存的问题,有人说我就要进行二级缓存怎么办呢?其实还是有办法的,什么办法呢?查询缓存,此时需要再配置一些东西:

 首先是hibernate的配置文件:

<!-- 启用查询缓存 -->
        <property name="hibernate.cache.use_query_cache">true</property>

然后再查询的实体类上加上@Cacheable注解即可,下面测试重新配置之后的代码:

@Test
    public void testQueryHql2() {
        Session session = null;

        try {
            session = HibernateSessionFactory.getSession();
            List<User> list = session.createQuery("from User u where u.name like ? ").setCacheable(true).setParameter(0, "%"+3+"%").list();
            System.out.println("---------------"+list.size());
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

        try {
            session = HibernateSessionFactory.getSession();
            List<User> list = session.createQuery("from User user where user.name like ?").setCacheable(true).setParameter(0, "%"+3+"%").list();
            System.out.println(list.size()+"---------------");
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

    }

  还是这段代码,测试结果如下:

Hibernate: select user0_.id as id0_, user0_.name as name0_ from t_class user0_ where user0_.name like ?
---------------3
3---------------

  可以看到此时只有一条sql语句发出。

如果两次查询条件不一样呢?看测试:

@Test
    public void testQueryHql2() {
        Session session = null;

        try {
            session = HibernateSessionFactory.getSession();
            List<User> list = session.createQuery("from User u where u.name like ? ").setCacheable(true).setParameter(0, "%"+3+"%").list();
            System.out.println("---------------"+list.size());
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

        try {
            session = HibernateSessionFactory.getSession();
            List<User> list = session.createQuery("from User user where user.name like ?").setCacheable(true).setParameter(0, "%"+1+"%").list();
            System.out.println(list.size()+"---------------");
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

    }

测试结果:

Hibernate: select user0_.id as id0_, user0_.name as name0_ from t_class user0_ where user0_.name like ?
---------------3
Hibernate: select user0_.id as id0_, user0_.name as name0_ from t_class user0_ where user0_.name like ?
1---------------

  发出两条sql语句。

结论:通过上面的两个测试我们得出如下结论,第一,在没有配置查询缓存的情况下,二级缓存不会对hql进行的属性查询进行缓存,只会对查询出的对象进行缓存;第二,已经配置查询缓存的情况下,二级缓存只会缓存HQL语句和传入参数一模一样的查询结果进行缓存,如果不一样则不进行缓存。

3.3.4

  写到这突然想到一个问题,上面的3.3.3的结论有点问题,但是不想改上面的了,就在这补充一下,并不是说只有在查询属性的时候二级缓存才不会缓存数据,而是说在使用hql的时候,及时查询出来的是对象,二级缓存也只会对对象进行缓存,但是对于hql语句是不会缓存的,如果要想缓存,那么久需要开启查询缓存,方法已经给出了,下面补充一个测试,我先把查询缓存给注掉,然后看测试:

@Test
    public void testQueryHql() {
        Session session = null;

        try {
            session = HibernateSessionFactory.getSession();
            List<User> list = session.createQuery("from User").list();
            System.out.println("---------------"+list.size());
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

        try {
            session = HibernateSessionFactory.getSession();
            List<User> list = session.createQuery("from User").list();
            System.out.println(list.size()+"---------------");
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

    }

  看此时的查询结果:

Hibernate: select user0_.id as id0_, user0_.name as name0_ from t_class user0_
---------------3
Hibernate: select user0_.id as id0_, user0_.name as name0_ from t_class user0_
3---------------

可以看到此时查询的并不是属性,并且两条hql语句也一样,查询时还是发出了两条sql语句,此时再开启查询缓存,看下结果,两次代码是基本一样的,开启查询缓存后只需要加上.setCacheable(true)即可,直接给结果:

Hibernate: select user0_.id as id0_, user0_.name as name0_ from t_class user0_
---------------3
3---------------

查询结果是只发出了一条sql语句,跟上面的结论符合。

4、N+1问题

4.1

  首先,什么是N+1问题,N+1问题是执行条件查询时,在第一次查询时iterate方法会执行满足条件的查询结果数再加一次(n+1)的查询,但是此问题只存在于第一次查询时,在后面执行相同查询时性能会得到极大的改善。

  我们先举个例子来说明什么是N+1问题:

@Test
    public void iteraTest(){
        Session session = null;
        try {
            session = HibernateSessionFactory.getSession();
            Iterator<User> it = session.createQuery("from User").iterate();
             for (; it.hasNext();)
                {
                 User u = (User) it.next();
                    System.out.println(u.getName());
                }

        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }
    }
    

上面代码的sql语句如下:

Hibernate: select user0_.id as col_0_0_ from t_class user0_
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_ from t_class user0_ where user0_.id=?
301
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_ from t_class user0_ where user0_.id=?
302
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_ from t_class user0_ where user0_.id=?
303

上面的sql语句可以看到,先查询出全部数据的id,再根据id查询其他数据,有N条数据就发出几条sql,再加上查询全部id的一条sql语句,总共就发出了N+1条sql语句。

  其实N+1问题也是很容易解决的,只需要使用list()的方式查询就行了,如下所示:

        try {
            session = HibernateSessionFactory.getSession();
            List<User> list = session.createQuery("from User").list();

        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }
        

  这也是我们平常经常用的一个方式,这样就不会出现N+1问题了,使用二级缓存也可以解决N+1问题,怎么办呢?如下所示:

@Test
    public  void N1Test(){
        Session session = null;

        try {
            session = HibernateSessionFactory.getSession();
            List<User> list = session.createQuery("from User").list();

        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

         /*
         * 由于user的对象已经缓存在二级缓存中了,此时再使用iterate来获取对象的时候,首先会通过一条
         * 取id的语句,然后在获取对象时去二级缓存中,如果发现就不会再发SQL,这样也就解决了N+1问题
         * 而且内存占用也不多
         */

        try {
            session = HibernateSessionFactory.getSession();
            Iterator<User> it = session.createQuery("from User").iterate();
             for (; it.hasNext();)
                {
                 User u = (User) it.next();
                    System.out.println("it---"+u.getName());
                }

        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

    }

  测试结果:

Hibernate: select user0_.id as id0_, user0_.name as name0_ from t_class user0_
Hibernate: select user0_.id as col_0_0_ from t_class user0_
it---301
it---302
it---303

  可以看到就发出了两条语句,并没有出现N+1的情况。

4.2

  查询缓存也是会引起N+1问题的,我们先去掉User对象上的@Cache(usage=CacheConcurrencyStrategy.READ_ONLY)注解,然后看测试代码:

@Test
    public void testQueryHql3() {
        Session session = null;

        try {
            session = HibernateSessionFactory.getSession();
            List<User> list = session.createQuery("from User u where u.name like ? ").setCacheable(true).setParameter(0, "%"+3+"%").list();
            System.out.println("---------------"+list.size());
            for(User u :list){
                System.out.println(u.getName());
            }
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

        try {
            session = HibernateSessionFactory.getSession();
            List<User> list = session.createQuery("from User user where user.name like ?").setCacheable(true).setParameter(0, "%"+3+"%").list();
            System.out.println(list.size()+"---------------");
            for(User u :list){
                System.out.println(u.getName());
            }
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

    }

测试结果:

Hibernate: select user0_.id as id0_, user0_.name as name0_ from t_class user0_ where user0_.name like ?
---------------3
301
302
303
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_ from t_class user0_ where user0_.id=?
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_ from t_class user0_ where user0_.id=?
Hibernate: select user0_.id as id0_0_, user0_.name as name0_0_ from t_class user0_ where user0_.id=?
3---------------
301
302
303

  可以看到,在去掉二级缓存之后,进行查询缓存时又出现了N+1问题,这是由于查询缓存缓存的是id,虽然此时缓存中已经存在了这样一组数据,但是只有id,那么需要user的其他属性时候就需要根据id去查,这也是导致N+1问题的一个原因。所以在使用查询缓存的时候还是必须开启二级缓存的。

  

5.read-write

  前面一直是使用read-only测试的,下面来一个read-write测试的,read-write表示可以更改,更改之后就需要重新就行查询了,二级缓存是不好使的,下面上测试:

首先把二级缓存的类型改为read-write

@Entity
@Table(name="t_class")
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
@Cacheable
public class User {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    private String name;

 下面上第一个测试:

@Test
    public void testAdd(){
        Session session = null;

        try {
            session = HibernateSessionFactory.getSession();
            List<User> list = session.createQuery("from User").setCacheable(true).list();
            for(User u : list){
                System.out.println("111111111111111"+u.getName());
            }
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

        try {
            session = HibernateSessionFactory.getSession();
            List<User> list = session.createQuery("from User").setCacheable(true).list();
            for(User u : list){
                System.out.println("222222222222"+u.getName());
            }
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

    }

看下查询结果:

Hibernate: select user0_.id as id0_, user0_.name as name0_ from t_class user0_
111111111111111301
111111111111111302
111111111111111303
111111111111111304
111111111111111305
222222222222301
222222222222302
222222222222303
222222222222304
222222222222305

此时只发出了一条sql语句,表示二级缓存成功,注意红色部分。

下面做第二个测试,一样的代码,只不过需要在中间加上一部分代码:

@Test
    public void testAdd(){
        Session session = null;

        try {
            session = HibernateSessionFactory.getSession();
            List<User> list = session.createQuery("from User").setCacheable(true).list();
            for(User u : list){
                System.out.println("111111111111111"+u.getName());
            }
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

        try {
            session = HibernateSessionFactory.getSession();
            User u = new User();
            u.setName("306");
            session.save(u);
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

        try {
            session = HibernateSessionFactory.getSession();
            List<User> list = session.createQuery("from User").setCacheable(true).list();
            for(User u : list){
                System.out.println("222222222222"+u.getName());
            }
        } catch (HibernateException e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

    }

  此时的测试结果为:

Hibernate: select user0_.id as id0_, user0_.name as name0_ from t_class user0_
111111111111111301
111111111111111302
111111111111111303
111111111111111304
111111111111111305
Hibernate: insert into t_class (name) values (?)
Hibernate: select user0_.id as id0_, user0_.name as name0_ from t_class user0_
222222222222301
222222222222302
222222222222303
222222222222304
222222222222305
222222222222306

  中间进行过新增操作之后,重新发出了查询的sql语句,这是因为read-write是允许写入操作的,在发生写入操作之后,需要重新发出sql语句进行查询,将查询结果放入二级缓存,如果中间没有发生其他写入操作,那么下次查询的时候就会从二级缓存里面读取数据了。

  6.总结

关于hibernate的缓存就暂时写到这里了,主要说的是二级缓存,一级缓存其实也没什么说的,也可能是我的理解达不到吧,有问题的地方欢迎大家指正,谢谢。

时间: 2024-07-31 16:45:28

hibernate的缓存问题的相关文章

hibernate 一级缓存

一级缓存 为什么要用缓存? 目的:减少对数据库的访问次数!从而提升hibernate的执行效率! Hibernate中缓存分类: 一级缓存 二级缓存 概念 1)Hibenate中一级缓存,也叫做session的缓存,它可以在session范围内减少数据库的访问次数!  只在session范围有效! Session关闭,一级缓存失效! 2)当调用session的save/saveOrUpdate/get/load/list/iterator方法的时候,都会把对象放入session的缓存中. 3)S

Hibernate之缓存详解

hibernate中提供了两级缓存,一级缓存是Session级别的缓存,它属于事务范围的缓存,该级缓存由hibernate管理,应用程序无需干预:二级缓存是SessionFactory级别的缓存,该级缓存可以进行配置和更改,并且可以动态加载和卸载,hibernate还为查询结果提供了一个查询缓存,它依赖于二级缓存: 一,缓存的概念 缓存是位于应用程序和永久性数据存储源之间用于临时存放复制数据的内存区域,缓存可以降低应用程序之间读写永久性数据存储源的次数,从而提高应用程序的运行性能: hibern

[转] Hibernate一级缓存、二级缓存

缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能.缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据. 缓存的介质一般是内存,所以读写速度很快.但如果缓存中存放的数据量非常大时,也会用硬盘作为缓存介质.缓存的实现不仅仅要考虑存储的介质,还要考虑到管理缓存的并发访问和缓存数据的生命周期. hibernate的缓存包括Session的缓存和SessionFactory的缓

hibernate一级缓存和二级缓存的区别

缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能.缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据. 缓存的介质一般是内存,所以读写速度很快.但如果缓存中存放的数据量非常大时,也会用硬盘作为缓存介质.缓存的实现不仅仅要考虑存储的介质,还要考虑到管理缓存的并发访问和缓存数据的生命周期. Hibernate的缓存包括Session的缓存和SessionFactory的缓

hibernate 一级缓存和二级缓存

hibernate一级缓存:session缓存即事务级缓存,session关闭,缓存自动销毁,开发人员不用管理,由hibernate管理,save.update.saveoOrUpdate.lock.load.list会自动向一级缓存中存放数据,get,load,list会自动从一级缓存中取数据,可调用evict(Object object)和clear()清除缓存. hibernate二级缓存:sessionFactory缓存即进程级别缓存,由缓存插件实现,如OSCache,对hibernat

Hibernate的缓存机制

一.why(为什么要用Hibernate缓存?) Hibernate是一个持久层框架,经常访问物理数据库. 为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能. 缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据. 二.what(Hibernate缓存原理是怎样的?)Hibernate缓存包括两大类:Hibernate一级缓存和Hibernate二级缓存. 1.Hibernate一级缓存又称为“Session的

Hibernate二级缓存

第一级缓存:事务范围的缓存.Session缓存.存放元数据和预定义SQL.只读缓存. 第二级缓存:进程范围或者集群范围.由SessionFactory负责管理.SessionFactory的外置缓存.SessionFactory这个级别维护的缓存.二级缓存是针对整个应用而不是某个特定的session. Session 如何判断持久化对象的状态的改变呢? Session 加载对象后会为对象值类型的属性复制一份快照.当Session 清理缓存时,比较当前对象和它的快照就可以知道那些属性发生了变化.

java框架篇---hibernate之缓存机制

一.why(为什么要用Hibernate缓存?) Hibernate是一个持久层框架,经常访问物理数据库. 为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能. 缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据. 二.what(Hibernate缓存原理是怎样的?)Hibernate缓存包括两大类:Hibernate一级缓存和Hibernate二级缓存. 1.Hibernate一级缓存又称为“Session的

Hibernate二级缓存以及ehcache的搭建配置

前言 这次主要复习Hibernate的二级缓存的相关知识,配置以及使用.二级缓存主要采用第三方的ehcache,也将介绍ehcache缓存的相关配置属性以及在项目中的搭建,具体的项目查看下一篇的 Maven搭建SpringMVC+Hibernate项目详解 的文章.(之前使用过Hibernate的二级缓存,但是没自己搭建和研究过,现在花了半天时间搭建了一下,写下来供大家参考) 1.Hibernate二级缓存 Hibernate包括两个级别的缓存: 1.一级缓存:默认总是启用的session级别的

攻城狮在路上(壹) Hibernate(十八)--- 管理Hibernate的缓存

一般Session的缓存被称为Hibernate的第一级缓存,SessionFactory的外置缓存是一个可配置的缓存插件,称为Hibernate的第二级缓存.一.缓存的基本原理: 1.持久化层的缓存的范围: A.事务范围:缓存只被当前事务访问. B.进程范围:缓存被进程内的所有事务共享.需要采取必要的隔离机制.缓存介质可以使内存或硬盘. C.集群范围:缓存被同一个机器或多个机器上的多个进程共享.缓存中的数据被复制到集群环境中的每一个进程节点,进程之间通过远程通信来保证缓存中的数据一致性,缓存中