Hi
I am testing sample petclinic application with multithreaded environment.
I have written a spring quartz bean which creates 10 threads every 500 seconds, each of them adding a pet to a different owner.
We are using following configuration
Spring 2.5.2
Hibernate 3.2.6ga
SQL Server2005
I am struggling with various errors for last one week.
Initially I used to get deadlocks. I changed soem configurations but now this error.
Code:
org.hibernate.HibernateException: createQuery is not valid without active transaction
at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:297)
at $Proxy15.createQuery(Unknown Source)
at net.site.brandnet.zz.HibernateClinic.findOwners(HibernateClinic.java:66)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:310)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy18.findOwners(Unknown Source)
at net.site.brandnet.zz.MultithreadedApp.init(MultithreadedApp.java:38)
at net.site.brandnet.zz.MultithreadedApp.executeInternal(MultithreadedApp.java:58)
at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:86)
at org.quartz.core.JobRunShell.run(JobRunShell.java:195)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:520)
ApplicationContext.xml
Code:
<bean id="BrandNETDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="defaultAutoCommit" value="true"/>
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
<property name="url" value="jdbc:sqlserver://${jdbc.brandNETDataSource.serverName};databaseName=${jdbc.brandNETDataSource}" />
<property name="username" value="${jdbc.brandNETDataSource.userName}" />
<property name="password" value="${jdbc.brandNETDataSource.password}" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource"><ref local="BrandNETDataSource" /></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.connection.release_mode">on_close</prop>
<prop key="hibernate.connection.autocommit">false</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.connection.pool_size">10</prop>
<prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</prop>
<prop key="hibernate.jdbc.batch_size">0</prop>
<prop key="hibernate.jdbc.use_streams_for_binary">true</prop>
<prop key="hibernate.use_outer_join">true</prop>
<prop key="hibernate.max_fetch_depth">8</prop>
<prop key="hibernate.bytecode.use_reflection_optimizer">false</prop>
<prop key="net.sf.ehcache.configurationResourceName">${net.sf.ehcache.configurationResourceName}</prop>
</props>
</property>
<property name="configLocation"><value>${sessionFactory.configLocation}</value></property>
</bean>
<bean id="petclinic" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref bean="hibernateTransactionManager"/></property>
<property name="target"><ref bean="clinicTarget"/></property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED,ISOLATION_SERIALIZABLE</prop>
</props>
</property>
</bean>
<bean id="clinicTarget" class="net.site.brandnet.zz.HibernateClinic">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
here is my quartz bean configuration
Code:
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="simpleTrigger"/>
</list>
</property>
</bean>
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="jobDetail" ref="jobDetail"/>
<property name="startDelay" value="10000"/>
<property name="repeatInterval" value="500000"/>
</bean>
<bean name="jobDetail"
class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass"
value="net.site.brandnet.zz.MultithreadedApp" />
<property name="jobDataAsMap">
<map>
<entry key="clinic">
<ref bean="petclinic" />
</entry>
</map>
</property>
</bean>
here is my class that creates multiple threads and adds pets to owners.
Code:
package net.site.brandnet.zz;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
import net.site.brandnet.exception.ServiceRuntimeException;
import net.site.brandnet.sponsorship.dao.ISponsoredActivity;
import net.site.services.interfaces.ISponsorshipActivityService;
import org.springframework.scheduling.quartz.QuartzJobBean;
public class MultithreadedApp extends QuartzJobBean {
public static final int threadCount = 10;
private Thread[] threads = new Thread[threadCount];
private Clinic clinic;
public void setClinic(Clinic clinic){
this.clinic = clinic;
}
public void init() throws Exception{
for(int i=1;i<threadCount+1;i++){
Collection<Owner> ownerList = clinic.findOwners("Owner"+i);
if(ownerList != null && ownerList.size()> 0){
continue;
}
Owner owner = new Owner();
owner.setFirstName("Owner"+i);
owner.setLastName("Owner"+i);
clinic.storeOwner(owner);
}
}
public void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
try {
System.out.println(" calling init......");
init();
System.out.println(" Created 10 owners......");
System.out.println(" Creating 10 threads......");
for(int i=0;i<threadCount;i++){
MyThread thread = new MyThread();
thread.setName("Thread_"+(i+1));
thread.setClinic(clinic);
threads[i] = thread;
thread.start();
}
for(int i=0;i<threadCount;i++){
try {
threads[i].join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
}
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
class MyThread extends Thread{
private Clinic clinic;
private Map data;
public void setClinic(Clinic clinic){
this.clinic = clinic;
}
public void setData(Map data){
this.data = data;
}
protected final Log logger = LogFactory.getLog(getClass());
public void run(){
Random random = new Random();
//int index = (int) (5* random.nextDouble()+1);
int index = Integer.parseInt(this.getName().substring(7));
Collection<Owner> ownerlist = clinic.findOwners("Owner"+index);
Collection<PetType> types = clinic.getPetTypes();
if(ownerlist!= null && ownerlist.size()> 0)
{
Owner owner = ownerlist.iterator().next();
PetType type = types.iterator().next();
System.out.println("Thread "+ index +" addign pet to Owner "+owner.getFirstName());
addPet(owner, type);
System.out.println("Thread "+ index +" added pet to Owner "+owner.getFirstName());
}
//}
}
private void addPet(Owner owner, PetType type) {
Collection petList = owner.getPets();
int petCount = petList.size();
Pet pet = new Pet();
clinic.getPetTypes();
pet.setType(type);
pet.setName("Pet"+(petCount+1));
owner.addPet(pet);
clinic.storeOwner(owner);
}
}
}
below is hibernate implementation of clinic
Code:
package net.site.brandnet.zz;
import java.util.Collection;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import net.site.brandnet.zz.Clinic;
import net.site.brandnet.zz.Owner;
import net.site.brandnet.zz.Pet;
import net.site.brandnet.zz.PetType;
import net.site.brandnet.zz.Vet;
import net.site.brandnet.zz.Visit;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
/**
* Hibernate implementation of the Clinic interface.
* <p>
* The mappings are defined in "petclinic.hbm.xml", located in the root of the
* class path.
* <p>
* Note that transactions are declared with annotations and that some methods
* contain "readOnly = true" which is an optimization that is particularly
* valuable when using Hibernate (to suppress unnecessary flush attempts for
* read-only operations).
*
* @author Juergen Hoeller
* @author Sam Brannen
* @author Mark Fisher
* @since 19.10.2003
*/
public class HibernateClinic implements Clinic {
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public Collection<Vet> getVets() {
return sessionFactory.getCurrentSession().createQuery("from Vet vet order by vet.lastName, vet.firstName").list();
}
public Collection<PetType> getPetTypes() {
return sessionFactory.getCurrentSession().createQuery("from PetType type order by type.name").list();
}
public Collection<Owner> findOwners(String lastName) {
return sessionFactory.getCurrentSession().createQuery("from Owner owner where owner.lastName like :lastName")
.setString("lastName", lastName + "%").list();
}
public Owner loadOwner(int id) {
return (Owner) sessionFactory.getCurrentSession().load(Owner.class, id);
}
public Pet loadPet(int id) {
return (Pet) sessionFactory.getCurrentSession().load(Pet.class, id);
}
public void storeOwner(Owner owner) {
// Note: Hibernate3's merge operation does not reassociate the object
// with the current Hibernate Session. Instead, it will always copy the
// state over to a registered representation of the entity. In case of a
// new entity, it will register a copy as well, but will not update the
// id of the passed-in object. To still update the ids of the original
// objects too, we need to register Spring's
// IdTransferringMergeEventListener on our SessionFactory.
Session session = sessionFactory.getCurrentSession();
session.merge(owner);
}
public void storePet(Pet pet) {
sessionFactory.getCurrentSession().merge(pet);
}
public void storeVisit(Visit visit) {
sessionFactory.getCurrentSession().merge(visit);
}
}
Can anybody please help????