I'm working with a spring project using hibernate and look to implement second-level cache using ehcache. I see a number of approaches to this:
spring-modules-cache which introduces the #Cacheable annotation
ehcache-spring-annotations a toolset which aims to be the successor of spring-modules-cache.
Hibernate cache is nicely integrated into hibernate itself to perform caching using e.g., the #Cache annotation.
Programmatic cache using proxies. Annotation based config quickly becomes either limited or complex (e.g., several levels of annotation nesting)
Personally I don't think spring-modules-cache is thorough enough, hence I would probably prefer consider the more actively developed ehcache-spring-annotations. Hibernate cache though seems to be most complete implementation (e.g., both read and write cache etc).
What would motivate which toolset to use? Please share your caching experience ...
Our project uses option 3. We apply annotation org.hibernate.annotations.Cache to entities that we cache in an Ehcache, configure Ehcache using ehcache.xml, and enable and configure the Hibernate second-level cache in hibernate.cfg.xml:
<!-- Enable the second-level cache -->
<property name="hibernate.cache.provider_class">
net.sf.ehcache.hibernate.EhCacheProvider
</property>
<property name="hibernate.cache.region.factory_class">
net.sf.ehcache.hibernate.EhCacheRegionFactory
</property>
<property name="hibernate.cache.use_query_cache">true</property>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.use_structured_entries">true</property>
<property name="hibernate.cache.generate_statistics">true</property>
For most entities, we use cache concurrency strategy CacheConcurrencyStrategy.TRANSACTIONAL:
#Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
Our Maven project uses Hibernate 3.3.2GA and Ehcache 2.2.0:
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.3.2.GA</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<version>3.3.0.ga</version>
<exclusions>
<exclusion>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.2.1.ga</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>ejb3-persistence</artifactId>
<version>3.3.2.Beta1</version>
</dependency>
Spring 3.1 has a new built-in cache abstraction. Read here.
Related
if one uses the spring-boot-starter-data-jpa dependency and extends repository classes by org.springframework.data.jpa.repository.JpaRepository, is this 'plain jpa' or hibernate?
What is the difference?
JPA is an interface and Hibernate is the implementation. By default Spring uses Hibernate as the default JPA vendor. If you prefer, you can use any other reference implementation e.g. EclipseLink for the Java Persistence in your Spring project.
From the docs:
Spring Data JPA aims to significantly improve the implementation of
data access layers by reducing the effort to the amount that’s
actually needed. As a developer you write your repository interfaces,
including custom finder methods, and Spring will provide the
implementation automatically.
Spring Data Jpa acts as high level API and you have to specify what will be the underlying Persistance Provider:
1) Eclipse Link Config
Maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.jpa</artifactId>
</dependency>
Spring Set-up
#SpringBootApplication
public class Application extends JpaBaseConfiguration {
protected Application(DataSource dataSource, JpaProperties properties,
ObjectProvider<JtaTransactionManager> jtaTransactionManagerProvider,
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
super(dataSource, properties, jtaTransactionManagerProvider, transactionManagerCustomizers);
}
#Override
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
return new EclipseLinkJpaVendorAdapter();
}
2) Hibernate Config
Maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
Spring Set-up
#SpringBootApplication
class SimpleConfiguration {}
Thats all there is needed to set-up the hibernate provider. Of course you need to define all the key data source properties inside your
src/main/resources/application.properties
spring.datasource.url = jdbc:mysql://localhost:3306/db
spring.datasource.username = root
spring.datasource.password = root
...
Examples are based on projects defined in (based on https://github.com/spring-projects/spring-data-examples/)
I'm trying to write JUnit Tests for an application that uses JPA with a Hibernate provider.
The way the JPA Context Beans are instantiated in the application is through JNDI names, that are defined in the Server Resources (Tomcat). I can't have that when testing with JUnit, so I have to provide a different context for JPA that is suited to run the tests.
The main problem when writing JUnit tests for an application that was written to be packaged in a WAR and run in a "Server Container", is that you have to replace the javaee-api jars with actual implementations of the APIs, I understand that part.
I use :
#ContextConfiguration(locations = { "classpath:context-config-test.xml" })
to tell Spring to setup a different context configuration XML for the Test.
Now, to the real problem : I'm trying to setup an EMF (EntitiManagerFactory) that uses Hibernate as the "Persistence Provider".
The way the "normal context" does it is via this :
<bean id="MyEntityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="my_pu_name" />
<property name="persistenceXmlLocation" value="classpath:jpa/persistence.xml" />
</bean>
and then in jpa/persistence.xml :
<!-- spring with jta and entity manager factory -->
<persistence-unit name="my_pu_name" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jdbc/my_jndi_db_name</jta-data-source>
<properties>
....
</properties>
</persistence-unit>
And it works fine.
Now the way I'm trying to do it for the "Test Context" is faily close, like this :
<bean id="myEntityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="myDatasource"/>
<property name="persistenceUnitName" value="my_pu_name_test" />
<property name="persistenceXmlLocation" value="classpath:jpa/persistence-test.xml" />
</bean>
Then in jpa/persistence-test.xml :
<persistence-unit name="my_pu_name_test" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<exclude-unlisted-classes/>
<properties>
.....
</properties>
</persistence-unit>
... it seems OK, but I get the exception :
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'myEntityManagerFactory'
defined in class path resource [spring/beans-test.xml]: Invocation of
init method failed; nested exception is java.lang.NoSuchMethodError:
javax.persistence.spi.PersistenceUnitInfo.getValidationMode()Ljavax/persistence/ValidationMode;
I looked around a while, changed the Maven Dependencies to point to Hibernate-Core, which is an Implemenatation of JPA, checked the scopes were OK, and such things... but nothing worked.
After a while looking around I found that
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
was maybe better to use than
<provider>org.hibernate.ejb.HibernatePersistence</provider>
and I thought I found the problem but that didn't fix it...
So I really don't know what else to do now...
Here is the Hibernate-Dependencies i use in my POM :
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.1.Final</version>
<scope>runtime</scope>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
<exclusions>
<!-- slf4j already contained in Tomcat -->
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
<exclusions>
<!-- slf4j already contained in Tomcat -->
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
I also tried commenting the first one but didn't work.
I would really appreciate any help or pointers on this issue...
Thanks and have a nice day :)
So the way I fixed it, since nothing seemed to work on the Maven side of things (no scope I put changed anything, javaee-api was always resolved in the classpath before hibernate-jpa) I downloaded and added the jars in the classpath of my JUnit test manually, putting them before the Maven Dependencies... it's not pretty but it does the trick.
I have a Spring MVC project using Maven.
I am using Spring-data-jpa as one of my dependency:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.10.5.RELEASE</version>
</dependency>
Spring-data-jpa provides the api.
Therefore, I need to add another dependency which implements jpa. However, I am confused about:
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.jpa</artifactId>
<version>2.6.4</version>
</dependency>
and
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.2.2.Final</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.4</version>
</dependency>
What is eclipse.persistence? And the difference with hibernate?
Please help!
Eclipse Persistence (EclipseLink) and Hibernate are both implementations of Java Persistence API, each with their own extra features and often their own bugs. In terms of speed, they're very similar to each-other, compared to the other implementations.
Only one of is used in each persistence unit, defined in META-INF/persistence.xml. Look at yours, inside the persistence-unit->provider node you will find the class that is used.
If it starts with org.hibernate, then you can safely remove the eclipse dependency.
If it starts with org.eclipse, you can remove the hibernate dependency.
If you have multiple persistence units, each one can use a different implementation/provider.
Issues with Hibernate Validator after upgrading from Hibernate 3 to 4 with Spring 4
I took over a very old Java project (rich client, swing, hibernate 3) which has some sort of homegrown Dependency Injection, uses Hibernate 3 and it has manual transaction management. Meaning every freakin DAO method gets a boolean that triggers a session to be opened or not. You can imagine what this means when you touch that fragile construct on many places... Anyhow, I am not here to whine...here's my Problem:
I have to implement a new complex feature and soon had to realize that this whole manual transaction thing gets out of control and I could convince the customer to refactor the whole thing to use Spring transaction mgmt in combination with hibernate 4.
So I started to implement this and after some major issues I came accross, the whole thing now runs but with some more detailed hickups.
One that drives me nuts is Hibernate Validator. The existing implementation is the old fashioned way I guess. All Entity Classes derive from a class named DomainObject which contains a org.hibernate.validator.ClassValidator for all Entities that are existing in the project.
In the entities themselves this validator will be called with .InvalidValues() to verify the fields.
Since I upgraded to Hibernate-Core 4.3.6.Final with Spring 4.2.4.RELEASE I get a lot of issues when Entities are to be validated. I know I am using an old Validator Version but when I upgrade to a higher one, the whole project has countless errors like The type org.hibernate.validator.InvalidValue cannot be resolved. It is indirectly referenced from required .class files but I wasn't able to resolve this with all answers I found on SO for it.
Right now the validation which causes errors runs in a SwingWorker Thread and while debugging it I can see the exception is swallowed somewhere deep in Spring and I don't even get a stacktrace :-(
I assume the issues still comes from a bad combination of the hibernate dependencies but I was really desperate until I got something that work together which
you can see in the pom.xml snippet below.
Here the snippets
<!-- Hibernate Stuff -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.3.6.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.5.6-Final</version>
<!-- Hibernate Core needs a higher version so we exclude this one -->
<exclusions>
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
<version>3.2.0.Final</version>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>4.3.2.Final</version>
</dependency>
<!-- <dependency> -->
<!-- <groupId>org.hibernate</groupId> -->
<!-- <artifactId>hibernate-c3p0</artifactId> -->
<!-- <version>3.6.10.Final</version> -->
<!-- </dependency> -->
<!-- <dependency> -->
<!-- <groupId>javassist</groupId> -->
<!-- <artifactId>javassist</artifactId> -->
<!-- <version>3.12.0.GA</version> -->
<!-- </dependency> -->
<!-- <dependency> -->
<!-- <groupId>c3p0</groupId> -->
<!-- <artifactId>c3p0</artifactId> -->
<!-- <version>0.9.1.2</version> -->
<!-- </dependency> -->
This is the method in all Entities that will be called during validation.
/**
* validate the entity. This method will be called internally before save or
* update to check validity before sql statements
*/
#Override
#Transient
protected InvalidValue[] validate(final String fieldName) {
if (fieldName == null) {
return VALIDATOR_ASSEMBLY_ENTRY.getInvalidValues(this);
} else {
return VALIDATOR_ASSEMBLY_ENTRY.getInvalidValues(this, fieldName);
}
}
Any hints ? If you need more Code, tell me. The whole Spring and Hibernate config is done in Java. No xml.
I fix this with a little workaround. Put this in your pom.xml
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator-legacy</artifactId>
<version>4.0.2.GA</version>
</dependency>
In Hibernate version 3.X it's possible to configure 2 level cache in hibernate.cfg like this:
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
In version 4.3.0 there is no class EhCacheProvider in org.hibernate.cache package.
What is the workaround for this situation?
Thanks
STEP 1 Add EHcache dependency
Hibernate ships with the ehcache library
1.1] Maven Dependency
add maven dependency for Ehcache in your application as
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>[2.0.0]</version>
<type>pom</type>
</dependency>
1.2] Download Jar file
If you are not using maven dependency you can download the jars file from Download URL
add this jar file into lib directory and your project CLASSPATH.
STEP 2 Configuring EhCache
To configure ehcache, you need to do two steps:
2.1] configure Hibernate for second level caching
<property key="hibernate.cache.use_second_level_cache">true</property>
2.2] specify the second level cache provider
Hibernate 3.3 and above
<property name="hibernate.cache.region.factory_class">net.sf.ehcache.hibernate.EhCacheRegionFactory</property>
Hibernate 3.2 and below
<property name="hibernate.cache.region.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</property>
hope this will help you !
Add below depenedency in your pom.
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.1.9.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>4.1.9.Final</version>
<exclusions>
<exclusion>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
</exclusion>
</exclusions>
</dependency>
Refer to this link: https://dzone.com/articles/hibernate-4-and-ehcache-higher