Статьи

GWT Spring и Hibernate входят в мир Data Grids

Увеличьте производительность Hibernate с помощью Infinispan Data Grid. Учебное пособие по интеграции GWT , Spring , JPA , Hibernate , Infinispan .

В этом уроке мы обсудим, как вы можете использовать Infinispan в качестве провайдера кэша второго уровня Hibernate . Infinispan является преемником кеша JBoss и флагманом компании в области грид- данных с открытым исходным кодом. Чтобы сделать вещи более интересными, мы продолжим с того места, которое мы оставили в предыдущей статье об интеграции Spring GWT Hibernate и JPA . Мы собираемся использовать наш проект GWTSpring и наделить его функциональностью сетки данных!

Hiberante поддерживает Infinispan в качестве поставщика кэша второго уровня начиная с версии 3.5 и выше, мы собираемся использовать версию 3.5.2 Hibernate и версию 4.0.0 Infinispan . Вы можете скачать бинарный дистрибутив Infinispan здесь

Настоятельно рекомендуется настроить Hibernate на использование транзакций JTA, чтобы Hibernate и Infinispan взаимодействовали в одной транзакции. В противном случае операции с базой данных и кэшем второго уровня не будут рассматриваться как единая единица работы. Риски здесь включают сбои в обновлении кэша второго уровня, в результате чего устаревшие данные остаются в то время, когда база данных корректно фиксирует данные.

В связи с тем, что мы развертываем наше веб-приложение в автономной среде ( Apache — Tomcat ), а не в полном объеме, сервер приложений JTA с поддержкой, чтобы соответствовать вышеупомянутым требованиям, мы собираемся реализовать среду JTA в Spring фреймворк. Для этого нам нужен JTA- совместимый менеджер транзакций, и мы предпочитаем Atomikos . Конечно, вы можете использовать любой JTA- совместимый менеджер транзакций, который вы предпочитаете. Мы будем использовать Atomikos Transactions Essentials версии 3.6.5, которую вы можете скачать здесь

И последнее, но не менее важное: нам понадобится MySQL Connector / J для подключения к базе данных MySQL для тестирования. Версия 3.6.5 Atomikos Transactions Essentials тестируется и хорошо работает с MySQL Connector / J версии 5.1.5, которую вы можете скачать здесь

Чтобы правильно интегрировать Infinispan и Hibernate во время выполнения, мы должны предоставить все необходимые библиотеки для веб-приложения. Поэтому скопируйте файлы, перечисленные ниже в / war / WEB-INF / lib (скопируйте соответствующие файлы, если вы используете разные версии)

Из бинарного распределения Infinispan

  • infinispan-core.jar
  • /lib/jboss-common-core-2.2.14.GA.jar
  • /lib/jcip-annotations-1.0.jar
  • /lib/jgroups-2.9.0.GA.jar
  • /lib/marshalling-api-1.2.0.GA.jar
  • /lib/rhq-pluginAnnotations-1.4.0.B01.jar
  • /lib/river-1.2.0.GA.jar

Из дистрибутива «Атомикос Транзакции»

  • /dist/transactions-essentials-all.jar
  • /lib/jca.jar
  • /lib/jms.jar
  • /lib/jmx.jar

MySQL, Connector / J

  • MySQL-разъем-Java-5.1.5-bin.jar

Наконец, для правильной работы Atomikos во время выполнения файл «jta.properties» должен находиться в пути к классам нашего веб-приложения. Создайте текстовый файл с именем «jta.properties», поместите его в пакет / resources проекта Eclipse и заполните его свойствами, показанными ниже:

1
2
3
4
com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory
com.atomikos.icatch.force_shutdown_on_vm_exit = true
com.atomikos.icatch.automatic_resource_registration = false
com.atomikos.icatch.console_log_level = INFO

Теперь нам нужно позаботиться о зависимостях для нашего проекта Eclipse . Следующие jar-файлы должны быть включены в путь сборки Java проекта:

  • hibernate3.jar

Следующим шагом является настройка Hibernate для использования диалекта MySQL и кеша второго уровня. Найдите файл persistence.xml в папке / resources / META-INF и внесите изменения, описанные ниже:

Чтобы использовать диалект MySQL, добавьте следующее свойство:

1
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />

Чтобы настроить использование менеджера транзакций, добавьте следующие свойства:

1
<property name="hibernate.transaction.manager_lookup_class" value="com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup" />

