Hibernate [cache] очки знаний

Java Hibernate Java EE

состояние объекта

Состояние объекта в Hibernate:

  • временное / переходное состояние
  • постоянное состояние
  • свободный штат

Изучение состояния объекта HibernateДля того, чтобы яснее узнать конструкторскую идею Hibernate, и основу кэша первого уровня...и конечно немного знаний

временное/переходное состояние

когда мыОбъект непосредственно новый - это временное/переходное состояние..

  • Объект не был сохранен [не сохранен в базе данных]
  • Не управляется сеансом

这里写图片描述

постоянное состояние

Когда объект хранится в базе данных, это постоянное состояние.

  • При вызове методов сохранения/сохранения или обновления/получения/загрузки/списка сеанса и других методов объект является постоянным состоянием.
  • соответствующие данные в базе данных
  • Управляется сеансом
  • При внесении изменений в свойства объекта они будут отражены в базе данных!

这里写图片描述

Давайте проверим это:При внесении изменений в свойства объекта они будут отражены в базе данных!


        session.save(idCard);
        idCard.setIdCardName("我是测试持久化对象");

这里写图片描述

свободный штат

Когда сеанс закрывается, постоянный объект становится свободным...

  • Не в управлении сессиями
  • Имеются соответствующие записи в базе данных

这里写图片描述


Кэш L1

Hibernate имеет кеш первого уровня и кеш второго уровня.Здесь в основном объясняется кеш первого уровня.

Что такое кеш первого уровня?

Кэш первого уровня в Hibernate, также известный как кеш сеанса,Это может уменьшить количество посещений базы данных в рамках сеанса! Действует только в рамках сеанса! Сессия закрыта, кэш первого уровня недействителен!

Пока состояние постоянного объекта управляется сеансом, то есть он будет находиться в кэше сеанса!

Кэш сеанса поддерживается спящим режимом,Пользователь не может управлять кэшированным содержимым; если вы хотите управлять кэшированным содержимым, вы должны использовать метод evit/clear, предоставляемый спящим режимом..

Зачем использовать кеш?

Сократите количество посещений базы данных! Тем самым повышая эффективность выполнения hibernate!

тестовое задание

Давайте посмотрим, как Hibernate сокращает количество обращений к базе данных.

Теперь в моей таблице User есть такая запись:

这里写图片描述

		//把数据放进cache
        User user = (User) session.get(User.class, 1);

		//发现要修改的字段和cache一样,不执行
        user.setUserName("你好2");

这里写图片描述

这里写图片描述

То же самое верно для выборки данных


        User user = null;
        user = (User) session.get(User.class, 1);
        user = (User) session.get(User.class, 1);

这里写图片描述


Методы, связанные с кэшем

Существует три широко используемых метода, связанных с кэшированием:

  • session.flush(); синхронизировать кеш первого уровня с базой данных

  • session.evict(arg0);Очистить указанный объект в кеше первого уровня

  • session.clear(); очищает все объекты, кэшированные в кеше первого уровня

  • clear


        User user = null;
        user = (User) session.get(User.class, 1);

        //清除缓存,那么下面获取的时候,就不能从缓存里面拿了
        session.clear();
        user = (User) session.get(User.class, 1);

  • flush

В случае кеша измените данные той же записи, в зависимости от того, какая из них последняя... Так что есть только одно обновление


        User user = null;
        user = (User) session.get(User.class, 1);

        user.setUserName("我是第一");
        user = (User) session.get(User.class, 1);
        user.setUserName("我是第二");

这里写图片描述

я разрешаюЗаставил его и синхронизацию базы данныхЕсли да, то будет два обновления.

        User user = null;
        user = (User) session.get(User.class, 1);

        user.setUserName("我是第一");
 		session.flush();
        user = (User) session.get(User.class, 1);
        user.setUserName("我是第二");

这里写图片描述

Как правило, мыиспользуется в пакетной обработке,потому чтоУ кеша тоже есть размер.Если в кеш вставить 1000 штук данных, то Hibernate может рухнуть....

  • Каждое определенное количество записей сначала синхронизируйте с базой данных flush()
  • Затем очистите кеш clear()

Стоит отметить, что:Разные сеансы не будут совместно использовать кеш!

Итератор и список

Когда мы используем HQL для запроса всех данных,Вы можете использовать list(), чтобы получить все данные, или вы можете использовать iterator(), чтобы получить итератор, а затем пройти по итератору.... так какая между ними разница?

. . . . Когда я смотрел видео, там было сказано:

这里写图片描述

Но когда я тестирую:Список также может получать кешированные данные

这里写图片描述

Конечно, Iterator также может получать кешированные данные.

这里写图片描述

следовательно,Удобно использовать list() при получении данных!

ленивая загрузка

Ленивая загрузка заключается в получении данных и выполнении соответствующего оператора SQL при использовании данных....Когда данные не использовались, соответствующие данные не будут загружены!

