предисловие
Я уже знакомил своих друзей со знаниями, связанными с мобильной разработкой для iOS и Android, поэтому сегодня я реорганизую и обобщу точки знаний по бэкенд-разработке: Hibernate, возможно, многие компании медленно переходят на spring boot и spring MVC, но они всегда неразделимы. , чтобы понять и изучить фреймворк или его идеи, это тоже одно и то же, и есть еще много старых проектов, оставленных предприятиями, которые до сих пор остаются в таких проектах, как SSM и SSH;
Введение в кэширование
Кэш находится между приложением и физическим источником данных, и его роль заключается в снижении частоты обращения приложения к физическому источнику данных, что повышает производительность приложения. Данные в кеше — это копия данных в физическом источнике данных.Приложение считывает и записывает данные из кеша во время выполнения и синхронизирует данные в кеше и физическом источнике данных в определенный момент или событие.
Кэшированный носитель обычно представляет собой память, поэтому скорость чтения и записи очень высока. Однако, если объем данных, хранящихся в кэше, очень велик, жесткий диск также будет использоваться в качестве носителя кэша. Реализация кеша должна учитывать не только носитель данных, но и параллельный доступ к кешу и жизненный цикл кэшированных данных.
Сессия, SessionFactory
Кэш Hibernate включает в себя кеш Session и кеш SessionFactory, Кэш SessionFactory можно разделить на две категории: встроенный кеш и внешний кеш. Кэш сеанса является встроенным и не может быть выгружен, также известный как кеш первого уровня Hibernate. Встроенный кэш SessionFactory аналогичен кэшу Session с точки зрения реализации: первый представляет собой данные, содержащиеся в некоторых атрибутах коллекции объекта SessionFactory, а второй относится к данным, содержащимся в некоторых атрибутах коллекции Session. Во встроенном кэше SessionFactory хранятся метаданные сопоставления и предопределенные операторы SQL.Метаданные сопоставления представляют собой копию данных в файле сопоставления, а предопределенные операторы SQL получаются из метаданных сопоставления на этапе инициализации Hibernate.Встроенный кэш SessionFactory только для чтения, приложение не может изменять метаданные сопоставления и предопределенные операторы SQL в кэше, поэтому SessionFactory не нужно синхронизировать встроенный кэш с файлом сопоставления. Внешний кеш SessionFactory — это настраиваемый плагин. По умолчанию SessionFactory не включает этот плагин. Данные во внешнем кэше являются копией данных базы данных, а носителем внешнего кэша может быть память или жесткий диск. Внешний кеш SessionFactory также известен как кеш второго уровня Hibernate.
Оба уровня кэша Hibernate расположены на уровне сохраняемости и хранят копии данных базы данных, так в чем же между ними разница? Чтобы понять разницу между ними, необходимо глубоко понять две характеристики кеша уровня сохраняемости: объем кеша и стратегию одновременного доступа к кешу.
Объем кэша уровня сохраняемости
Объем кеша определяет время жизни кеша и тех, кто может получить к нему доступ. Объем кэша делится на три категории.
сфера деятельности
Доступ к кешу может получить только текущая транзакция. Жизненный цикл кеша зависит от жизненного цикла транзакции, когда транзакция завершается, кеш также завершает свой жизненный цикл. В этой области кэшированный носитель — это память. Транзакции могут быть транзакциями базы данных или транзакциями приложений, каждая транзакция имеет свой собственный кеш, а данные в кеше обычно представлены в виде взаимосвязанных объектов.
объем процесса
Кэш используется всеми транзакциями внутри процесса. Эти транзакции могут обращаться к кешу одновременно, поэтому для кеша должен быть принят необходимый механизм изоляции транзакций. Жизненный цикл кеша зависит от жизненного цикла процесса.Когда процесс завершается, кеш завершает свой жизненный цикл. Кэш всего процесса может содержать большой объем данных, поэтому носителем данных может быть память или жесткий диск. Данные в кэше могут быть в виде взаимосвязанных объектов или отдельных данных объектов. Форма данных свободного объекта чем-то похожа на сериализованные данные объекта, но алгоритм разложения объекта в свободный алгоритм требует более быстрого, чем алгоритм сериализации объекта.
область кластера
В кластерной среде кеш совместно используется процессами на одной или нескольких машинах. Данные в кеше копируются на каждый узел процесса в среде кластера, а непротиворечивость данных в кеше обеспечивается удаленной связью между процессами.Данные в кеше обычно находятся в виде свободных данных объектов.
Для большинства приложений необходимо тщательно рассмотреть необходимость использования кэша на уровне кластера, поскольку доступ не обязательно будет намного быстрее, чем прямой доступ к данным базы данных.
Уровень сохраняемости может предоставлять широкий спектр кэшей. Если соответствующие данные не найдены в кэше области транзакции, их также можно запросить в кэше области процесса или кластера.Если они все еще не найдены, их можно запросить только в базе данных. Кэш на уровне транзакций — это кеш первого уровня уровня сохраняемости и обычно требуется; кеш на уровне процесса или кластера — это кеш второго уровня уровня сохранения и обычно необязательный.
Стратегия параллельного доступа к кешу уровня сохраняемости
Когда несколько параллельных транзакций одновременно обращаются к одним и тем же данным, кэшированным на уровне сохраняемости, возникают проблемы параллелизма, и необходимо принимать необходимые меры по изоляции транзакций.
Проблемы параллелизма возникают при использовании кэшей всего процесса или кластера, т. е. кэшей второго уровня. Следовательно, могут быть установлены следующие четыре типа стратегий одновременного доступа, и каждая стратегия соответствует уровню изоляции транзакции.
Транзакционный: применим только в управляемой среде. Он обеспечивает уровень изоляции транзакций Repeatable Read. Этот тип изоляции можно использовать для данных, которые часто считываются, но редко изменяются, поскольку он предотвращает проблемы параллелизма, такие как грязное чтение и неповторяющееся чтение.
Чтение-запись: обеспечивает уровень изоляции транзакций Read Committed. Применимо только в некластеризованных средах. Этот тип изоляции можно использовать для данных, которые часто считываются, но редко изменяются, поскольку он предотвращает проблемы параллелизма, такие как грязное чтение.
Нестрогий тип чтения-записи: непротиворечивость данных в кеше и базе данных не гарантируется. Если существует вероятность того, что две транзакции могут получить доступ к одним и тем же данным в кэше одновременно, для данных необходимо настроить короткое время истечения срока действия данных, чтобы максимально избежать грязных чтений. Эту стратегию параллельного доступа можно использовать для данных, которые редко изменяются и допускают периодическое грязное чтение.
Только для чтения: для данных, которые никогда не изменяются, например для справочных данных, можно использовать эту стратегию параллельного доступа.
Стратегия транзакционного параллельного доступа имеет самый высокий уровень изоляции транзакций, а тип только для чтения — самый низкий уровень изоляции. Чем выше уровень изоляции транзакций, тем ниже производительность параллелизма.
Какие данные подходят для хранения в кеше второго уровня?
1. Данные, которые редко изменяются 2. Не очень важные данные, допускающие случайные одновременные данные 3. Данные, к которым не будет осуществляться одновременный доступ 4. Справочные данные
Данные, которые не подходят для хранения в кеше второго уровня?
1. Данные, которые часто изменяются 2. Категорически запрещается одновременное отображение финансовых данных. 3. Данные передаются другим приложениям.
Кэш второго уровня Hibernate
Как упоминалось ранее, Hibernate предоставляет двухуровневый кеш, первый уровень — это кеш Session. Поскольку жизненный цикл объекта Session обычно соответствует транзакции базы данных или транзакции приложения, его кэш является кэшем области транзакции. Кэш первого уровня обязателен, не разрешен и по сути не сравним с выгрузкой. В кэше первого уровня каждый экземпляр персистентного класса имеет уникальный OID.
Кэш второго уровня — это подключаемый плагин кеша, которым управляет SessionFactory. Поскольку жизненный цикл объекта SessionFactory соответствует всему процессу приложения, кэш второго уровня является кэшем всего процесса или всего кластера. Свободные данные для объектов, хранящихся в этом кэше. Объекты второго уровня могут иметь проблемы с параллелизмом, поэтому необходимо принять соответствующую стратегию параллельного доступа, которая обеспечивает уровень изоляции транзакций для кэшируемых данных. Адаптеры кэша используются для интеграции специального программного обеспечения для реализации кэша с Hibernate. Кэш второго уровня является необязательным и может быть настроен на уровне детализации для каждого класса или коллекции.
Общий процесс стратегии кэширования второго уровня Hibernate выглядит следующим образом:
-
При условном запросе всегда выполняйте оператор SQL, например select * from table_name где ⋯ (выберите все поля), чтобы запросить базу данных и получить все объекты данных одновременно.
-
Поместите все полученные объекты данных в кэш второго уровня в соответствии с идентификатором.
-
Когда Hibernate обращается к объекту данных на основе его идентификатора, он сначала проверит его из кэша Session level 1, если его не удастся найти, если настроен кэш второго уровня, то он будет проверяться из кэша второго уровня; не может быть найден, он запросит базу данных и поместит результат в соответствии с идентификатором в кеш.
-
При удалении, обновлении и добавлении данных кэш обновляется одновременно.
Стратегия кэширования второго уровня Hibernate — это стратегия кэширования запросов ID, но она не влияет на условные запросы. С этой целью Hibernate предоставляет кэш запросов для условных запросов.
Процесс стратегии кэширования запросов Hibernate выглядит следующим образом:
-
На основе этой информации Hibernate сначала составляет Query Key, который включает в себя общую информацию условного запроса запроса: SQL, параметры, требуемые SQL, диапазон записей (начальная позиция rowStart, максимальное количество записей maxRows) и т. д.
-
Hibernate ищет соответствующий список результатов в кэше запросов на основе этого ключа запроса. Если он существует, верните список результатов; если он не существует, запросите базу данных, получите список результатов и поместите весь список результатов в кэш запросов в соответствии с ключом запроса.
-
SQL в ключе запроса включает имена некоторых таблиц. Если какие-либо данные в этих таблицах изменены, удалены, добавлены и т. д., эти связанные ключи запроса должны быть удалены из кэша.
Многие люди мало что знают о кеше второго уровня или имеют неправильное представление Я всегда хотел написать статью, чтобы представить кэш второго уровня гибернации, и я, наконец, не мог удержаться сегодня. Мой опыт в основном исходит от версии hibernate2.1, основной принцип такой же, как 3.0, 3.1, пожалуйста, простите мое упрямство.
Сессия Hibernate предоставляет кеш первого уровня, для каждой сессии один и тот же id загружается дважды, и два SQL не отправляются в базу данных, но когда сессия закрывается, кеш первого уровня недействителен.
Кэш второго уровня — это глобальный кеш на уровне SessionFactory, под ним могут использоваться разные библиотеки кеша, такие как ehcache, oscache и т. д., и необходимо установить hibernate.cache.provider_class. в 2.1. hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvider Если вы используете кэш запросов, добавьте hibernate.cache.use_query_cache=истина
Кэш можно просто рассматривать как Карту, и значение находится в кеше по ключу.
Кэш классов
Для записи, то есть PO, он находится по идентификатору, закэшированный ключ — это идентификатор, а значение — это POJO. Независимо от списка, загрузки или итерации, пока объект читается, кэш будет заполнен. Однако список не будет использовать кеш, и итерация сначала возьмет id выбора базы данных, а затем загрузит один id и один id.Если в кеше есть, он будет взят из кеша, а если нет, то он будут загружены из базы данных. Предполагая, что это кеш чтения-записи, вам нужно установить:
<cache usage="read-write"/>
Если вы используете реализацию кэша второго уровня — ehcache, вам необходимо настроить ehcache.xml.
<cache name="com.xxx.pojo.Foo" maxElementsInMemory="500" eternal="false" timeToLiveSeconds="7200" timeToIdleSeconds="3600" overflowToDisk="true" />
Внутренний указывает, будет ли тайм-аут кеша никогда не истечет, timeToLiveSeconds — это время ожидания каждого элемента в кеше (здесь POJO), если internal="false", элемент будет удален, если он превысит указанное время. timeToIdleSeconds — это время простоя, которое не является обязательным. При помещении в кеш более 500 элементов, если overflowToDisk="true", часть данных в кеше будет сохранена во временном файле на жестком диске. Каждый класс, который необходимо кэшировать, должен быть настроен таким образом. Если вы не настроите его, hibernate предупредит вас при запуске, а затем будет использовать конфигурацию defaultCache, чтобы несколько классов использовали одну конфигурацию.
Когда идентификатор изменяется спящим режимом, спящий режим узнает об этом и удалит кеш.
Таким образом, вы можете подумать, что для одних и тех же условий запроса, в первый раз, когда вы перечисляете его, и во второй раз итерации, вы можете использовать кеш. На самом деле это сложно, потому что нельзя судить, когда это первый раз, а условия каждого запроса обычно разные.Если записей в базе 100, то id от 1 до 100, а первый когда список отображается. Когда отображаются первые 50 идентификаторов, идентификатор 30-70 запрашивается при повторении во второй раз, затем 30-50 берется из кеша, 51-70 берется из базы данных, и всего 1 +20 sql отправлены. Поэтому я всегда думал, что итерация бесполезна, всегда будет проблема 1+N. (Не по теме: Говорят, что большие запросы используют list для загрузки всего набора результатов в память, что очень медленно, и iterate лучше выбирает только id, но большие запросы всегда нужно листать, и никто толком не поставит весь результат. Появляется сборка. Если на странице 20 элементов, итерация должна выполнить в общей сложности 21 оператор. Хотя список выбирает несколько полей, он медленнее, чем первый оператор выбора идентификатора итерации, но есть только один оператор, и hibernate не загрузит весь набор результатов.Для оптимизации в соответствии с диалектом базы данных, например, с использованием предела mysql, общий вид должен быть быстрее, чем список.) Если вы хотите кэшировать результаты списка или повторного запроса, вам нужно использовать кеш запроса.
кэш запросов
Сначала вам нужно настроить hibernate.cache.use_query_cache=true Если вы используете ehcache, настройте ehcache.xml, обратите внимание, что hibernate 3.0 не является именем пакета net.sf.
<cache name="net.sf.hibernate.cache.StandardQueryCache"
maxElementsInMemory="50" eternal="false" timeToIdleSeconds="3600"
timeToLiveSeconds="7200" overflowToDisk="true"/>
<cache name="net.sf.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="5000" eternal="true" overflowToDisk="true"/>
потом query.setCacheable(true);//Активировать кэш запросов query.setCacheRegion("myCacheRegion");//Укажите используемый cacheRegion, необязательно Во второй строке указывается, что cacheRegion, который будет использоваться, это myCacheRegion, то есть можно сделать отдельную конфигурацию для каждого кеша запросов, для этого используйте setCacheRegion, нужно настроить в ehcache.xml:
<cache name="myCacheRegion" maxElementsInMemory="10" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200" overflowToDisk="true" />
Если вторая строка опущена и cacheRegion не задан, то будет использоваться упомянутая выше стандартная конфигурация кэша запросов, то есть net.sf.hibernate.cache.StandardQueryCache.
Для кеша запросов закэшированный ключ — это SQL, сгенерированный по hql, плюс параметры, пейджинг и прочая информация (можно посмотреть через вывод лога, но его вывод не очень читабелен, лучше всего изменить его код). Например, hql:
from Cat c where c.name like ?
Сгенерируйте sql примерно следующим образом:
select * from cat c where c.name like ?
Параметр - "tiger%", затем запросить кешированный ключОЭто такая строка (я написал ее по памяти, это не точно, но вы должны понять это после прочтения):
select * from cat c where c.name like ? , parameter:tiger%
Таким образом, для одного и того же запроса и с одними и теми же параметрами гарантируется один и тот же ключ.
Теперь давайте поговорим о кэшированном значении.Если это метод списка, значением здесь является не весь результирующий набор, а строка запрошенных идентификаторов. То есть, будь то метод списка или метод итерации, когда они запрашиваются в первый раз, их методы запросов такие же, как и их обычные методы.Список выполняет один sql, а итерация выполняет 1+N. поведение такое Кэш заполнен. Но когда то же условие запрашивается во второй раз, поведение такое же, как итерация.По закешированному ключу значение находится в кеше.Значение представляет собой строку идентификаторов, а затем загружается по одному в кеше класса. Это сделано для экономии памяти. Видно, что кеш запроса должен открыть кеш класса связанного класса. Когда методы списка и итерации выполняются в первый раз, заполняются и кеш запроса, и кеш класса.
Существует также важная проблема, которую легко упустить из виду, то есть после открытия кеша запросов даже метод списка может столкнуться с проблемой 1+N! Когда одни и те же условия перечислены в первый раз, поскольку кеш запроса не может быть найден, независимо от того, есть ли данные в кеше класса, всегда отправляется оператор SQL в базу данных для получения всех данных, а затем кеш запроса и кеш класса заполнены. Но когда он выполняется во второй раз, возникает проблема: если время ожидания вашего кеша классов относительно короткое, и теперь время ожидания кеша классов истекло, но кеш запроса все еще существует, тогда метод списка получит id строки по одному.Перейти к загрузке базы данных! Следовательно, период тайм-аута кеша классов не должен быть меньше периода тайм-аута, установленного кешем запросов! Если также установлено время затухания, убедитесь, что время затухания кэша классов также превышает время жизни кэша запросов. Здесь есть и другие ситуации, например, кеш класса принудительно удаляется программой, обратите внимание на эту ситуацию.
Кроме того, если hql-запрос содержит предложение select, то значением в кэше запроса является весь результирующий набор.
Когда hibernate обновляет базу данных, как он узнает, какие кеши запросов нужно обновить? Hibernate хранит время последнего обновления каждой таблицы в одном месте, которое фактически помещается в конфигурацию кэша, указанную выше в net.sf.hibernate.cache.UpdateTimestampsCache. При обновлении через спящий режим спящий режим будет знать, какие таблицы затронуты обновлением. Затем он обновляет время последнего обновления этих таблиц. Каждый кеш имеет время генерации и таблицу, запрошенную кешем.Когда спящий режим запрашивает, существует ли кеш, если кеш существует, он также извлекает время генерации кеша и таблицы, запрошенной кешем, а затем ищет эти Время последнего обновления таблицы. Если таблица обновляется после времени генерации, кеш недействителен. Можно видеть, что пока таблица обновляется, кеш запросов, связанный с этой таблицей, будет недействительным, поэтому частота попаданий в кеш запросов может быть относительно низкой.
Кэш коллекции
Его нужно установить в сборе hbm
<cache usage="read-write"/>
Если класс Cat и коллекция называется дочерней, то конфигурация в ehcache
<cache name="com.xxx.pojo.Cat.children"
maxElementsInMemory="20" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200"
overflowToDisk="true" />
Кэш коллекции аналогичен списку в предыдущем кеше запроса. Он поддерживает только строку идентификаторов, но не будет аннулирован, поскольку таблица была обновлена. Кэш коллекции будет аннулирован только тогда, когда элементы в коллекции будут добавлено или удалено. У этого есть проблема.Если ваша коллекция отсортирована по полю, когда один из элементов обновляет поле, вызывая изменение порядка, порядок в кеше коллекции не обновляется.
стратегия кэширования
кеш только для чтения: нечего сказать кеш чтения/записи (чтение-запись): программа может захотеть обновить данные Нестрогий кэш чтения/записи (nonstrict read-write): данные необходимо обновлять, но вероятность того, что две транзакции обновят одну и ту же запись, мала, а производительность лучше, чем кэш чтения-записи. Транзакционный: Кэш поддерживает транзакции.При возникновении исключения кеш тоже можно откатить.Поддерживает только среду jta.Я особо не изучал.
Разница в реализации между кешем чтения-записи и свободным кешем чтения-записи заключается в том, что когда кеш чтения-записи обновляет кеш, данные в кеше будут заменены блокировкой.Если другие транзакции отправляются на выборку соответствующего кеша данные, они обнаружат, что они заблокированы, а затем напрямую получат запрос к базе данных. В реализации ehcache спящего режима 2.1, если в транзакции, которая блокирует часть кэша, возникает исключение, кэш будет заблокирован до тех пор, пока не истечет время ожидания через 60 секунд. Нестрогие кэши чтения-записи не блокируют данные в кэше.
Предварительные условия для использования кэша L2
Ваша спящая программа имеет эксклюзивный доступ для записи в базу данных, другие процессы обновляют базу данных, спящий режим невозможно узнать. Вы должны управлять базой данных напрямую через спящий режим, если вы вызываете хранимые процедуры или обновляете базу данных с помощью jdbc, спящий режим этого не знает. Массовое обновление и удаление спящего режима 3.0 не обновляет вторичный кеш, но говорят, что 3.1 решила эту проблему. Это ограничение довольно сложное: иногда hibernate очень медленно выполняет пакетные обновления и удаления, но вы не можете написать jdbc, чтобы оптимизировать его самостоятельно, что очень угнетает.
SessionFactory также предоставляет методы для удаления кеша. Если вам нужно написать JDBC самостоятельно, вы можете вызвать эти методы для удаления кеша. Вот эти методы:
void evict(Class persistentClass)
Evict all entries from the second-level cache.
void evict(Class persistentClass, Serializable id)
Evict an entry from the second-level cache.
void evictCollection(String roleName)
Evict all entries from the second-level cache.
void evictCollection(String roleName, Serializable id)
Evict an entry from the second-level cache.
void evictQueries()
Evict any query result sets cached in the default query cache region.
void evictQueries(String cacheRegion)
Evict any query result sets cached in the named query cache region.
Я не рекомендую делать это, потому что это сложно поддерживать. Например, если вы используете JDBC для пакетного обновления таблицы, три кеша запросов будут использовать эту таблицу, используйте evictQueries(String cacheRegion) для удаления трех кешей запросов, а затем используйте evict(Class PermanentClass) для удаления кеша класса. похоже, что он завершен. Но однажды вы добавите связанный кеш запросов, вы можете забыть обновить здесь код удаления. Если ваш код jdbc повсюду, когда вы добавляете кэш запросов, знаете ли вы, где еще внести соответствующие изменения?
гибернировать кеш первого уровня
Кэш первого уровня очень короткий и соответствует жизненному циклу сеанса.Кэш первого уровня также называется кешем уровня сеанса или кешем уровня транзакций.
Эти методы поддерживают кеш L1: получить() нагрузка() итерация (запрос объекта сущности)
Как управлять кешем первого уровня: сессия.clear(), сессия.evict()
Как избежать переполнения памяти, вызванного одновременным хранением большого количества данных сущностей в базе данных Сначала промыть, потом очистить
Если объем данных особенно велик, рассмотрите возможность его реализации с помощью jdbc.Если jdbc не соответствует требованиям, вы можете рассмотреть возможность использования специального инструмента импорта для самих данных.
спящий кэш второго уровня
Кэш второго уровня также называется кешем уровня процесса или кешем уровня SessionFactory.Кэш второго уровня может совместно использоваться всеми сеансами. Жизненный цикл кэша L2 соответствует циклу SessionFactory, и SessionFactory может управлять кэшем L2.
Настройка и использование кеша L2:
将echcache.xml文件拷贝到src下
开启二级缓存,修改hibernate.cfg.xml文件 放在<mapping>前
<property name="hibernate.cache.use_second_level_cache">true</property>
指定缓存产品提供商,修改hibernate.cfg.xml文件 放在<mapping>前
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
Укажите, какие классы сущностей используют кэш второго уровня (два метода) Принять теги в файлах сопоставления [Рекомендуется] В файле hibernate.cfg.xml используйте такие теги, как:
<class-cache class="com.bcm.model.Article" usage="read-write"/>
Кэш второго уровня предназначен для кэширования сущностных объектов.
кеш запросов гибернации
Кэш запросов — это кеш для обычных наборов результатов атрибутов. Наборы результатов для сущностных объектов кэшируют только идентификатор
Жизненный цикл кеша запросов, текущая связанная таблица изменяется, затем жизненный цикл кеша запросов заканчивается
Конфигурация кэша запросов и использование:
- Включите кеширование запросов в файле hibernate.cfg.xml, например:
true
- Кэширование запросов должно быть включено вручную в программе, например:
query.setCacheable(true);
/**
* 开启查询缓存,关闭二级缓存
*
* 开启一个session,分别调用query.list
*/
public void testCache1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Query query = session.createQuery("select s.name from Student s");
//启用查询查询缓存
query.setCacheable(true);
List names = query.list();
for (Iterator iter=names.iterator();iter.hasNext(); ) {
String name = (String)iter.next();
System.out.println(name);
}
System.out.println("-------------------------------------");
query = session.createQuery("select s.name from Student s");
//启用查询查询缓存
query.setCacheable(true);
//没有发出查询sql,因为启用了查询缓存
names = query.list();
for (Iterator iter=names.iterator();iter.hasNext(); ) {
String name = (String)iter.next();
System.out.println(name);
}
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
Запрос объекта сущности [Важно]
Проблема N+1, по умолчанию (без открытия кеша запросов), для запроса используйте query.iterate, проблем может быть N+1 Так называемый N+1 означает, что при запросе выдается N+1 SQL-операторов. 1: сначала запустите sql, запрашивающий список идентификаторов объектов. N: запрос в кеше в соответствии со списком идентификаторов, если в кеше нет соответствующих данных, будет выдан соответствующий оператор sql в соответствии с идентификатором В чем разница между списком и итерацией? список будет выдавать оператор sql каждый раз, список будет помещать данные в кеш без использования данных в кеше iterate: по умолчанию iterate использует кешированные данные, но если в кеше нет данных, может возникнуть проблема N+1
Независимо от списка, загрузки или итерации, пока объект читается, кэш будет заполнен. Однако список не будет использовать кеш, и итерация сначала возьмет идентификатор выбора базы данных, а затем загрузит один идентификатор и один идентификатор.Если он есть в кеше, он будет взят из кеша.Если нет, он будет перейти к базе данных для загрузки.
Суммировать
Не считайте само собой разумеющимся, что кэширование определенно улучшит производительность, только если вы можете с этим справиться и условия правильные. Кэш второго уровня Hibernate имеет массу ограничений, а использовать jdbc неудобно, что может сильно снизить производительность обновления. Если использовать его без понимания принципа, может возникнуть проблема 1+N. Неправильное использование также может привести к чтению грязных данных.
Если вы не переносите множество ограничений гибернации, то вам следует самостоятельно заняться кэшированием на уровне приложений. Чем выше уровень кэширования, тем лучше эффект. Кажется, что хотя на диске есть кеш, база данных все равно должна реализовать свой собственный кеш, и даже несмотря на то, что у базы данных есть кеш, наше приложение все равно должно делать кеш. Поскольку базовый кеш не знает, что должен делать с данными высокоуровневый, он может делать это только в более общем виде, а высокоуровневый может реализовать целевое кэширование, поэтому кэширование на более высоком уровне должно быть лучше.