利用Infinispan数据网格的功能最大化Hibernate性能。 一个GWT , Spring , JPA , Hibernate , Infinispan集成教程。
在本教程中,我们将讨论如何将Infinispan用作Hibernate二级缓存提供程序。 Infinispan是JBoss缓存的继承者,也是公司在开源数据网格领域的旗舰。 为了使事情变得更有趣,我们将从上一篇关于Spring GWT Hibernate和JPA集成的文章的 结尾处继续。 我们将使用我们的GWTSpring项目 ,并使用数据网格功能对其进行授权!
Hiberante从版本3.5开始就支持Infinispan作为二级缓存提供程序,我们将使用Hibernate 3.5.2版本和Infinispan 4.0.0版本。 您可以在此处下载Infinispan二进制发行版
强烈建议将Hibernate配置为使用JTA事务,以便Hibernate和Infinispan在同一事务中合作。 否则,对数据库和二级缓存的操作将不会被视为单个工作单元。 这里的风险包括无法更新第二级高速缓存,而在数据库正确提交数据的同时,旧高速缓存将保留陈旧数据。
由于我们将Web应用程序部署到一个独立的环境( Apache – Tomcat )中,而不是为了完全满足上述要求而部署到一个完全的,启用JTA的应用程序服务器中,因此我们将在Spring中实现JTA环境。框架。 为此,我们需要一个符合JTA的交易管理器,而我们的首选客户是Atomikos 。 当然,您可以使用您喜欢的任何符合JTA的事务管理器。 我们将使用Atomikos Transactions Essentials版本3.6.5,您可以从此处下载
最后但并非最不重要的一点是,我们将需要MySQL Connector / J连接到MySQL数据库进行测试。 Atomikos Transactions Essentials的3.6.5版本已经过测试,可与MySQL Connector / J版本5.1.5很好地兼容,您可以从此处下载
为了在运行时正确集成Infinispan和Hibernate ,我们必须为Web应用程序提供所有必需的库。 因此,复制下面在/ 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
从Atomikos Transactions Essentials发行
- /dist/transactions-essentials-all.jar
- /lib/jca.jar
- /lib/jms.jar
- /lib/jmx.jar
MySQL Connector / J
- mysql-connector-java-5.1.5-bin.jar
最后,为了使Atomikos在运行时正常运行,必须在我们的Web应用程序的类路径上找到一个“ jta.properties”文件。 创建一个名为“ jta.properties”的文本文件,将其放在Eclipse项目的/ resources包下,并使用以下所示的属性进行填充:
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语言和二级缓存。 在/ resources / META-INF文件夹下找到persistence.xml文件,然后执行以下描述的更改:
要使用MySQL语言,请添加以下属性:
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
要配置事务管理器以使用,请添加以下属性:
<property name="hibernate.transaction.manager_lookup_class" value="com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup" />
要启用启用了查询结果缓存的Hibernate二级缓存,您应该添加以下属性:
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
在这一点上,我们必须指出,启用查询结果缓存可能不会提高性能,尤其是在您的应用程序执行主要返回唯一结果的查询的情况下。
要配置Infinispan缓存区域工厂,请添加以下属性:
<property name="hibernate.cache.region.factory_class"
value="org.hibernate.cache.infinispan.InfinispanRegionFactory"/>
我们还可以通过添加以下属性来配置驱逐策略(此处为最近最少使用– LRU):
<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文件应类似于以下提供的文件:
<persistence 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_2_0.xsd"
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>
下一步是配置有关JTA数据源, Atomikos事务管理器和JPA / Hibernate的 Spring 。 在/ war / WEB-INF /下找到您的applicationContext.xml文件,并进行如下更改:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
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/jee http://www.springframework.org/schema/jee/spring-jee-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/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">
<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提供程序的引用,以便为我们的DAO正确提供ORM功能
- 数据源被配置为XA资源。 如上所述,这是强制性的,以便Infinispan和数据库参与相同的事务。 您必须根据数据库配置更改“ xaProperties” URL,用户和密码属性值。
- 我们将Spring配置为使用符合JTA的 Atomikos事务管理器。
我们快完成了!
为了使实体可缓存,我们只需要这样注释即可。 在/ shared / dto包下找到EmployeeDTO对象,并添加@Cache批注,如下所示:
… 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”,因为我们不仅想对缓存的对象执行检索,而且还要执行创建/更新/删除操作。
而已! 要部署Web应用程序,只需将/ war文件夹复制到Apache – Tomact“ webapps”文件夹中。 您可以将war文件夹的名称更改为任何您喜欢的名称,最好在项目名称之后将其重命名,例如GWTSpringInfinispan
在午餐之前,应用程序不要忘记创建数据库模式,这里是“ javacodegeeks”。
午餐应用程序将您的浏览器指向以下地址
http:// localhost:8080 / GWTSpringInfinispan /
如果一切顺利,您应该会看到您的主页。 应该显示两个文本框,每个文本框后面都有一个按钮。 在第一个文本框中,您可以将雇员保存或更新到数据库。 作为输入,提供ID,名称,姓氏和职位描述,并用空格字符分隔。 单击“ SaveOrUpdate”按钮,将提供的信息存储到数据库中。 对于现有员工条目(相同的ID),将执行更新。 第二个文本框用于检索现有员工条目。 提供员工ID,然后单击“检索”按钮。 如果该员工存在,则应该看到该员工的ID,姓名,姓氏和职位描述。
Atomikos事务管理器配置为在INFO级别生成日志记录(请参见上面的“ jta.properties”文件)。 日志文件位于Apache – Tomcat安装的bin目录中。 打开文件并观察对数据库执行的查询。 您应该期望以下内容:
- 第一次对员工执行检索操作。 雇员对象未缓存,并且对数据库执行查询。 现在应该缓存employee对象
- 对同一员工执行第二次检索操作。 现在不应该执行任何查询。 从Infinispan检索数据
- 对同一员工执行更新操作。 在单个工作单元中对Infinispan和数据库执行更新操作
- 对同一员工执行第三次查询。 不应对数据库执行任何查询,并且应该看到上一步中更新的数据!
您可以从此处下载该项目(如开头所述,并且不包含先前的文章,所需的第三方库)
玩得开心!
贾斯汀
- GWT 2 Spring 3 JPA 2 Hibernate 3.5教程
- Spring 3 HornetQ 2.1集成教程
- Spring3 RESTful Web服务
- GWT 2 Spring 3 JPA 2 Hibernate 3.5教程– Eclipse和Maven 2展示
- 带有Spring和Maven教程的JAX–WS
翻译自: https://www.javacodegeeks.com/2010/06/gwt-spring-and-hibernate-enter-world-of.html