Основная цель состоит в том, чтобыУлучшить производительность Hibernate и повысить эффективность выполнения!

  • get: загрузить вовремя, просто вызовите метод get, чтобы немедленно запросить базу данных
  • load: по умолчанию используется ленивая загрузка, а запросы к базе данных выполняются только при использовании данных.

Ленивая загрузка снова

        User user = (User) session.load(User.class, 1);

        System.out.println("________");
        System.out.println(user);

这里写图片描述

Мы можем соответствоватьФайл конфигурации задается с обычным ленивым атрибутом

Отключить ленивую загрузку:

    <class name="IdCard" table="IdCard" lazy="false">

这里写图片描述

lazy имеет три свойства:

  • истинное использование ленивой загрузки
  • false отключить ленивую загрузку
  • дополнительно (для повышения эффективности при ленивой загрузке данных коллекции) [используется только в тегах коллекции, таких как набор и список]
    • SQL-запрос отправляется в базу данных только тогда, когда данные фактически используются;
    • Если вы вызываете метод коллекции size()/isEmpty(), это всего лишь статистика, а не запрос данных!

исключение ленивой загрузки

Когда сессия закрыта, отложенная загрузка не может быть использована, иначе будет сообщено об исключении


Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session

这里写图片描述

Когда об этом исключении сообщается, у нас есть 4 способа его решения:

  • Способ 1: сначала используйте данные
    • dept.getDeptName();
  • Способ 2: принудительная инициализация прокси-объекта
    • Hibernate.initialize(dept);
  • Способ 3: отключить ленивую загрузку
    • установить ленивый = ложь;
  • **Метод 4: После использования данных закройте сеанс! **

Спящий кэш второго уровня

Мы уже объясняли кэш первого уровня ранее.Кэш первого уровня также является кэшем сеанса, который действителен только в рамках сеанса....время действия находится в рамках сеанса,относительно небольшой диапазон

Hibernate предоставляет нам функцию кэширования второго уровня:Кэш второго уровня — это кеш на основе приложений, который может использоваться всеми сессиями.

  • Кэш второго уровня, предоставляемый Hibernate, имеет реализацию по умолчанию и являетсяПодключаемый фреймворк кэширования! Если пользователь хочет использовать кеш второго уровня,Просто нужно настроить в hibernate.cfg.xml; Если вы не хотите его использовать, удалите его напрямую, не затрагивая код.
  • Если пользователи считают, что инфраструктура, предоставляемая спящим режимом, непроста в использовании,Вы можете перейти на другие фреймворки кэширования или реализовать свою собственную фреймворк кэширования..

这里写图片描述

Вторичный кэш с гибернацией:Часто используемые классы хранятся


Настроить кеш L2

Так как кеш второго уровня поставляется с Hibernate, то мы можемНайдите соответствующую информацию в файле hibernate.properties...

这里写图片描述

  • #hibernate.cache.use_second_level_cache false [Кэш второго уровня не включен по умолчанию, и его необходимо включить вручную]
  • #hibernate.cache.use_query_cache true [Включить кэш запросов]
  • выбрать реализацию кеша [реализация фреймворка кеша второго уровня]

  • #hibernate.cache.provider_class org.hibernate.cache.EhCacheProvider
  • #hibernate.cache.provider_class org.hibernate.cache.EmptyCacheProvider
  • hibernate.cache.provider_class org.hibernate.cache.HashtableCacheProvider реализация по умолчанию
  • #hibernate.cache.provider_class org.hibernate.cache.TreeCacheProvider
  • #hibernate.cache.provider_class org.hibernate.cache.OSCacheProvider
  • #hibernate.cache.provider_class org.hibernate.cache.SwarmCacheProvider

Через файл конфигурации мы можем обнаружить, что кеш второго уровня не включен по умолчанию, и нам нужно включить его вручную.Следующие шаги:

  • 1) Включить кеш второго уровня
  • 2) Укажите структуру кеша
  • 3) Указать, какие классы добавляются в кеш второго уровня

Включить кеш L2

Включить кеш L2 в файле hibernate.cfg.xml


		<!-- a.  开启二级缓存 -->
		<property name="hibernate.cache.use_second_level_cache">true</property>

Укажите кадр кэша

Просто укажите структуру кэширования второго уровня, которая поставляется с Hibernate.


		<!-- b. 指定使用哪一个缓存框架(默认提供的) -->
		<property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>

Укажите, какие классы добавляются в кеш второго уровня


	    <!-- c. 指定哪一些类,需要加入二级缓存 -->
        <class-cache usage="read-write" class="zhongfucheng.aa.Monkey"/>
        <class-cache usage="read-only" class="zhongfucheng.aa.Cat"/>

тестовое задание:

Мы знаем, что кеш первого уровня — это кеш сеанса, тогда мы находимся вПротестируйте вторичный кеш при использовании двух сеансов, чтобы проверить все в порядке. Если второй сеанс получает кэшированные данные, это доказывает, что кэш второго уровня полезен.