Чтобы включить кэш второго уровня Hibernate с включенным кэшированием результатов запроса, необходимо добавить следующие свойства:

1
2
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.use_query_cache" value="true"/>

На данный момент мы должны точно указать, что включение кэширования результатов запроса может не повысить производительность, особенно если ваше приложение выполняет запросы, которые в основном возвращают уникальные результаты.

Чтобы настроить фабрику области кэша Infinispan, добавьте следующее свойство:

1
2
<property name="hibernate.cache.region.factory_class"
 value="org.hibernate.cache.infinispan.InfinispanRegionFactory"/>

Мы также можем настроить политику выселения (здесь «Наименее недавно использовавшийся» — LRU), добавив следующие свойства:

01
02
03
04
05
06
07
08
09
10
<property name="hibernate.cache.infinispan.entity.eviction.strategy"
 value= "LRU"/>
<property name="hibernate.cache.infinispan.entity.eviction.wake_up_interval"
 value= "2000"/>
<property name="hibernate.cache.infinispan.entity.eviction.max_entries"
 value= "5000"/>
<property name="hibernate.cache.infinispan.entity.expiration.lifespan"
 value= "60000"/>
<property name="hibernate.cache.infinispan.entity.expiration.max_idle"
 value= "30000"/>

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

  • Свойство «wake_up_interval» определяет, как часто процесс контроллера будет сканировать кэш второго уровня для записей кандидатов на выселение (здесь каждые 2 секунды)
  • Свойство max_entries определяет максимальное количество записей в кэше
  • Свойство продолжительности жизни определяет максимальное время, в течение которого объект может храниться в кэше. Если срок службы объекта достигнут, то объект выселяется независимо от того, как часто осуществляется доступ (здесь 1 минута)
  • Свойство max_idle определяет максимальный период времени, в течение которого объект может бездействовать (не быть доступным) до выселения (здесь 30 секунд).

Наконец, мы должны изменить атрибут «постоянного элемента» «тип транзакции» на JTA

Полный файл persistence.xml должен выглядеть так, как показано ниже:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
version="2.0">
 
 <persistence-unit name="MyPersistenceUnit" transaction-type="JTA">
  <provider>org.hibernate.ejb.HibernatePersistence</provider>
 
  <properties>
   <property name="hibernate.hbm2ddl.auto" value="update" />
   <property name="hibernate.show_sql" value="false" />
   <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
 
   <property name="hibernate.transaction.manager_lookup_class" value="com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup" />
 
   <property name="hibernate.cache.use_second_level_cache" value="true"/>
   <property name="hibernate.cache.use_query_cache" value="true"/>
   <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.infinispan.InfinispanRegionFactory"/>
   <!--
   <property name="hibernate.cache.infinispan.entity.eviction.strategy" value= "LRU"/>
   <property name="hibernate.cache.infinispan.entity.eviction.wake_up_interval" value= "2000"/>
   <property name="hibernate.cache.infinispan.entity.eviction.max_entries" value= "5000"/>
   <property name="hibernate.cache.infinispan.entity.expiration.lifespan" value= "60000"/>
   <property name="hibernate.cache.infinispan.entity.expiration.max_idle" value= "30000"/>
   -->
 
  </properties>
 
 </persistence-unit>
 
</persistence>

Следующим шагом является настройка Spring относительно источника данных JTA , менеджера транзакций Atomikos и JPA / Hibernate . Найдите файл applicationContext.xml в / war / WEB-INF / и измените его следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
 xsi:schemaLocation="
 
 <context:component-scan base-package="com.javacodegeeks.gwtspring" />
 
 <task:annotation-driven executor="myExecutor"
 scheduler="myScheduler" />
 
 <task:executor id="myExecutor" pool-size="5" />
 
 <task:scheduler id="myScheduler" pool-size="10" />
 
 <tx:annotation-driven />
 
 <bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="jpaVendorAdapter">
   <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
  </property>
 </bean>
 
 <bean id="dataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
  init-method="init" destroy-method="close">
  <property name="uniqueResourceName" value="javacodegeeks" />
  <property name="xaDataSourceClassName"
   value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
  <property name="xaProperties">
   <props>
    <prop key="URL">jdbc:mysql://localhost:3306/javacodegeeks</prop>
    <prop key="user">***</prop>
    <prop key="password">***</prop>
   </props>
  </property>
  <property name="maxPoolSize" value="50" />
  <property name="minPoolSize" value="20" />
 </bean>
 
 <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
  init-method="init" destroy-method="close">
  <property name="forceShutdown" value="false" />
 </bean>
 
 <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.J2eeUserTransaction">
  <property name="transactionTimeout" value="300" />
 </bean>
 
 <bean id="transactionManager"
  class="org.springframework.transaction.jta.JtaTransactionManager"
  depends-on="atomikosTransactionManager,atomikosUserTransaction">
  <property name="transactionManager" ref="atomikosTransactionManager" />
  <property name="userTransaction" ref="atomikosUserTransaction" />
  <property name="allowCustomIsolationLevels" value="true" />
 </bean>
 
