Во время написания сервера для броузерной онлайн игрушки, столкнулся с проблемой передачи данных между двумя Hibernate. В этом топике хочу поделится неким решением.
Серверная часть игры крутилась на SmartFoxServer x2, в своем составе имела extension для SmartFoxServer x2 (написанный на Java с применением технологии Hibernate 3.6) и веб админку (написанную на Spring Framework + Spring Security + Hibernate + JSF2).
Веб-админка и Smartfox Extension крутились в разных контейнерах. Задача состояла в том, что б при изменении данных в админке они обновлялись и в SmartfoxServer Extension.
Много бессонных ночей прошло пока я не нашел необходимое решение. Как не удивительно решение было простое. В Hibernate существовал механизм распределенного кеша — Cache Second Level. Так как это единственное средство общения между несколькими образами Hibernate.
Как не странно для кеша второго уровня было разработано достаточно большое количество провайдеров. Для конкретно моей задачи подходил EhCacheProvider. И тут началось самое интересное. Сутки потратил на поиск необходимой документации, чтоб настроить ECHACHE.
Для того, что бы включить Cache Second Level необходимо в настройках hibernate установить параметр.
Теперь нужно настроить EChache, это делается при помощи конфигурационного файла ehcache.xml.
И сообственно сам код конфигурационного файла ehcache.xml.
В консоли появится следующее сообщение показано на рисунке.

