Deadlock caused by EntityManager using dependency injection - java

I am developing an application with REST services. I am using dependency injection to, among other things, inject EntityManagerFactory. I have a heavy process where I want to use threads, but it is giving me a deadlock when using EntityManager. The code:
Note: All code has been simplified and renamed classes to explain the problem
persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
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">
<persistence-unit name="mypersistenceunit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!-- Entities -->
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.event.merge.entity_copy_observer" value="allow" />
<property name="hibernate.connection.autocommit" value="false"/>
</properties>
</persistence-unit>
</persistence>
applicationContext.xml:
<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:jee="http://www.springframework.org/schema/jee"
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-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
"
default-autowire="byName">
<context:property-placeholder location="classpath:database.properties"/>
<bean id="logDao" class="my.package.example.dao.LogDao">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="extractDataDao" class="my.package.example.source.ExtractDataDao">
<property name="completeDatabaseModel" ref="completeDatabaseModel"/>
</bean>
<bean id="completeDatabaseModel" class="my.package.example.source.CompleteDatabaseModel">
<property name="logDao" ref="logDao" />
</bean>
<bean id="fill" class="my.package.example.services.impl.FillDatabaseServiceImpl">
<property name="extractDataDao" ref="extractDataDao" />
</bean>
<!-- Configuracion de acceso a base de datos -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="persistenceUnitName" value="mypersistenceunit"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
</bean>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
</bean>
<bean id="myDataSource" parent="dataSource">
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
FillDatabaseServiceImpl.java:
public class FillDatabaseServiceImpl implements FillDatabaseService {
private ExtractDataDao extractDataDao;
private final static Gson gson = new Gson();
#Override
public Response start() {
ResultDto resultDto = new ResultDto();
Thread thread = new Thread(this.extractDataDao);
thread.start();
resultDto.setData("Process has started");
return Response.ok(gson.toJson(resultDto)).build();
}
public void setExtractDataDao(ExtractDataDao extractDataDao) {
this.extractDataDao = extractDataDao;
}
}
ExtractDataDao.java:
public class ExtractDataDao implements Runnable {
private CompleteDatabaseModel completeDatabaseModel;
#Override
public void run() {
// Very simplifed class
int numThreads = 5;
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
for (int j = 0; j < numThreads; j++) {
executor.execute(this.completeDatabaseModel);
}
}
public void setCompleteDatabaseModel(CompleteDatabaseModel completeDatabaseModel) {
this.completeDatabaseModel = completeDatabaseModel;
}
}
CompleteDatabaseModel.java
public class CompleteDatabaseModel implements Runnable {
private EntityManagerFactory entityManagerFactory;
private LogDao logDao;
#Override
public void run() {
// Very simplified class
EntityManager entityManager = null;
try {
entityManager = this.entityManagerFactory.createEntityManager();
...
this.logDao.insertLog("Test message", CATEGORY);
...
this.getCountry(entityManager, "country")
} finally {
entityManager.close();
}
}
private synchronized Country getCountry(final EntityManager entityManager, String strCountry) {
Country country = Country.getCountryByCountry(entityManager, strCountry);
if (country == null) {
country = ImdbToMovieDatabase.convert(strCountry, Country.class);
entityManager.getTransaction().begin();
entityManager.persist(country);
entityManager.getTransaction().commit();
country = Country.getCountryByCountry(entityManager, strCountry);
}
return country;
}
public void setLogDao(final LogDao logDao) {
this.logDao = logDao;
}
}
And the classes that provoke deadlock:
LogDao.java:
public class LogDao {
private EntityManagerFactory entityManagerFactory;
public void insertLog(final String message, final Category.CategoryName categoryName) {
Log log = new Log();
EntityManager entityManager = this.entityManagerFactory.createEntityManager();
try {
entityManager.getTransaction().begin();
Category category = Category.getCategoryByName(entityManager, categoryName.name());
log.setCategory(category);
log.setLog(message);
entityManager.persist(log); // // Cause of deadlock in Thread-1 (for example)
entityManager.getTransaction().commit();
} catch (Exception e) {
logger.error("Error persisting log [" + message + "]", e);
entityManager.getTransaction().rollback();
} finally {
if (entityManager != null) {
entityManager.close();
}
}
}
public void setEntityManagerFactory(final EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
}
Entity.java:
public static Country getCountryByCountry(final EntityManager entityManager, final String strCountry) {
Country country = null;
try {
TypedQuery<Country> typedQuery =
entityManager.createQuery(
"SELECT c FROM Country c WHERE country = ?",
Country.class);
typedQuery.setParameter(1, strCountry);
country = typedQuery.getSingleResult(); // Cause of deadlock in Thread-2 (for example)
} catch (NoResultException e) {
System.out.println("No data found for " + strCountry);
} catch (Exception e) {
e.printStackTrace();
}
return country;
}
Maybe private synchronized Country getCountry is provoking the deadlock? I don't think I should, since logDao has injected its own EntityManagerFactory
Can I use a connection pool?
Thanks in advance.

Related

spring Quartz scheduler not accessing database

here is my 'GenericQuartzJob' class
public class GenericQuartzJob extends QuartzJobBean
{
private String batchProcessorName;
public String getBatchProcessorName() {
return batchProcessorName;
}
public void setBatchProcessorName(String name) {
// System.out.println("jo"+name);
this.batchProcessorName = name;
}
protected void executeInternal(JobExecutionContext jobCtx) throws JobExecutionException
{
try {
// System.out.println("jo");
SchedulerContext schedCtx = jobCtx.getScheduler().getContext();
ApplicationContext appCtx =
(ApplicationContext) schedCtx.get("applicationContext");
java.lang.Runnable proc = (java.lang.Runnable) appCtx.getBean(batchProcessorName);
proc.run();
}
catch (Exception ex) {
// ex.printStackTrace();
throw new JobExecutionException("Unable to execute batch job: " + batchProcessorName, ex);
}
}
}
Here is my MyRunnableJob Class
#Configuration
#ComponentScan("com.ehydromet.service")
public class MyRunnableJob implements Runnable {
//#Resource private SpringService myService;
#Autowired
public UserService service;
#Override
public void run() {
// System.out.println("hu");
try{
service.getAllAdminUser();
}catch(Exception ex){
System.out.println(ex.getMessage()+" MyRunnableJob");
}MqttImplement mqtt=new MqttImplement();
mqtt.publishMessage();
//Run the Job. This code will run in the Spring context so you can use injected dependencies here.
}
}
Below is my MqttImplement class
public class MqttImplement implements MqttCallback {
#Autowired
private static UserService service;
#RequestMapping("/publish")
public void publishData(ModelMap map){
MyTask.map=map;
pubTopic="tmsdata";
susTopic="tmsack";
if(initializeMqTTParameters() ){
if(suscribeForAck()){
// new ClassPathXmlApplicationContext("spring-quartz.xml");
AbstractApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
}
}
// initializeMqTTParameters();
// suscribeForAck();
// publishMessage();
}
public void publishMessage(){
try{
// System.out.print("sending ");
Received received=service.getReceivedDataToPublishTMS();
if(received!=null){
System.out.print("sending you not null");
String publisgMSG=createMessageToPublish(received);
pubMessage="lava," ;
publishMessageTms();
}else{
System.out.println("null hora");
}
}catch(Exception ex){
System.out.println("hora"+ex.getLocalizedMessage()+" "+ex.toString());
}
}
}
and here is 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: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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- <bean id="exampleBusinessObject" class="com.ehydromet"/> -->
<!-- Old JobDetail Definition
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="exampleBusinessObject"/>
<property name="targetMethod" value="doIt"/>
</bean>
-->
<!-- Runnable Job: this will be used to call my actual job. Must implement runnable -->
<bean name="myRunnableJob" class="com.ehydromet.controller.MyRunnableJob"></bean>
<!-- New Clusterable Definition -->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="com.ehydromet.schedule.GenericQuartzJob" />
<property name="jobDataAsMap">
<map>
<entry key="batchProcessorName" value="myRunnableJob" />
</map>
</property>
</bean>
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<!-- see the example of method invoking job above -->
<property name="jobDetail" ref="jobDetail"/>
<!-- 10 seconds -->
<property name="startDelay" value="5000"/>
<!-- repeat every 50 seconds -->
<property name="repeatInterval" value="5000"/>
</bean>
<context:component-scan base-package="com.ehydromet.service"/>
<context:component-scan base-package="com.ehydromet.dao"/>
<context:component-scan base-package="com.ehydromet.service.impl"/>
<context:component-scan base-package="com.ehydromet.dao.impl"/>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.ehydromet.entity.Alarms</value>
<value>com.ehydromet.entity.UserData</value>
<value>com.ehydromet.entity.ModemInfo</value>
<value>com.ehydromet.entity.Received</value>
<value>com.ehydromet.entity.Modems</value>
<value>com.ehydromet.entity.AdminLogin</value>
<value>com.ehydromet.entity.UserPolicy</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
</props>
</property>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
<property name="triggers">
<list>
<ref bean="simpleTrigger" />
</list>
</property>
<!-- Add this to make the Spring Context Available -->
<property name="applicationContextSchedulerContextKey"><value>applicationContext</value></property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/ejava" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="hibernateInterceptor" class="org.springframework.orm.hibernate3.HibernateInterceptor">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
</beans>
Dao classes are #Transactional and #Repository.
in MqttImplement class service object is null i think autowired is not working with Quartz scheduler. Any suggestion????
i think autowired is kind of resolved. but
error is-- org.springframework.beans.NotWritablePropertyException: Invalid property 'sessionFactory' of bean class [org.springframework.scheduling.quartz.SchedulerFactoryBean]: Bean property 'sessionFactory' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?
i am new to it. so may be some foolish mistakes i have done, please have a look.
Have you tried #Autowired without static? Seems weird for me...
From other side you do this:
MqttImplement mqttPublishTms=new MqttImplement();
................
mqttPublishTms.publishMessage();
So, it's new not Dependency Injection. There is no surprise that the service property there is null.

publish a file and a decryption key to jms queue

I have a requirement to publish an encrypted file (file size can be upto 100 M.B) to a jms queue. Along with the file i have to send a decryption key to the same message which is used by the jms listener to to decrypt file.
I have attached the applicationContext.xml and the jms publisher. Currently i am tryign to use MapMessage to publish both the file and the key, but getting the below error.
2015-12-09 19:31:12,709 INFO [simBatchQueueListener-1] - Received a message for updating organization
2015-12-09 19:31:12,719 DEBUG [simBatchQueueListener-1] - Received a JMS message: Key ->null
2015-12-09 19:31:12,729 DEBUG [simBatchQueueListener-1] - Received a JMS message: File ->null
2015-12-09 19:31:12,729 DEBUG [simBatchQueueListener-1] - Received a JMS message: bytesMessage ->null
weblogic.jms.common.MessageFormatException: [JMSClientExceptions:055130]Invalid data type: java.io.BufferedWriter
at weblogic.jms.common.MapMessageImpl.setObject(MapMessageImpl.java:234)
at com.vodafone.m2m.kssv.jms.JMSNotifier$1.createMessage(JMSNotifier.java:113)
at com.vodafone.m2m.kssv.jms.JMSNotifier$1.createMessage(JMSNotifier.java:106)
at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:602)
at org.springframework.jms.core.JmsTemplate$4.doInJms(JmsTemplate.java:583)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:493)
at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:579)
at com.vodafone.m2m.kssv.jms.JMSNotifier.publishMessage(JMSNotifier.java:106)
at com.vodafone.m2m.kssv.directoryscanner.file.SIMBatchReturnFileProcessor.run(SIMBatchReturnFileProcessor.java:88)
at java.lang.Thread.run(Thread.java:744)
The jms publish should be synchronous. Once the message is read from the queue an ID will be created and the ID need to be acknowledged to the publisher.
As I am new to coding jms could anyone please help me how I can achieve this.
public class JMSNotifier {
private final Logger LOG = LoggerFactory.getLogger(JMSNotifier.class);
private static final String myName = JMSNotifier.class.getSimpleName();
private String filename = null;
private FileInputStream inStream = null;
private BytesMessage bytesMessage = null;
private int bytes_read = 0;
private int BUFLEN = 64;
private byte[] buf1 = new byte[BUFLEN];
private byte[] buf2 = new byte[BUFLEN];
private int length = 0;
private int exitResult = 0;
#Autowired
private JmsTemplate jmsTemplate;
private String simBatchQueue;
private MapMessage m = null;
#Required
public void setSimBatchQueue(String simBatchQueue) {
this.simBatchQueue = simBatchQueue;
}
public synchronized void publishMessage(String destinationName, String msg) throws JMSException {
LOG.debug("Sending message {} on {} queue...", msg.toString(), destinationName);
try {
filename = new String("C:\\Vijay\\cleartext.txt");
inStream = new FileInputStream(filename);
} catch (IOException e) {
System.out.println("Problem getting file: " + e.toString());
System.exit(1);
}
if (Constants.SIM_BATCH_QUEUE.equals(destinationName)) {
destinationName = simBatchQueue;
LOG.trace("{}: Attempting messgage for D_N_SIM_BATCH_QUEUE {} ", myName, simBatchQueue);
} else {
LOG.trace("{}: Unknow JMS destinaion name {} ", myName, destinationName);
throw new JMSException("Unknow JMS destinaion name {}" + destinationName);
}
jmsTemplate.send(destinationName, new MessageCreator() {
#Override
public MapMessage createMessage(Session session) throws JMSException {
try {
m = session.createMapMessage();
m.setObject("file", writeToFile(inStream));
m.setObject("key","123");
return m;
} catch (Exception ex) {
ex.printStackTrace();
return m;
}
}
});
}
public static String prepareNormalDateString() {
Calendar tzCal = Calendar.getInstance();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-ddhhmmss");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
StringBuffer date = new StringBuffer(dateFormat.format(tzCal.getTime()));
date.append("UTC");
return (date.toString());
}
private BufferedWriter writeToFile(InputStream is) {
BufferedReader br = null;
String time = prepareNormalDateString();
String filepath = "C:\\vijay\\File" + time + ".csv";
String line;
BufferedWriter bufferedWriter = null;
try {
bufferedWriter = new BufferedWriter(new FileWriter(filepath));
br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null) {
bufferedWriter.write(line);
}
bufferedWriter.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return bufferedWriter;
}
}
public class SimBatchQueueMessageHandler implements MessageListener {
private static org.slf4j.Logger myLogger = LoggerFactory.getLogger(SimBatchQueueMessageHandler.class);
private String myName = SimBatchQueueMessageHandler.class.getSimpleName();
int bytes_read = 0;
final int BUFLEN = 64;
byte[] buf1 = new byte[BUFLEN];
byte[] buf2 = new byte[BUFLEN];
int length = 0;
int exitResult = 0;
FileOutputStream fos = null;
File newFile = null;
private static int count = 1;
#Override
public synchronized void onMessage(Message message) {
try {
myLogger.info("Received a message for updating organization");
Source source;
count = count + 1;
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
source = new StringSource(textMessage.getText());
myLogger.debug("Text Message received {}", textMessage.getText());
} else if (message instanceof MapMessage) {
MapMessage msg = (MapMessage) message;
myLogger.debug("Received a JMS message: Key ->" + msg.getObject("key"));
myLogger.debug("Received a JMS message: File ->" + msg.getObject("file"));
Object bytesMessage = msg.getObject("file");
myLogger.debug("Received a JMS message: bytesMessage ->" + bytesMessage);
} else if (message instanceof BytesMessage) {
else {
throw new MessageConversionException("Unsupported JMS Message type " + message.getClass() + ", expected instance of TextMessage or BytesMessage for " + message);
}
Object[] params = new Object[]{myName};
} catch (JMSException jmsEx) {
myLogger.error("Error occured while publishing" + jmsEx);
}
}
}
<?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:jms="http://www.springframework.org/schema/jms"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:ws="http://jax-ws.dev.java.net/spring/core"
xmlns:wss="http://jax-ws.dev.java.net/spring/servlet"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd
http://jax-ws.dev.java.net/spring/core
http://jax-ws.java.net/spring/core.xsd
http://jax-ws.dev.java.net/spring/servlet
http://jax-ws.java.net/spring/servlet.xsd">
<!--
Activates various annotations to be detected in bean classes:
Spring's #Required and #Autowired, as well as JSR 250's #Resource.
-->
<context:annotation-config/>
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="org.springframework.util.Log4jConfigurer" />
<property name="targetMethod" value="initLogging" />
<property name="arguments">
<list>
<value>file:///${MYCOMPONENT_CONFIG_PATH}/log4j.properties</value>
</list>
</property>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="searchSystemEnvironment" value="true" />
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>file:///${MYCOMPONENT_CONFIG_PATH}/jdbc.properties</value>
<!--<value>file:///${MYCOMPONENT_CONFIG_PATH}/MYCOMPONENTConfig.xml</value>-->
<value>file:///${MYCOMPONENT_CONFIG_PATH}/MYCOMPONENT.properties</value>
</list>
</property>
</bean>
<!--
Uses Apache Commons DBCP for connection pooling. See Commons DBCP documentation
for the required JAR files. Alternatively you can use another connection pool
such as C3P0, similarly configured using Spring.
-->
<!-- USE FOR GLASSFISH DATABASE POOLING
<bean id="dataSourceMYCOMPONENT" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${MYCOMPONENT.jdbc.dataSource}"/>
</bean>-->
<!-- USE FOR SPRING DATABASE POOLING -->
<bean id="dataSourceMYCOMPONENT" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}"
p:password="${jdbc.password}" >
<property name="defaultAutoCommit" value="false"/>
<property name="maxActive" value="10"/>
<property name="maxIdle" value="5"/>
<property name="minIdle" value="2"/>
<property name="initialSize" value="1"/>
<property name="maxWait" value="500"/>
<property name="testOnBorrow" value ="true"/>
<property name="timeBetweenEvictionRunsMillis" value ="1800000"/>
<property name="minEvictableIdleTimeMillis" value ="300000"/>
</bean>
<bean id="lobHandler" class="org.springframework.jdbc.support.lob.OracleLobHandler" lazy-init="true">
<property name="nativeJdbcExtractor" ref="nativeJdbcExtractor"/>
</bean>
<bean id="dao" class="com.mycompany.m2m.MYCOMPONENT.support.dataaccess.jdbc.JdbcDataAccessObject">
<!-- Must set schemaName before dataSource! -->
<property name="schemaName" value="${jdbc.schema}"/>
<property name="dbUser" value="${jdbc.username}"/>
<property name="dataSource" ref="dataSourceMYCOMPONENT"/>
</bean>
<!-- Ends -->
<!-- USE FOR JMS CONFIGURATION ************************* -->
<bean id="connectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="jndiTemplate" />
<property name="jndiName" value="${MYCOMPONENT.jms.connectionFactory}" />
</bean>
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">${MYCOMPONENT.jndi.initialFactory}</prop>
<prop key="java.naming.provider.url">${MYCOMPONENT.jndi.providerUrl}</prop>
</props>
</property>
</bean>
<bean id="jmsDestinationResolver" class="org.springframework.jms.support.destination.JndiDestinationResolver">
<property name="jndiTemplate" ref="jndiTemplate" />
<property name="cache" value="true" />
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="defaultDestination" ref="simBatchQueue" />
<property name="destinationResolver" ref="jmsDestinationResolver" />
<property name="connectionFactory" ref="connectionFactory" />
<property name="sessionAcknowledgeModeName" value="AUTO_ACKNOWLEDGE" />
<property name="sessionTransacted" value="false" />
</bean>
<bean id="jmsNotifier" class="com.mycompany.m2m.MYCOMPONENT.jms.JMSNotifier">
<property name="simBatchQueue" value="${MYCOMPONENT.jms.simBatchQueue}" />
</bean>
<!-- JMS Message Listener to handle messages from MYCOMPONENT-->
<bean id="simBatchQueueMessageListener" class="com.mycompany.m2m.MYCOMPONENT.jms.listener.SimBatchQueueMessageHandler"/>
<bean id="simBatchQueue" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="jndiTemplate" />
<property name="jndiName" value="${MYCOMPONENT.jms.simBatchQueue}" />
</bean>
<bean id="simBatchQueueListener" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="concurrentConsumers" value="1" />
<property name="connectionFactory" ref="connectionFactory" />
<property name="destination" ref="simBatchQueue" />
<property name="messageListener" ref="simBatchQueueMessageListener" />
<property name="pubSubDomain" value="true"/>
<property name="subscriptionDurable" value="false"/>
<!--<property name="durableSubscriptionName" value="${sasm.jms.orgDurableSubName}"/>-->
</bean>
</beans>