package zhongfucheng.aa;

import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;

public class App5 {
    public static void main(String[] args) {


        //获取加载配置管理类
        Configuration configuration = new Configuration();
        //加载类对应的映射文件!
        configuration.configure().addClass(Animal.class);
        //创建Session工厂对象
        SessionFactory factory = configuration.buildSessionFactory();
        //得到Session对象
        Session session1 = factory.openSession();
        //使用Hibernate操作数据库,都要开启事务,得到事务对象
        Transaction transaction = session1.getTransaction();
        //开启事务
        transaction.begin();
        Monkey monkey = (Monkey) session1.get(Monkey.class,"40283f815be67f42015be67f43240001" );
        System.out.println(monkey.getName());
        System.out.println("-----------------------");



        Session session2 = factory.openSession();
        Transaction transaction2 = session2.getTransaction();
        transaction2.begin();
        Monkey monkey2 = (Monkey) session1.get(Monkey.class, "40283f815be67f42015be67f43240001");
        System.out.println(monkey2.getName());


        //提交事务
        transaction.commit();
        transaction2.commit();

        //关闭Session
        session1.close();
        session2.close();


    }
}

То, что вы получаете, это кешированные данные!

这里写图片描述


стратегия кэширования

Когда мы помещаем класс Animal в кеш второго уровня, использование доступно только для чтения.

这里写图片描述

Другими словами, вы можете только читать, а не писать, давайте посмотрим, что происходит, когда вы пишете:


  monkey2.setName("小猴子");

Было выброшено исключение....

这里写图片描述


Есть 4 атрибута использования:

  • ** Объекты, помещенные в кэш L2, доступны только для чтения; **
  • нестрогое чтение и запись
  • Чтение и запись, объекты, помещенные в кэш L2, могут быть прочитаны и записаны;
  • (транзакционная стратегия)

Кэш коллекции

Если данные, которые мы запрашиваем в базе данных, представляют собой коллекцию...Hibernate не устанавливает кеш второго уровня для сбора данных по умолчанию... так что вам все еще нужно читать и записывать информацию о базе данных

Далее давайте посмотрим, что делает установка коллекции в качестве кеша второго уровня:

  • В hibernate.cgf.xml настроить коллекцию в объекте как кеш второго уровня
		<!-- 集合缓存[集合缓存的元素对象,也加加入二级缓存] -->
		<collection-cache usage="read-write" collection="cn.itcast.b_second_cache.Dept.emps"/>
  • Тестовый код:

	public void testCache() {
		Session session1 = sf.openSession();
		session1.beginTransaction();
		// a. 查询一次
		Dept dept = (Dept) session1.get(Dept.class, 10);
		dept.getEmps().size();// 集合
		session1.getTransaction().commit();
		session1.close();
		
		System.out.println("------");
		
		// 第二个session
		Session session2 = sf.openSession();
		session2.beginTransaction();
		// a. 查询一次
		dept = (Dept) session2.get(Dept.class, 10);  // 二级缓存配置好; 这里不查询数据库
		dept.getEmps().size();
		
		session2.getTransaction().commit();
		session2.close();
	}

кэш запросов

list() и iterator() поместят данные в кеш первого уровня, но кеш первого уровня действителен только в рамках сеанса... Если вы хотитеДля использования между сеансами необходимо настроить кеш запросов.

Так же видим в конфиг файлеКэш запросов такой конфигурации..

	#hibernate.cache.use_query_cache true      【开启查询缓存】

То есть,Данные запроса по умолчанию не помещаются в кеш второго уровня., если мы хотим поместить запрошенные данные в кеш второго уровня, нам нужновключить в конфигурационном файле

		<!-- 开启查询缓存 -->
		<property name="hibernate.cache.use_query_cache">true</property>
  • Когда запрос с использованием программы, но также также вызовов SETCAACHIBLE () метод, установите кэш запроса.

	@Test
	public void listCache() {
		Session session1 = sf.openSession();
		session1.beginTransaction();
		// HQL查询  【setCacheable  指定从二级缓存找,或者是放入二级缓存】
		Query q = session1.createQuery("from Dept").setCacheable(true);
		System.out.println(q.list());
		session1.getTransaction().commit();
		session1.close();
		
		
		Session session2 = sf.openSession();
		session2.beginTransaction();
		q = session2.createQuery("from Dept").setCacheable(true);
		System.out.println(q.list());  // 不查询数据库: 需要开启查询缓存
		session2.getTransaction().commit();
		session2.close();
	}

Если в статье есть какие-либо ошибки, пожалуйста, поправьте меня, и мы сможем общаться друг с другом. Учащиеся, привыкшие читать технические статьи в WeChat и желающие получить больше ресурсов по Java, могутОбратите внимание на публичный аккаунт WeChat: Java3y