I'm new in kundera. My usecase is with Kundera and MySQL. I'm saving an entity using spring's CrudRepository. ID in that entity is AUTO generated.
Kundera is saving that object successfully in DB. but returning wrong ID. and if I'm using that Id to find the data from DB , it returns null.
Could you please let me know if I'm missing any thing.
Entity Class :
#Entity
#Table(name = "REQUEST_DETAILS")
public class RequestDetails {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID")
protected long id;
#Column(name = "REQUEST_STATUS", nullable = false)
private String requestStatus;
// getter setter
}
MAIN class :
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:/spring/jpa-config.xml");
RequestDetailsRepository repository = context.getBean(RequestDetailsRepository.class);
RequestDetails requestDetails = new RequestDetails();
requestDetails.setRequestStatus("STARTED");
RequestDetails updatedRequest = repository.save(requestDetails);
System.out.println("request id : " + updatedRequest.getId()); // returning wrong ID (probably hashcode of that object)
// Do some operation
RequestDetails details = repository.findOne(updatedRequest.getId()); // returning NULL
}
CRUD Repository :
public interface RequestDetailsRepository extends org.springframework.data.repository.CrudRepository<RequestDetails, Long> {
}
jpa-config.xml :
<beans>
<context:component-scan base-package="com.example.project" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="persistenceUnit"/>
</bean>
<jpa:repositories base-package="com.example.project.repository"/>
</beans>
Persistence.xml :
<persistence>
<persistence-unit name="persistenceUnit">
<provider>com.impetus.kundera.KunderaPersistence</provider>
<properties>
<property name="kundera.client.lookup.class" value="com.impetus.client.rdbms.RDBMSClientFactory" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServer2008Dialect" />
<property name="hibernate.connection.driver_class" value="net.sourceforge.jtds.jdbc.Driver" />
<property name="hibernate.connection.url"
value="jdbc:jtds:sqlserver://10.127.127.215:1433;databaseName=myDB" />
<property name="hibernate.connection.username" value="user" />
<property name="hibernate.connection.password" value="password" />
<property name="hibernate.current_session_context_class"
value="org.hibernate.context.ThreadLocalSessionContext" />
</properties>
</persistence-unit>
</persistence>
Related
I am new to this Hibernate framework and using Hibernate 3 just to start using this framework.
I have a small module that is executing a update query.
public void saveProduct(Product prod) {
String hql = "UPDATE Product set description = :description, price = :price,ctr=ctr+1 WHERE id = :id";
Query query = this.sessionFactory.getCurrentSession().createQuery(hql);
query.setParameter("description", prod.getDescription());
query.setParameter("price", prod.getPrice());
query.setParameter("id", prod.getId());
logger.info(prod.toString());
int result = query.executeUpdate();
logger.info("Rows affected: " + result);
}
These are logs for this particular module and i have issue in this part hibernate is showing two different update queries one without column ctr and other one with column ctr or is it a normal behaviour:
May 23, 2016 5:55:37 PM com.mogae.dashboard.db.dao.ProductDaoImp saveProduct
INFO: Description: test311;Price: 1.7279999999999998
Hibernate:
update
products
set
description=?,
price=?
where
id=?
Hibernate:
update
products
set
description=?,
price=?,
ctr=ctr+1
where
id=?
May 23, 2016 5:55:37 PM com.mogae.dashboard.db.dao.ProductDaoImp saveProduct
INFO: Rows affected: 1
This is my xml configuration for DB connectivity:
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<!-- the parent application context definition for the springapp application -->
<aop:config>
<aop:advisor pointcut="execution(* *..ProductManager.*(..))" advice-ref="txAdvice"/>
</aop:config>
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<bean id="productDao" class="com.mogae.dashboard.db.dao.ProductDaoImp">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>product.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.user}"/>
<property name="password" value="${db.password}"/>
</bean>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:db.properties</value>
</list>
</property>
</bean>
</beans>
and this is my hibernate mapping file :
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.mogae.dashboard.actions.domain.Product" table="products" lazy="false">
<id name="id" column="id" type="int">
<generator class="native">
<param name="sequence">products_id_seq</param>
</generator>
</id>
<property name="description" column="description" type="string" />
<property name="price" column="price" type="double" />
</class>
</hibernate-mapping>
and this is my entity (Product) class:
package com.mogae.dashboard.actions.domain;
import java.io.Serializable;
public class Product implements Serializable {
private static final long serialVersionUID = 1L;
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("Description: " + description + ";");
buffer.append("Price: " + price);
return buffer.toString();
}
private String description;
private Double price;
private int id;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
Please help i have been searching for this issue on the google and various hibernate forums but haven't found one.
I have User class and BattleReportILogItem class. This class (User, BattleReportILogItem) are #Entity.
User have 0..N BattleReportILogItem.
USER
#Entity
#Table(name = DomainConstant.TABLE_USER)
public class User implements Serializable {
#Id
#Column(name = DomainConstant.DOMAIN_USER_ID)
#GeneratedValue
private Long userId;
#ManyToMany(cascade = {CascadeType.ALL})
#JoinTable(name = DomainConstant.VIEW_USER_BATTLE_LOGS, joinColumns = {
#JoinColumn(name = DomainConstant.DOMAIN_USER_ID)}, inverseJoinColumns = {
#JoinColumn(name = DomainConstant.DOMAIN_BATTLE_REPORT_ID)})
private Set<BattleReportILogItem> setOfBattleLogs = new HashSet<>();
....(other stuff, get and set methods...)
BattleReportILogItem
#Entity
#Table(name = DomainConstant.TABLE_BATTLE_REPORT)
public class BattleReportILogItem implements Serializable {
#Id
#GeneratedValue
#Column(name = DomainConstant.DOMAIN_BATTLE_REPORT_ID)
private Long BattleReportILogItemId;
#ManyToMany(mappedBy = "setOfBattleLogs")
private Set<User> setOfBattleLogs = new HashSet<>();
....(other stuff, get and set methods...)
The problem is, that I load User program loads all data in private Set<BattleReportILogItem> setOfBattleLogs = new HashSet<>();. This mean 1 000 000 000 items in my set setOfBattleLogs. I don't want load data to this set. For load data i have BattleReportLogItemDao DAO.
Is there any solution how to NOT LOAD DATA to my set?
I hope, you understand me... :-))
Thank you for your help.
EDIT persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="com.donutek" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.password" value=""/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/db"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
<property name="hibernate.validator.apply_to_ddl" value="true" />
<property name="connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider"/>
<property name="hibernate.c3p0.min_size" value="5"/>
<property name="hibernate.c3p0.max_size" value="20"/>
<property name="hibernate.c3p0.timeout" value="300"/>
<property name="hibernate.c3p0.max_statements" value="50"/>
<property name="hibernate.c3p0.idle_test_period" value="300"/>
</properties>
</persistence-unit>
</persistence>
EDIT 2:
For load user I am using the code:
#Override
public User findByEmail(String email) {
TypedQuery<User> q = em.createQuery("SELECT u FROM " + User.class.getSimpleName() + " u WHERE u.email = :uemail", User.class);
q.setParameter("uemail", email);
try {
return q.getSingleResult();
} catch (NoResultException e) {
return null;
}
}
You can use the parameter fetchtype Lazy. Now your strategy seems to be Eager.
Consider this example in which I have created two JPA entities and used Spring Data JPA repositories to perform simple CRUD -
import java.sql.Timestamp;
import javax.persistence.Version;
#MappedSuperclass
public class AbstractValueObject {
#Id
#GeneratedValue
private Long id;
#Version
#Column(name = "time_stamp")
private Timestamp version;
public Long getId() {
return id;
}
#Override
public String toString() {
if (id == null) {
return "";
}
return id.toString();
}
}
#Entity
#Table(name = "demo")
public class Demo extends AbstractValueObject {
private String name;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "demo")
private List<Owner> owners;
public Demo() {
owners = new ArrayList<>();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Owner> getOwners() {
return Collections.unmodifiableList(owners);
}
public void addOwner(Owner owner) {
this.owners.add(owner);
owner.setDemo(this);
}
public void addAllOwners(List<Owner> owners) {
this.owners.addAll(owners);
for (Owner owner : owners) {
owner.setDemo(this);
}
}
public void update(Demo demo) {
this.setName(demo.getName());
this.owners.clear();
this.addAllOwners(demo.getOwners());
}
}
#Entity
#Table(name = "owner")
public class Owner extends AbstractValueObject {
private String attribute;
#ManyToOne(cascade = CascadeType.ALL, optional = false)
#JoinColumn(name = "demo_id", nullable = false)
private Demo demo;
public String getAttribute() {
return attribute;
}
public void setAttribute(String attribute) {
this.attribute = attribute;
}
public Demo getDemo() {
return demo;
}
public void setDemo(Demo demo) {
this.demo = demo;
}
}
After that, I have created a JPA repository for the Demo entity, extending from JpaRepository -
import org.springframework.data.jpa.repository.JpaRepository;
public interface DemoRepository extends JpaRepository<Demo, Long> {}
Corresponding service implementation -
import javax.annotation.Resource;
import org.springframework.transaction.annotation.Transactional;
public class DemoServiceImpl implements DemoService {
#Resource
private DemoRepository demoRepository;
#Override
#Transactional
public Demo create(Demo demo) {
return demoRepository.save(demo);
}
#Override
#Transactional
public Demo update(long id, Demo demo) {
Demo dbDemo = demoRepository.findOne(id);
if (dbDemo == null) {
return demo;
}
dbDemo.update(demo);
return dbDemo;
}
#Transactional
public void testRun() {
Owner owner = new Owner();
owner.setAttribute("attribute");
Demo demo = new Demo();
demo.setName("demo");
demo.addOwner(owner);
this.create(demo);
demo.setName("another");
this.update(demo.getId(), demo);
}
}
persistence.xml file -
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="jpa-optimistic-locking" transaction-type="RESOURCE_LOCAL">
</persistence-unit>
</persistence>
Spring app-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"
xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.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-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="com.keertimaan.example.jpaoptimisticlocking" />
<jpa:repositories base-package="com.keertimaan.example.jpaoptimisticlocking.repository" />
<bean id="demoService" class="com.keertimaan.example.jpaoptimisticlocking.service.DemoServiceImpl" />
<!-- JPA/Database/Transaction Configuration -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test" />
<property name="user" value="root" />
<property name="password" value="admin123" />
<property name="minPoolSize" value="1" />
<property name="maxPoolSize" value="2" />
<property name="acquireIncrement" value="1" />
<property name="maxStatements" value="5" />
<property name="idleConnectionTestPeriod" value="500" />
<property name="maxIdleTime" value="1000" />
<property name="loginTimeout" value="800" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="jpa-optimistic-locking" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
Now whenever I try to update an entity like this on Windows 7 -
public class App {
public static void main(String[] args) {
DemoService demoService = (DemoService) SpringHelper.INSTANCE.getBean("demoService");
demoService.testRun();
}
}
I get an exception like this -
Exception in thread "main"
org.springframework.orm.ObjectOptimisticLockingFailureException:
Object of class
[com.keertimaan.example.jpaoptimisticlocking.domain.Demo] with
identifier [4]: optimistic locking failed; nested exception is
org.hibernate.StaleObjectStateException: Row was updated or deleted by
another transaction (or unsaved-value mapping was incorrect) :
[com.keertimaan.example.jpaoptimisticlocking.domain.Demo#4] at
org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:228)
at
org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:155)
at
org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:519)
at
org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
at
org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
at
org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:478)
at
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:272)
at
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy31.testRun(Unknown Source) at
com.keertimaan.example.jpaoptimisticlocking.App.main(App.java:9)
Caused by: org.hibernate.StaleObjectStateException: Row was updated or
deleted by another transaction (or unsaved-value mapping was
incorrect) :
[com.keertimaan.example.jpaoptimisticlocking.domain.Demo#4] at
org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:2541)
at
org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3285)
at
org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3183)
at
org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3525)
at
org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:159)
at
org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:463)
at
org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:349)
at
org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350)
at
org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1222)
at
org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:425)
at
org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at
org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:177)
at
org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:77)
at
org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:515)
... 9 more
If I run the same example in Ubuntu, then I get no exception at all and my application completes successfully. Why is that?
I am using Windowsw 7 64-bit edition -
OS Name: Microsoft Windows 7 Enterprise
OS Version: 6.1.7601 Service Pack 1 Build 7601
and my Ubuntu version is 12.04.5 64-bit edition.
JDK used in Windows: jdk7 update 75
JDK used in Ubuntu: jdk7 update 51
MySQL Server version in Windows: 5.6.23-log MySQL Community Server (GPL)
MySQL Server version in Ubuntu: 5.5.41-0ubuntu0.12.04.1 (Ubuntu)
I have a feeling that this is related to the timestamp precision of MySQL 5.6. MySQL 5.6.4 introduced microsecond precision, which will cause a version mismatch, and the locking will fail.
This is not related to your problem directly but in a highly concurrent environment you should not use timestamp as your version as two entity might have the same time! It's better to use a long/int version like below-
#Version
long version;
Also from design perspective please make your super class abstract as well. Can you check if changing these solves your problem?
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.