HIBERNATE : TransactionRequiredException: Executing an update/delete query after entityManager.createNativeQuery()

I'm working on a project using Struts, Spring and Hibernate. After clicking on a button, the Struts action leads me through a DS and DAO, in which I try to call a native query to update the DB. Here is the error trace:
javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.ejb.QueryImpl.executeUpdate(QueryImpl.java:48)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:79)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:618)
at org.springframework.orm.jpa.SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:310)
at $Proxy496.executeUpdate(Unknown Source)
at com.my.project.MyDAO.unsubscribe(MyDAO.java:307)
at com.my.project.MyDS.unsubscribe(MyDS.java:507)
at com.my.project.MyDS.updateValue(MyDS.java:784)
at com.my.project.MyAction.handleUpdate(MyAction.java:235)
MyDAO :
public class MyDAO extends
AbstractDAOGenericImpl<MyEntity> {
/** Entity Manager */
#PersistenceContext(unitName = "myPersistenceUnit")
private EntityManager entityManager;
#Transactional(readOnly = false, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
public int unsubscribe(String entityId) throws JrafDaoException {
StringBuilder strQuery = new StringBuilder();
strQuery.append("update MYENTITY set SUBSCRIBE=:subscribe where ENTITY_ID=:entity_id");
final Query myQuery = getEntityManager().createNativeQuery(strQuery.toString(), MyEntity.class);
myQuery.setParameter("subscribe", "N");
myQuery.setParameter("entity_id", entityId);
try {
return myQuery.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
}
In MyDS :
#Autowired
#Qualifier("MyDAO")
private MyDAO myDao;
#Transactional(readOnly = false, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
public int unsubscribe(String entityId) throws JrafDomainException {
return myDao.unsubscribe(entityId);
}
MyAction :
public class MyAction extends DispatchAction {
private MyDS myDS;
// ...
private ActionForward handleUpdate(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
MyForm myForm = (MyForm) form;
myDS.unsubscribe(myForm.getEntityId());
}
}
And application-context-spring.xml :
<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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">
<!-- Enterprise layer's dependencies -->
<bean id="springLocator"
class="com.jraf.bootstrap.locator.SpringLocator">
</bean>
<!-- To precise the persistence configuration name file -->
<bean id="persistenceUnitManager"
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="persistenceXmlLocations">
<list>
<value>/META-INF/persistence-web.xml</value>
</list>
</property>
</bean>
<!-- EntityManagerFactory definition : JPA one -->
<bean id="myEmf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager"
ref="persistenceUnitManager" />
<property name="persistenceUnitName" value="myPersistenceUnit" />
</bean>
<!-- TransactionManager JPA one -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf" />
</bean>
<!-- EntityManagerFactory definition : JPA one -->
<bean id="myEmf2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager" ref="persistenceUnitManager" />
<property name="persistenceUnitName" value="myPersistenceUnit2" />
</bean>
<!-- Transaction Manager definition : JPA one-->
<bean id="myTxManager2" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf2" />
</bean>
<!-- Enable annotation usage for transaction -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="1" />
<property name="maxPoolSize" value="1" />
<property name="queueCapacity" value="1" />
</bean>
<bean id="myDS" class="com.my.internal.MyDS">
<property name="myDao" ref="MyDAO"/>
</bean>
<!-- Enable the annotation usage (bean injection for instance) -->
<context:annotation-config />
</beans>
I'm working on an existing project which is why the unsubscribe function already exists and uses a native query instead of a HQL one. But maybe I should use it instead...?
Thanks for your help.
I also faced the similar issue.
Adding
tx:annotation-driven transaction-manager="transactionManager"
to your spring context xml will resolve the issue.

Rollback not working in jdbc spring programatic transaction

Im unable to get a rollback working in my spring (3.0.5) jdbc application, running on Oracle 11.2
When I throw NoClassesException in the Controller below the row inserted by updatedB() remains in the dB.
I think this is because autoCommit is on (by default) in my dataSource so the commit has already happened and the rollback obviously doesn't work,
but I thought the Spring DataSourceTransactionManager handled all this and enforced the rollback?
Interestingly, when i turn autoCommit off in my dataSource ie comment in the :
"defaultAutoCommit" value="false"
and call the commit explicity myself ie comment in:
this.jdbcTemplate.getDataSource().getConnection().commit();
nothing happens ie the row is not commited at all,so it looks like i've done something stupid.
If someone could please point out this mistake I would be very gratefull
My code is :
public static void main(String[] args) {
String [] configList ={"database.xml","spring.xml"};
ApplicationContext ctx = new ClassPathXmlApplicationContext(configList);
cont = (Controller)ctx.getBean("controller");
cont.transactionTest();
}
// Controller , called from Main()
public class Controller {
private JdbcTemplate jdbcTemplate;
public void transactionTest()
{
int retCode=0;
try {
retCode = updatedB("param1","param2");
//this.jdbcTemplate.getDataSource().getConnection().commit();
throw new NoClassesException();
}catch (NoClassesException e){
System.out.println(e.getMessage() + "2 patents ");
}
}
public int updatedB(String param1,String param2 )
{
int stat = 0;
stat = this.jdbcTemplate.update("INSERT INTO myTable"
+ "(param1,param2)"
+ " VALUES(?,?)" ,
new Object[] { param1,param2});
return stat;
}
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}
public class NoClassesException extends RuntimeException {
public NoClassesException() {
super("Rolled back ");
}
}
and my spring.xml file is:
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.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">
<bean id="controller" class="Controller">
<property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="transaction*" propagation="REQUIRED" rollback-for="NoClassesException" />
<tx:method name="update*" propagation="SUPPORTS" />
<tx:method name="*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="myMethods" expression="execution(* *..Controller.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="myMethods" />
</aop:config>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
and my database.xml file is:
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.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">
<bean id="dataConfigPropertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="searchSystemEnvironment" value="true" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="initialSize" value="2" />
<property name="maxActive" value="2" />
<property name="url" value="my connection details" />
<property name="username" value="xxx" />
<property name="password" value="xxx" />
<!-- <property name="defaultAutoCommit" value="false" /> -->
</bean>
</beans>
Your code should be updated such as
public void transactionTest()
{
int retCode=0;
retCode = updatedB("param1","param2");
//this.jdbcTemplate.getDataSource().getConnection().commit();
throw new NoClassesException();
}
public int updatedB(String param1,String param2 )
{
int stat = 0;
stat = this.jdbcTemplate.update("INSERT INTO myTable"
+ "(param1,param2)"
+ " VALUES(?,?)" ,
new Object[] { param1,param2});
return stat;
}
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
}

Spring-Hibernate - No Session found for current thread

I have a java stuts2 web application using spring and hibernate.
Im getting org.hibernate.HibernateException: No Session found for current thread.
SpringBean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<context:component-scan base-package="org.rohith" />
<context:annotation-config />
<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/company" />
<property name="username" value="root" />
<property name="password" value="password" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>hibernate.cfg.xml</value>
</list>
</property>
</bean>
<!-- <tx:annotation-driven/> -->
<bean id = "transactionManager" class = "org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name = "sessionFactory" ref = "sessionFactory" />
</bean>
<bean id="customerDaoImpl" class="org.rohith.dao.impl.CustomerDaoImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="customerServiceImpl" class="org.rohith.service.impl.CustomerServiceImpl">
<property name="customerDaoImpl" ref="customerDaoImpl"/>
</bean>
</beans>
hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Names the annotated entity class -->
<mapping class="org.rohith.model.Customer"/>
</session-factory>
</hibernate-configuration>
CustomerServiceImpl.java
package org.rohith.service.impl;
import org.rohith.dao.impl.CustomerDaoImpl;
import org.rohith.model.Customer;
import org.rohith.service.CustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class CustomerServiceImpl implements CustomerService {
#Autowired
private CustomerDaoImpl customerDaoImpl;
#Override
public void saveCustomer(Customer customer) {
customerDaoImpl.saveCustomer(customer);
}
public CustomerDaoImpl getCustomerDaoImpl() {
return customerDaoImpl;
}
public void setCustomerDaoImpl(CustomerDaoImpl customerDaoImpl) {
this.customerDaoImpl = customerDaoImpl;
}
}
CustomerDaoImpl.java
package org.rohith.dao.impl;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.rohith.dao.CustomerDao;
import org.rohith.model.Customer;
public class CustomerDaoImpl implements CustomerDao {
private SessionFactory sessionFactory;
#Override
public void saveCustomer(Customer customer) {
Session session = getSession();
session.clear();
try {
session.saveOrUpdate(customer);
session.flush();
} catch (Throwable e) {
throw new RuntimeException(e.getMessage(), e);
}
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public SessionFactory getSessionFactory() {
return this.sessionFactory;
}
public Session getSession() throws HibernateException {
Session sess = getSessionFactory().getCurrentSession();
if (sess == null) {
sess = getSessionFactory().openSession();
}
// Session sess = getSessionFactory().openSession();
return sess;
}
}
CustomerAction.java
public class CustomerAction extends ActionSupport{
private String name;
private String addr1;
private String addr2;
private String city;
private String state;
private CustomerServiceImpl customerServiceImpl;
//Getters and setters
public String execute(){
Customer cust= new Customer();
cust.setName(name);
cust.setAddress1(addr1);
cust.setAddress2(addr2);
cust.setCity(city);
cust.setState(state);
System.out.println(name);
WebApplicationContext webApplicationContext = WebApplicationContextUtils
.getRequiredWebApplicationContext(getRequest().getSession()
.getServletContext());
customerServiceImpl = (CustomerServiceImpl) webApplicationContext.getBean("customerServiceImpl");
customerServiceImpl.saveCustomer(cust);
//saveCust(cust);
return "success";
}
protected HttpServletRequest getRequest() {
return ServletActionContext.getRequest();
}
protected HttpServletResponse getResponse() {
return ServletActionContext.getResponse();
}
}
The Exception I am getting
org.hibernate.HibernateException: No Session found for current thread
org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:978)
org.rohith.dao.impl.CustomerDaoImpl.getSession(CustomerDaoImpl.java:33)
org.rohith.dao.impl.CustomerDaoImpl.saveCustomer(CustomerDaoImpl.java:16)
org.rohith.service.impl.CustomerServiceImpl.saveCustomer(CustomerServiceImpl.java:18)
org.rohith.CustomerAction.execute(CustomerAction.java:36)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:606)
You have a transaction manager specified in your Spring config, but no configuration on when or where to apply transactions.
In your SpringBean.xml you should uncomment <tx:annotation-driven/>:
<tx:annotation-driven transaction-manager="transactionManager"/>
And then you should annotate the CustomerServiceImpl.saveCustomer method as #Transactional:
#Service
public class CustomerServiceImpl implements CustomerService {
...
#Override
#Transactional
public void saveCustomer(Customer customer) {
customerDaoImpl.saveCustomer(customer);
}
...
}
Add the following property in your hibernate.cfg.xml file for Hibernate 4.
<property name="hibernate.current_session_context_class">thread</property>
Add #EnableTransactionManagement annotation in your java configuration file if your configuration based on annotation without xml.
This may help someone
You can add in hibernate.proerties below value. It's worked for me.
hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext
or
hibernate.current_session_context_class=thread

Categories

Resources