</beans>

Что следует отметить здесь:

  • Spring Entity Manager Factory содержит ссылки на источник данных и провайдера JPA , чтобы должным образом обеспечить функциональность ORM для наших DAO.
  • Источник данных настроен как ресурс XA. Это обязательно для того, чтобы Infinispan и база данных участвовали в одних и тех же транзакциях, как описано выше. Вы должны изменить значения URL-адреса «xaProperties», свойства пользователя и пароля в соответствии с конфигурацией вашей базы данных.
  • Мы настраиваем Spring для использования JTA- совместимого менеджера транзакций Atomikos .

Мы почти закончили!

Чтобы сделать объект кэшируемым, нам нужно только аннотировать его как таковой. Найдите объект EmployeeDTO в пакете / shared / dto и добавьте аннотацию @Cache, как показано ниже:

01
02
03
04
05
06
07
08
09
10
11
12
import statements here …
 
@Cache (usage=CacheConcurrencyStrategy.TRANSACTIONAL)
@Entity
@Table(name = "EMPLOYEE")
public class EmployeeDTO implements java.io.Serializable {
  
 private static final long serialVersionUID = 7440297955003302414L;
 
 
}

Что следует отметить здесь:

  • Мы определяем стратегию параллельного использования кэша как «TRANSACTIONAL», потому что мы хотим выполнять не только операции извлечения, но и создания / обновления / удаления кэшированного объекта.

Это оно! Для развертывания веб-приложения просто скопируйте папку / war в папку «webapps» Apache — Tomact. Вы можете изменить имя папки war на любое другое, желательно переименовать его после имени проекта, например, GWTSpringInfinispan

Перед запуском приложения не забудьте создать схему базы данных, здесь «javacodegeeks».

Для запуска приложения укажите ваш браузер по следующему адресу

HTTP: // локальный: 8080 / GWTSpringInfinispan /

Если все прошло хорошо, вы должны увидеть свою главную веб-страницу. Должны отображаться два текстовых поля, за которыми следует кнопка. В первом текстовом поле вы можете сохранить или обновить сотрудника в базе данных. Введите в качестве входных данных идентификатор, имя, фамилию и описание задания, разделенные пробелом. При нажатии на кнопку «SaveOrUpdate» предоставленная информация будет сохранена в базе данных. Для существующих записей сотрудников (с тем же идентификатором) будет выполнено обновление. Второе текстовое поле используется для получения существующих записей сотрудников. Введите идентификатор сотрудника и нажмите кнопку «Получить». Если сотрудник существует, вы должны увидеть его идентификатор, имя, фамилию и описание работы.

Диспетчер транзакций Atomikos настроен на создание записей журнала на уровне INFO (см. Файл «jta.properties» выше). Файл журнала находится в каталоге bin вашей установки Apache — Tomcat . Откройте файл и просмотрите запросы, выполненные к базе данных. То, что вы должны ожидать, это следующее:

  • Выполните операцию извлечения сотрудника в первый раз. Объект employee не кэшируется, и к базе данных выполняется запрос. Объект сотрудника теперь должен быть кэширован
  • Выполните вторую операцию получения для того же сотрудника. Никакой запрос не должен быть выполнен сейчас. Данные получены из Infinispan
  • Выполните операцию обновления для того же сотрудника. Операции обновления выполняются как для Infinispan, так и для базы данных за одну единицу работы.
  • Выполните третий запрос для того же сотрудника. Не следует выполнять запросы к базе данных, и вы должны увидеть обновленные данные с предыдущего шага!

Вы можете скачать проект отсюда (необходимые сторонние библиотеки, как описано в начале и предыдущие статьи не включены)

Повеселись!

Джастин

Статьи по Теме :