I try get data through jpa-hibernate, lazy join, but I got an error.
Here my stuff:
Table user_role
user_role_id username ROLE
2 petroff ROLE_ADMIN
Table user
id username password salt email profile phone repassword
6 petroff 12345 ${config.salt} petroff#еуые.com test petroff prifile "" 12345
Part class User
#Entity
#Table(name = "tbl_user")
#Repassword(pass = "password", repass = "repassword")
public class User {
#Id
#Column(name = "id")
private int id;
#NotNull
#Size(min = 2, max = 64)
#Column(name = "username")
private String username;
#NotNull
#Size(min = 2, max = 64)
#Column(name = "password")
private String password;
#Column(name = "salt")
private String salt;
#Email
#Column(name = "email")
private String email;
#NotEmpty
#Column(name = "profile")
private String profile;
private String repassword;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
private Set<UserRole> userRole = new HashSet<UserRole>();
public Set<UserRole> getUserRole() {
return userRole;
}
public void setUserRole(Set<UserRole> userRole) {
this.userRole = userRole;
}
Part class UserRole
#Entity
#Table(name = "user_roles")
public class UserRole {
#Id
#Column(name = "user_role_id")
private Integer userRoleId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "username", nullable = false)
private com.blog.blog.entity.User user;
#Column(name = "role", nullable = false, length = 45)
private String role;
//getter and setter methods
public Integer getUserRoleId() {
return userRoleId;
}
public void setUserRoleId(Integer userRoleId) {
this.userRoleId = userRoleId;
}
call method
#Autowired
UserService us;
#RequestMapping(value = "/test", method = RequestMethod.GET)
public String printHello(ModelMap model, HttpSession session) {
com.blog.blog.entity.User u = us.getByUserName("petroff");
Set<UserRole> userRoles = u.getUserRole();
return "hello";
}
Service
#Service
#Transactional(readOnly = true)
public class UserServiceImpl implements UserService {
#Autowired
private UserRepository userRepository;
#PersistenceContext
private EntityManager entityManager;
#Override
public User addUser(User u) {
User savedUser = userRepository.saveAndFlush(u);
return savedUser;
}
#Override
public void delete(Integer id) {
userRepository.delete(id);
}
#Override
public User editUser(User u) {
return userRepository.saveAndFlush(u);
}
#Override
public List<User> getAll() {
return userRepository.findAll();
}
#Override
public User getByUserName(String name) {
return userRepository.findByUserName(name);
}
}
config file
<?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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="/WEB-INF/config.properties"/>
<context:component-scan base-package="com.blog.blog.service.impl"/>
<jpa:repositories base-package="com.blog.blog.repositories"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.drivers}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
<property name="database" value="MYSQL"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<!-- spring based scanning for entity classes-->
<property name="packagesToScan" value="com.blog.blog.entity"/>
</bean>
<tx:annotation-driven/>
<bean id="userDetailsService"
class="com.blog.blog.service.impl.UserDetailsImpl">
</bean>
<import resource="spring-security.xml"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"/>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<bean id="sessionFactory" class="org.springframework.orm.jpa.vendor.HibernateJpaSessionFactoryBean">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<aop:config>
<aop:pointcut id="userServicePointCut"
expression="execution(* com.blog.blog.service.impl.*Service.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="userServicePointCut"/>
</aop:config>
</beans>
I get User obj
com.blog.blog.entity.User u = us.getByUserName("petroff");
but when i call
Set<UserRole> userRoles = u.getUserRole();
i got an error:
Exception occurred in target VM: failed to lazily initialize a collection of role: com.blog.blog.entity.User.userRole, could not initialize proxy - no Session
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.blog.blog.entity.User.userRole, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:566)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:186)
at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:137)
at org.hibernate.collection.internal.PersistentSet.size(PersistentSet.java:156)
at com.blog.blog.controller.Main.printHello(Main.java:37)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at
You will need to initialize lazy collection in the service if you want to use it on the caller side. Try this
#Override
public User getByUserName(String name) {
User u = userRepository.findByUserName(name);
Hibernate.initialize(u.getUserRole());
return u;
}
There is plenty of discussions on this topic online, look it up if you want more background info on the subject.
Related
I am not able to auto-create table from maven spring mvc.
I was doing a spring mvc project using maven. By far i have got no errors but when i am trying to create table in my database using applicationconfig.xml it is not working. i have searched over the internet but my applicationconfig.xml seems fine to me. I have got no errors. Still the table is not created..
applicationconfig.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:jpa="http://www.springframework.org/schema/data/jpa"
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-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<bean id="entityManager" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.milan.entities" /><!--scans model/entity/domain(name 3 but same) and registers-->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">create-drop</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/inventorymanagement" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManager" />
</bean>
<tx:annotation-driven />
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
</beans>
User Class
package com.milan.entities;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
public class User implements Serializable{
#Id
#Column(name = "USER_ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long userId;
#Column(name = "USERNAME")
private String userName;
#Column(name = "PASSWORD")
private String password;
#Column(name = "IS_ENABLEd")
private boolean isEnabled;
public long getUserId() {
return userId;
}
public void setUserId(long userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isIsEnabled() {
return isEnabled;
}
public void setIsEnabled(boolean isEnabled) {
this.isEnabled = isEnabled;
}
}
There is no error while running the program however the table is not created automatically.
Put #Entity on your User class, if the table still not created try putting below annotations on the class:
#Entity
#Table(name = "`user`")
Could be happening because User is a reserve word in DB.
I use spring data jpa in my web-app, i have entity user
#Entity
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private String password;
private String email;
private Boolean enabled;
private String name;
private String lastname;
private String userRole;
public User() {
}
public User(String password, String email, Boolean enabled, String name, String lastname, String userRole) {
this.password = password;
this.email = email;
this.enabled = enabled;
this.name = name;
this.lastname = lastname;
this.userRole = userRole;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "users_id_seq")
#SequenceGenerator(name="users_id_seq", sequenceName="users_id_seq", allocationSize = 1)
#Column(name = "id", nullable = false)
public Long getId() {
return id;
}
//Other columns
}
And i have UserRepository interface which extends CrudRepository.
When i call method findAll in my Controller, I get this error
01-May-2016 22:45:58.674 WARN [http-nio-8080-exec-3] org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logExceptions SQL Error: 0, SQLState: 42703
01-May-2016 22:45:58.675 ERROR [http-nio-8080-exec-3] org.hibernate.engine.jdbc.spi.SqlExceptionHelper.logExceptions Error: column user0_.id does not exist
Position: 8
My spring-config.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:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<jpa:repositories base-package="com.birthright.repository"/>
<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.birthright.entity"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQL9Dialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<tx:annotation-driven/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.postgresql.Driver"/>
<property name="url" value="jdbc:postgresql://localhost:5432/AutoService"/>
<property name="username" value="postgres"/>
<property name="password" value="root"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf"/>
</bean>
</beans>
My table in postgresql
CREATE TABLE public."user"
(
id integer NOT NULL DEFAULT nextval('users_id_seq'::regclass),
password character varying,
email character varying,
enabled boolean,
name character varying,
lastname character varying,
user_role character varying,
CONSTRAINT users_pkey PRIMARY KEY (id)
)
User is a reserved keyword in PostgreSQL. With a default naming strategy you, probably, had User table name.
Don't know why #Table(name = "user", schema = "public") works. Maybe PostgreSQL doesn't consider public.user as a keyword opposite User.
Please use plural names for tables. And using a system or subsystem prefix for a table name (xxx_users) is a good idea too.
A naming strategy can be used for such approach. Refer this as an example: Hibernate5NamingStrategy
An example of prefixes:
StrategyOptions
I'm trying to learn hibernate and spring. The first thing I want to do is get some data from database using Hibernate.
What I am trying to do is getting all data from data base but I get null pointer exception.
Here is my code;
City.java (under com.hopyar.dao package)
#Entity
#Table(name = "Cities")
public class City implements Serializable{
private static final long serialVersionUID = 2637311781100429929L;
#Id
#GeneratedValue
#Column(name = "c_id")
int id;
#Column(name = "c_name")
String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
CityService.java (under com.hopyar.service package)
#Service
public class CityService {
#PersistenceContext
private EntityManager em;
#Transactional
public List<City> getAllCities(){
List<City> result = em.createQuery("Select c From Cities c", City.class)
.getResultList(); // This is where I get the exeption.
System.out.println();
return result;
}
}
spring-context.xml(under webapp/WEB-INF)
<?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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<!-- Enable annotation-based Spring MVC controllers (eg: #Controller annotation) -->
<mvc:annotation-driven/>
<!-- Classpath scanning of #Component, #Service, etc annotated class -->
<context:component-scan base-package="com.hopyar" />
<!-- Resolve view name into jsp file located on /WEB-INF -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- MySQL Datasource with Commons DBCP connection pooling -->
<bean class="org.apache.commons.dbcp.BasicDataSource" id="dataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/myproject"/>
<property name="username" value="username"/>
<property name="password" value="password"/>
</bean>
<!-- EntityManagerFactory -->
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="persistenceUnit"/>
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- Transaction Manager -->
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!-- Enable #Transactional annotation -->
<tx:annotation-driven/>
</beans>
Main.java(under com.hopyar.test package)
public class Main {
public static void main(String[] args) {
CityService service = new CityService();
List<City> cities = service.getAllCities();
System.out.println(cities.size());
}
}
You are instantiating service as new CityService(), which is wrong because you are bypassing Spring. This means your annotations are not proccessed, and em is null. You need to get your service from spring context.
CityService service = applicationContext.getBean("cityService");
You can try to use autowired annotation on CityService, and Spring will instantiate it.
Here is my jpaContext.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:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.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">
<context:annotation-config />
<context:component-scan base-package="com.pluralsight"/>
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="punit"></property>
<property name="dataSource" ref="dataSource"></property>
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"></property>
</bean>
</property>
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.dialect"
value="org.hibernate.dialect.MySQL5InnoDBDialect">
</entry>
<entry key="hibernate.hbm2ddl.auto" value="none"></entry>
<entry key="hibernate.format_sql" value="true"></entry>
</map>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory"
ref="entityManagerFactory">
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"
value="com.microsoft.sqlserver.jdbc.SQLServerDriver">
</property>
<property name="url"
value="jdbc:sqlserver://123.123.123.123:1433;databaseName=WikiGenome">
</property>
<property name="username" value="xxx"></property>
<property name="password" value="xxx"></property>
</bean>
</beans>
Here is my Disease.java:
#Entity
#Table(name="Disease")
public class Disease {
#Id
#GeneratedValue
#Column(name="DiseaseID")
public int DiseaseID;
#Column(name="Name")
public String Name;
}
Here is my another class:
#Entity
#Table(name="ChrPosDisease")
public class ChrPosDisease implements Serializable{
#Id
#Column(name="chr")
public String chr;
#Id
#Column(name="pos")
public int pos;
#Id
#Column(name="DiseaseID")
public int diseaseID;
}
I am new to hibernate and spring mvc framework and I just follows the guide in the tutorials.
I can query the result by using:
#SuppressWarnings({ "unchecked"})
public List getDiseaseByName(String name) {
Query query = em.createQuery("Select d From Disease d Where d.Name=?1").setParameter(1,name);
List diseaseList=query.getResultList();
return diseaseList;
}
However, when I join two table by DiseaseID, it gives following error.
java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: Path expected for join! [Select d From cuhk.cse.fyp.model.Disease d JOIN ChrPosDisease c Where d.DiseaseID=c.DiseaseID AND d.Name=?1]
I don't got the error when querying the result with one table only.
Here is the code that I used to join that two table:
#SuppressWarnings({ "unchecked"})
public List getJoinDiseaseByName(String name) {
Query query = em.createQuery("Select d From Disease d JOIN ChrPosDisease c Where d.DiseaseID=c.DiseaseID AND d.Name=?1").setParameter(1,name);
List diseaseList=query.getResultList();
return diseaseList;
}
What's wrong?
Thanks for help.
Supplementary:
Updated ChrPosDisease
#SuppressWarnings("serial")
#Entity
#Table(name="ChrPosDisease")
public class ChrPosDisease implements Serializable{
#Id
#Column(name="chr")
public String chr;
#Id
#Column(name="pos")
public int pos;
#Column(name="DiseaseID")
public int diseaseID;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="DiseaseID",nullable=false)
private Disease disease;
}
Updated Disease:
#SuppressWarnings("serial")
#Entity
#Table(name="Disease")
public class Disease implements Serializable{
#Id
#GeneratedValue
#Column(name="DiseaseID")
public int DiseaseID;
#Column(name="Name")
public String Name;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "ChrPosDisease")
private Set<ChrPosDisease> chrPosDisease = new HashSet<ChrPosDisease>();
}
I used above entity and there is exception in deploying.
Do I need to add anything else?
I think you should not use d.ChrPosDisease instead use just ChrPosDisease as d is an alias for only Disease entity.
and it should work.
let me know if it doesn't work.
You should have mapping entry as:
#OneToMany(fetch = FetchType.LAZY, mappedBy = "disease")
private Set<ChrPosDisease> chrPosDisease = new HashSet<ChrPosDisease>();
mappedBy attribute notifies that the field is mapped by that particular entity property. So, this property should be the one on which connects entity on ManyToOne side.
Here Disease has many ChrPosDisease. And ChrPosDisease has one Disease. So mapped by column should be the one by which OneToMany field is bound with property on ManyToOne side.
I'm trying to get EHCache working within my app. First thing I did was adding maven dependency:
pom.xml
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>${hibernate-version}</version>
</dependency>
So far so good, now within my application root-context.xml (SessionFactory is defiend in roout because of OpenSessionInView filter) I added MBean for Hibernate statistics from jConsole and full definition of my sessionFactory:
root-context.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<bean id="jmxExporter"
class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="Hibernate:type=statistics">
<ref local="statisticsBean"/>
</entry>
</map>
</property>
</bean>
<bean id="statisticsBean" class="org.hibernate.jmx.StatisticsService">
<property name="statisticsEnabled" value="true"/>
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="namingStrategy" class="com.execon.OracleNamingStrategy"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="oracle.jdbc.OracleDriver"/>
<property name="jdbcUrl" value="jdbc:oracle:thin:#127.0.0.1:1521:orcl"/>
<property name="user" value="xxx"/>
<property name="password" value="xxx"/>
<property name="maxPoolSize" value="10"/>
<property name="maxStatements" value="0"/>
<property name="minPoolSize" value="5"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="namingStrategy" ref="namingStrategy"/>
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:hibernate.cfg.xml"/>
<property name="packagesToScan" value="com.execon.models"/>
</bean>
</beans>
Time to define hibernate.cfg.xml and ehcache file, so here they are:
hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.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.provider_configuration_file_resource_path">ehcache.xml</property>
<property name="hibernate.generate_statistics">true</property>
</session-factory>
</hibernate-configuration>
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">
<diskStore path="java.io.tmpdir"/>
<defaultCache
eternal="false"
maxElementsInMemory="1000"
maxElementsOnDisk="10000"
overflowToDisk="true"
diskPersistent="true"
timeToLiveSeconds="300"
/>
</ehcache>
Everything is working great, so now its time to define some Service to test cache, so I did:
#Service
#Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS)
#Transactional(readOnly = true)
public class MyService
{
#Autowired
private SessionFactory sessionFactory;
#SuppressWarnings("unchecked")
#Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
public List<SettlementModelGroup> getModelGroups()
{
List<SettlementModelGroup> list = new ArrayList<SettlementModelGroup>();
Session session = sessionFactory.getCurrentSession();
Query query = session.createQuery( "from SettlementModelGroup" );
list.addAll( query.list() );
return list;
}
}
As you can see, this basic method alwas returns me same list. So I'm checking hibernate statistics and:
secondLevelCacheHitCount 0
secondLevelCacheMissCount 0
secondLevelCachePutCount 0
Rest of the statistics on screen:
Link if too small: http://s11.postimage.org/yfg9h6m83/image.jpg
So whats wrong, did I miss something (obvious)? Or am I going completly wrong way?
EDIT
SettlementModelGroup Entity (tried also CacheConcurrencyStrategy.READ_WRITE)
#Entity
#Table(name = "MODEL_GROUP")
#Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
public class SettlementModelGroup implements Serializable
{
#Id
#GeneratedValue(generator = "MODEL_GROUP_SEQ", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "MODEL_GROUP_SEQ", sequenceName = "SEQ_MODEL_GROUP_MODEL_GROUP_ID")
#Column(name = "MODEL_GROUP_ID", nullable = false)
private Integer modelId;
#Column(name = "NAME", nullable = false)
private String modelGroupName;
#Column(name = "DESCRIPTION", nullable = false)
private String modelGroupDescription;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "MODEL_GROUP_TYPE_ID", nullable = false)
private SettlementModelGroupType settlementModelGroupType;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PERIOD_TYPE_ID", nullable = false)
private PeriodType periodType;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "DOMAIN_ID")
private Domain domain;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "OWNER_ID", nullable = false)
private User user;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "modelId")
#Cascade(CascadeType.ALL)
private List<SettlementModel> settlementModels;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "STATUS_ID")
private Status status;
//getters and setters here
}
Put #Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL) on SettlementModelGroup (your domain entity) not the service method.
Also see this link. Depending on your version of EhCache (2.4.3.?) you might have to use CacheConcurrencyStrategy.READ_WRITE.