介绍
这是一个集成二级缓存(确切的说是ehcache)和spring3以及hibernate4.1的一个快速指导
下边是所使用的api的版本和框架的版本
Java 1.6
Spring 3.2.8.RELEASE
Hibernate 4.2.11.FINAL
Mysql 5
JUnit 4.11
警告:使用Java 8会导致 “org.springframework.core.NestedIOException: ASM ClassReader failed to parse class file – probably due to a new Java class file version that isn’t supported yet …”
警告:使用hibernate4.3.x会导致 “ERROR SessionFactoryImpl:1518 – HHH000302: Unable to construct current session context [org.springframework.orm.hibernate4.SpringSessionContext]java.lang.reflect.InvocationTargetException”
在这个指导里边你将会看到:
使用spring和junit进行测试,以及application加载
dao和service分层
使用ehcache作为二级缓存
spring缓存
spring3+hibernate4+ehcache集成
hibernate统计
many-to-many映射关系
DB表
CREATE DATABASE `learn` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci'; USE `learn`;
项目结构
依赖(pom.xml)
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>info.hevi.learn</groupId> <artifactId>spring-hibernate-ehcache</artifactId> <version>1.0</version> <description>Annotation Based Spring 3 + Hibernate 4 + EHCache + log4j Demo</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.mainClass>info.hevi.learn.spring3hibernate4ehcache.Main</project.build.mainClass> <java.version>1.6</java.version> <spring.version>3.2.8.RELEASE</spring.version> <hibernate.version>4.2.11.Final</hibernate.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <!--@Transactional --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-ehcache</artifactId> <version>${hibernate.version}</version> </dependency> <!-- connection pooling with c3p0 --> <dependency> <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> <version>0.9.1.2</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.27</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.1</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> <scope>test</scope> </dependency> </dependencies> <repositories> <repository> <id>JBoss repository</id> <url>http://repository.jboss.org/nexus/content/groups/public/</url> </repository> <repository> <id>java.net-Public</id> <url>https://maven.java.net/content/groups/public/</url> </repository> </repositories> </project>
Bean以及hibernate定义(applicationContext.xml)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" 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" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd"> <!-- Autowired --> <!-- used to activate annotations in beans already registered in the application context (no matter if they were defined with XML or by package scanning) --> <context:annotation-config/> <!-- scans packages to find and register beans within the application context. --> <context:component-scan base-package="info.hevi.learn.spring3hibernate4ehcache"/> <!-- enable @Transactional Annotation --> <tx:annotation-driven transaction-manager="transactionManager"/> <!--spring cache--> <bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager"> <property name="caches"> <set> <bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="task" /> </set> </property> </bean> <!-- @PersistenceUnit annotation --> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/> <!-- classpath*:*.properties--> <context:property-placeholder location="classpath:db.properties"/> <!-- data source with c3p0 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" p:driverClass="${jdbc.driverClassName}" p:jdbcUrl="${jdbc.url}" p:user="${jdbc.username}" p:password="${jdbc.password}" p:acquireIncrement="${c3p0.acquire_increment}" p:minPoolSize="${c3p0.min_size}" p:maxPoolSize="${c3p0.max_size}" p:maxIdleTime="${c3p0.max_idle_time}" p:unreturnedConnectionTimeout="${c3p0.unreturned_connection_timeout}"/> <!-- Hibernate as JPA vendor--> <bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" p:database="${jpa.database}" p:showSql="${jpa.showSql}"/> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="hibernateProperties"> <props> <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop> <prop key="hibernate.dialect">${hibernate.dialect}</prop> <!--<prop key="hibernate.connection.autocommit">${hibernate.connection.autocommit}</prop>--> <prop key="hibernate.cache.use_second_level_cache">true</prop> <prop key="hibernate.cache.use_query_cache">true</prop> <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop> <prop key="hibernate.show_sql">true</prop> <!--useful for debugging--> <prop key="hibernate.generate_statistics">true</prop> </props> </property> <property name="packagesToScan" value="info.hevi.learn.spring3hibernate4ehcache"/> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> </beans>
Ehcache cache definitions (ehcache.xml)
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false"> <diskStore path="cacheIO" /> <defaultCache maxElementsInMemory="10000" eternal="true" overflowToDisk="false" diskPersistent="false" diskExpiryThreadIntervalSeconds="1800" memoryStoreEvictionPolicy="FIFO"> </defaultCache> <cache name="info.hevi.learn.spring3hibernate4ehcache.domain.Country" maxElementsInMemory="300" eternal="true" overflowToDisk="false" timeToIdleSeconds="12000" timeToLiveSeconds="12000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> <cache name="countryCache" maxElementsInMemory="300" eternal="true" overflowToDisk="false" timeToIdleSeconds="12000" timeToLiveSeconds="12000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> <cache name="countryByNameCache" maxElementsInMemory="300" eternal="true" overflowToDisk="false" timeToIdleSeconds="12000" timeToLiveSeconds="12000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> </ehcache>
类图
测试文件
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"/applicationContext.xml"}) public class MainTest { @Autowired ILanguageService languageService; @Autowired ICountryService countryService; @After public void cleanup() { Logger rootLogger = Logger.getRootLogger(); rootLogger.setLevel(Level.ERROR); countryService.deleteAll(); languageService.deleteAll(); } @Before public void setup() { Logger rootLogger = Logger.getRootLogger(); Level level = rootLogger.getLevel(); rootLogger.setLevel(Level.ERROR); Language english = new Language("english"); Language french = new Language("french"); Language german = new Language("german"); Language spanish = new Language("spanish"); Language turkish = new Language("turkish"); Language finnish = new Language("finnish"); languageService.save(english); languageService.save(french); languageService.save(german); languageService.save(spanish); languageService.save(turkish); languageService.save(finnish); Country uk = new Country("uk"); Country us = new Country("us"); Country tr = new Country("tr"); Country es = new Country("es"); Country sw = new Country("sw"); Country fn = new Country("fn"); Country gr = new Country("gr"); countryService.save(uk); countryService.save(us); countryService.save(tr); countryService.save(es); countryService.save(fn); countryService.save(sw); countryService.save(gr); Country country = countryService.getByName("gr"); // adding some languages to Greece country.getLanguages().add(english); country.getLanguages().add(finnish); country.getLanguages().add(french); country.getLanguages().add(turkish); countryService.save(country); rootLogger.setLevel(level); } @Test public void testCache() { countryService.getAll(); countryService.getByName("gr"); countryService.getAll(); } }