Описание задачи
Серверная часть игры крутилась на SmartFoxServer x2, в своем составе имела extension для SmartFoxServer x2 (написанный на Java с применением технологии Hibernate 3.6) и веб админку (написанную на Spring Framework + Spring Security + Hibernate + JSF2).
Веб-админка и Smartfox Extension крутились в разных контейнерах. Задача состояла в том, что б при изменении данных в админке они обновлялись и в SmartfoxServer Extension.
Решение данной задачи
Много бессонных ночей прошло пока я не нашел необходимое решение. Как не удивительно решение было простое. В Hibernate существовал механизм распределенного кеша — Cache Second Level. Так как это единственное средство общения между несколькими образами Hibernate.
Как не странно для кеша второго уровня было разработано достаточно большое количество провайдеров. Для конкретно моей задачи подходил EhCacheProvider. И тут началось самое интересное. Сутки потратил на поиск необходимой документации, чтоб настроить ECHACHE.
Настройка Extension для SmartfoxServer
persistense.xml
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="bigbrother" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.example.DomainSuperClass</class>
<class>com.example.Pecur</class>
<properties>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/example?characterEncoding=UTF-8&autoReconnect=true" />
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
<property name="hibernate.connection.username" value="root" />
<property name="hibernate.connection.password" value="root" />
<property name="hibernate.connection.autoReconnect" value="true" />
<property name="current_session_context_class" value="thread" />
<property name="hibernate.connection.isolation" value="2" />
<property name="hibernate.connection.autoReconnectForPools" value="true" />
<property name="hibernate.connection.is-connection-validation-required" value="true" />
<property name="hibernate.use_sql_comments" value="true" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.c3p0.timeout" value="20" />
<property name="hibernate.c3p0.maxIdleTime" value="20" />
<property name="hibernate.c3p0.idleConnectionTestPeriod" value="20" />
<property name="hibernate.c3p0.max_statements" value="100" />
<property name="hibernate.c3p0.testConnectionOnCheckout" value="true" />
<property name="hibernate.c3p0.preferredTestQuery" value="SELECT 1;" />
<property name="hibernate.c3p0.min_size" value="10" />
<property name="hibernate.c3p0.max_size" value="100" />
<property name="hibernate.c3p0.validate" value="false" />
<!-- EhCache -->
<property name="hibernate.default_batch_fetch_size" value="0" />
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider" />
<property name="hibernate.cache.use_structured_entries" value="true" />
<property name="hibernate.cache.use_second_level_cache" value="true" />
<property name="hibernate.cache.use_minimal_puts" value="true" />
<property name="hibernate.max_fetch_depth" value="1" />
</properties>
</persistence-unit>
</persistence>
Для того, что бы включить Cache Second Level необходимо в настройках hibernate установить параметр.
<property name="hibernate.cache.use_second_level_cache" value="true" />
Теперь нужно настроить EChache, это делается при помощи конфигурационного файла ehcache.xml.
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd">
<diskStore path="java.io.tmpdir/example"/> <!-- Указываем куда будут писаться временные файлы-->
<cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory"
properties="connect=UDP(mcast_addr=230.0.0.1;
mcast_port=55566;
ip_ttl=32;
mcast_send_buf_size=150000;
mcast_recv_buf_size=80000):
PING(timeout=2000;num_initial_members=6):
MERGE2(min_interval=5000;max_interval=10000):
FD_SOCK:VERIFY_SUSPECT(timeout=1500):
pbcast.NAKACK(gc_lag=10;retransmit_timeout=3000):
UNICAST(timeout=5000):
FRAG:
pbcast.GMS(join_timeout=5000;
join_retry_timeout=2000;
shun=false;
print_local_addr=true)"
propertySeparator="::" />
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
diskSpoolBufferSizeMB="30"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
statistics="false"
/>
<cache name="exampleName"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="1000"
timeToLiveSeconds="1000"
overflowToDisk="false">
<cacheEventListenerFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true,
replicateUpdates=true,
replicateUpdatesViaCopy=false,
replicateRemovals=true" />
</cache>
</ehcache>
</code>
<h5>Настройка Hibernate в веб-админке</h5>
Как я уже говорил, что админка крутится на Spring, поэтому все настройки Hibernate будут проводится в конфигурационном файле spring-config.xml
<code><?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:secure="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="com.example">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service" />
</context:component-scan>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>/WEB-INF/db.example.connect.properties</value>
</list>
</property>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="bigbrother" />
<property name="jpaProperties">
<props>
<prop key="hibernate.connection.url">${connectionURL}</prop>
<prop key="hibernate.connection.driver_class">${connectionDriverName}</prop>
<prop key="hibernate.connection.username">${connectionUserName}</prop>
<prop key="hibernate.connection.password">${connectionPassword}</prop>
<prop key="hibernate.dialect">${connectionDialect}</prop>
<prop key="hibernate.hbm2ddl.auto">${hbm2ddl.auto}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.connection.autoReconnect">true</prop>
<prop key="hibernate.connection.autoReconnectForPools">true</prop>
<prop key="hibernate.connection.is-connection-validation-required">true</prop>
<prop key="hibernate.generate_statistics">false</prop>
<!-- EhCache -->
<prop key="hibernate.default_batch_fetch_size">0</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
<prop key="hibernate.cache.use_structured_entries">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_minimal_puts">true</prop>
<prop key="hibernate.max_fetch_depth">1</prop>
</props>
</property>
</bean>
<bean id="jpaTemplate" class="org.springframework.orm.jpa.JpaTemplate">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="jpaDialect" ref="jpaDialect" />
</bean>
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
</beans>
И сообственно сам код конфигурационного файла ehcache.xml.
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd">
<diskStore path="java.io.tmpdir/example2"/>
<cacheManagerPeerProviderFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheManagerPeerProviderFactory"
properties="connect=UDP(mcast_addr=230.0.0.1;
mcast_port=55566;
ip_ttl=32;
mcast_send_buf_size=150000;
mcast_recv_buf_size=80000):
PING(timeout=2000;num_initial_members=6):
MERGE2(min_interval=5000;max_interval=10000):
FD_SOCK:VERIFY_SUSPECT(timeout=1500):
pbcast.NAKACK(gc_lag=10;retransmit_timeout=3000):
UNICAST(timeout=5000):
FRAG:
pbcast.GMS(join_timeout=5000;
join_retry_timeout=2000;
shun=false;
print_local_addr=true)"
propertySeparator="::" />
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
diskSpoolBufferSizeMB="30"
maxElementsOnDisk="10000000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"
statistics="false"
/>
<cache name="exampleName"
maxElementsInMemory="1000"
eternal="false"
timeToIdleSeconds="1000"
timeToLiveSeconds="1000"
overflowToDisk="false">
<cacheEventListenerFactory class="net.sf.ehcache.distribution.jgroups.JGroupsCacheReplicatorFactory"
properties="replicateAsynchronously=true,
replicatePuts=true,
replicateUpdates=true,
replicateUpdatesViaCopy=false,
replicateRemovals=true" />
</cache>
</ehcache>
Как узнать заработал ли EHCACHE
В консоли появится следующее сообщение показано на рисунке.