I am trying this and get exception:
java.lang.IllegalStateException: Existing transaction detected in JobRepository. Please fix this and try again (e.g. remove #Transactional annotations from client).
Is there anyone who have encountered this problem?
#Transactional(propagation = Propagation.REQUIRED)
public void method1() // this method must be Transactional
{
... /*code to call JMS services*/
method2();
}
#Transactional(propagation = Propagation.NOT_SUPPORTED)
public void method2()
{
batchService.runJobWithId(123L);
}
Try removing #Transactional(propagation = Propagation.NOT_SUPPORTED) from method2()
I solved this issue like this:
Create a new bean exclusively to launch the batch job.
Add #Transaction(propagation = Propagation.NOT_SUPPORTED) on that bean.
Configure a task executor for spring batch. something like:
spring-batch.xml:
<beans:bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<beans:property name="jobRepository" ref="jobRepository" />
<beans:property name="taskExecutor" ref="taskExecutor" />
</beans:bean>
Application-context.xml
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="50" />
<property name="queueCapacity" value="10" />
<property name="keepAliveSeconds" value="120" />
</bean>
What does the trick is the task executor. If you check your logs spring batch will complain that, since no task executor is defined, it reverts to synchronous task execution, which is on the same thread. Using the configuration above jobs will be launched on a different thread.
Important note
Altough I managed for a while without configuring a taskExecutor, I ran into the twilight zone when I added a JobListener to update my own tables with start and end times for the job. Any DB Updates the jobListener performed would be reverted when the StartJob() call returned. So, I recommend that you execute your jobs in a separated thread. Simpler. Cleaner.
Related
My application is currently using Spring's JdbcTemplate and #Transaction annotation for transaction handling.
I have a method that calls a web service on a single transaction, and I designed it so that exceptions from the web service will rollback all database changes within the transaction.
my question: how can i FLUSH the database changes made before calling my web service?
many thanks
#Autowired
private MyDao dao;
#Transactional
#Override
public void myMethod() {
.....
dao.saveThis(myObjectToSaveIsNotAnIssue);
// I need to FLUSH here in order for my web service to "see" the saved object
callWebservice();
}
My spring config:
<context:component-scan base-package="com.xxx.xxx" />
<context:annotation-config />
<!-- proxy-target-class is set to true to use transactional scope -->
<tx:annotation-driven proxy-target-class="true" transaction-manager="tomcatTransactionManager" />
<bean id="sybaseDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/xxx"/>
<property name="lookupOnStartup" value="true"/>
<property name="proxyInterface" value="javax.sql.DataSource"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="sybaseDataSource"/>
</bean>
<!-- Transaction Manager -->
<bean id="tomcatTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="sybaseDataSource" />
</bean>
JDBC doesn't have any "flushing" concept. The SQL queries are executed when you execute them. Nothing to be flushed is kept in memory.
Your web service won't see anything in database that you hasn't been committed, due to transaction isolation (which is READ_COMMITTED by default). You'll have to set the isolation level to READ_UNCOMMITTED if that's really what you want (in the web service):
#Transactional(isolation = Isolation.READ_UNCOMMITTED)
We can take out callWebservice() method out of transaction in an assembler and then myMethod can called first from assembler, followed by callWebService() method.
And withinCall Webservice method, we can handle the success and failure scenarios. (Eg: update the status)
I am using spring scheduler tasks for calling a method in class after fixed interval like below
<task:scheduled-tasks scheduler="scheduler">
<task:scheduled ref="processScheduledJobs" method="init" fixed-delay=5000/>
Once the scheduler triggers the init method. init method is going to use the thread pool executor to execute all the jobs in the queue.
<bean id="processScheduledJobs" class="XXXX.VV.ProcessScheduledJobs">
<property name="pool" ref="jobExecutorService"" />
</bean>
<bean id="scheduler" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="threadFactory">
<bean class="XXX..VVV.NamingThreadFactory">
<constructor-arg value="thread" />
</bean>
</property>
<property name="corePoolSize" value="16" />
<property name="maxPoolSize" value="64" />
<property name="keepAliveSeconds" value="4" />
<property name="queueCapacity" value="512" />
</bean>
Questions:
is the initial thread which executed the init method wait till all the processing (done by executor service by spawning new threads) in the init method is finished?
Is the pool size attribute for scheduler task is only used for triggering the tasks not for executing or processing the logic inside the triggered task.
Thread belonging to scheduler will submit all jobs to jobExecutorService. Up to 64 of them will begin executing immediately, the rest, up to 512 will end up in queue. As soon as all are submitted - not executed - the init method will exit. This shouldn't take longer than mere milliseconds.
If scheduler is not the same as jobExecutorService - I can't tell this since part of your xml is missing - its threads won't be used for execution of jobs logic.
I implemented a Scheduled Job in Spring, I'm using Spring 3.1.1 with Hibernate and Struts2. The configuration works fine, but I want to change de cron dynamically, so I found several examples but I could not implement them, everywhere are different configurations, I only need to read cron values from the database instead of configuration file. Is this possible somehow?
My configuration now looks like that:
<!-- Scheduler Tasks -->
<bean name="statTask" class="com.bvc.spring.schedulers.MarketStatusJob"></bean>
<!-- Scheduler jobs -->
<bean id="statJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="statTask" />
<property name="targetMethod" value="execute" />
</bean>
<!-- Cron Triggers -->
<bean id="statCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="statJobDetail" />
<property name="cronExpression" value="0 30 12 1/1 * ? *"/>
</bean>
<!-- Triggers -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="statCronTrigger"/>
</list>
</property>
</bean>
Thanks in advance for help guys.
The possibly easiest approach would be, to subclass CronTriggerBean and implement database property resolution in an overridden setCronExpression(..) method, where you go to the database, fetch the desired cron, and call super.setCronExpression(dbValue)
An alternative, harder approach is to implement a PropertyPlaceholderConfigurer that reads them from a database rather than a properties file. It may not be trivial, though. There is no support for that, because it is more customary to read the values from a properties file. Also note that you won't be able to change the cron dynamically during execution.
You dont need to have statCronTrigger, need to implement quartz trigger in your main class
Job detail is fine.
CronTrigger trigger = null;
JobDetail jobD;
//Load context
ApplicationContext context = new ClassPathXmlApplicationContext("YOUR_CONTEXT_FILES.xml");
//Setup JobDetail
jobD = (JobDetail) context.getBean("statJobDetail");
//Setup CronTrigger
try {
trigger = new CronTrigger();
trigger.setName("AppTrigger");
trigger.setGroup(jobD.getGroup());
trigger.setJobName(jobD.getName());
trigger.setJobGroup(jobD.getGroup());
trigger.setCronExpression("*/10 * * * * ?");// you can read this from DB as well or any other configured string
} catch (ParseException e1) {
e1.printStackTrace();
}
//Scheduler
try{
Scheduler scheduler = (Scheduler) context.getBean("Scheduler");
scheduler.scheduleJob(jobD, trigger);
You may add quartz scheduler bean in context
<bean id="Scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"></bean>
I have the following code in a Spring JdbcTemplate based dao -
getJdbcTemplate().update("Record Insert Query...");
int recordId = getJdbcTemplate().queryForInt("SELECT last_insert_id()");
The problem is that my sometimes my update and queryForInt queries get executed using different connections from the connection pool.
This results in an incorrect recordId being returned since MySql last_insert_id() is supposed to be called from the same connection that issued insert query.
I have considered the SingleConnectionDataSource but do not want to use it since it degrades the application performance. I only want single connection for these two queries. Not for all the requests for all the services.
So I have two questions:
Can I manage the connection used by the template class?
Does JdbcTemplate perform automatic transaction management? If i manually apply a transaction to my Dao method does that mean two transactions will be created per query?
Hoping that you guys can shed some light on the topic.
Update - I tried nwinkler's approach and wrapped my service layer in a transaction. I was surprised to see the same bug pop up again after sometime. Digging into the Spring source code i found this -
public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action)
throws DataAccessException {
//Lots of code
Connection con = DataSourceUtils.getConnection(getDataSource());
//Lots of code
}
So contrary to what I thought, there isn't necessarily one database connection per transaction, but one connection for each query executed.
Which brings me back to my problem. I want to execute two queries from the same connection. :-(
Update -
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${db.driver}" />
<property name="url" value="${db.jdbc.url}" />
<property name="username" value="${db.user}" />
<property name="password" value="${db.password}" />
<property name="maxActive" value="${db.max.active}" />
<property name="initialSize" value="20" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
autowire="byName">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRES_NEW" rollback-for="java.lang.Exception" timeout="30" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* service.*.*(..))" />
<aop:pointcut id="pointcut2" expression="execution(* *.ws.*.*(..))" />
<aop:advisor pointcut-ref="pointcut" advice-ref="transactionAdvice" />
<aop:advisor pointcut-ref="pointcut2" advice-ref="transactionAdvice" />
</aop:config>
Make sure your DAO is wrapped in a transaction (e.g. by using Spring's Interceptors for Transactions). The same connection will then be used for both calls.
Even better would be to have the transactions one level higher, at the service layer.
Documentation: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html
Update:
If you take a look at the JavaDoc of the DataSourceUtils.getConnection() method that you referenced in your update, you will see that it obtains the connection associated with the current thread:
Is aware of a corresponding Connection bound to the current thread, for example
when using {#link DataSourceTransactionManager}. Will bind a Connection to the
thread if transaction synchronization is active, e.g. when running within a
{#link org.springframework.transaction.jta.JtaTransactionManager JTA} transaction).
According to this, it should work like you have set it up. I have used this pattern plenty of times, and never ran into any issues like you described...
Please also take a look at this thread, someone was dealing with similar issues there: Spring Jdbc declarative transactions created but not doing anything
This is my approach to do this:
namedJdbcTemplate.execute(savedQuery, map, new PreparedStatementCallback<Object>() {
#Override
public Object doInPreparedStatement(PreparedStatement paramPreparedStatement)
throws SQLException, DataAccessException {
paramPreparedStatement.execute("SET #userLogin = 'blabla123'");
paramPreparedStatement.executeUpdate();
return null;
}
});
I'm developing a web application using Struts2 + Spring, and now I'm trying to add a scheduled task. I'm using Spring's task scheduling to do so. In my applicationContext I have:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
...
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="MYSQL" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
And then I have my DAO that uses this entityManagerFactory:
<bean id="dao" class="data.GenericDAO" />
So this works flawlessly within the web application. But now I have a problem when creating the scheduled task:
<task:scheduled-tasks scheduler="notifier">
<task:scheduled ref="emailService" method="sendMail" fixed-rate="30000" />
</task:scheduled-tasks>
<task:scheduler id="notifier" pool-size="10" />
<bean id="emailService" class="services.emailService" >
<property name="dao" ref="dao" />
</bean>
This executes the method sendMail on my emailService class every 30 seconds. And my emailService has the DAO injected correctly. The thing is that I can fetch objects with my DAO using the findById named queries, but when I try to access any property mapped by Hibernate, such as related collections or entities, I get an "LazyInitializationException: could not initialize proxy - no Session ". I don't know what's wrong, since I believe the scheduled task is being managed by Spring, so it should have no problem using a Spring managed DAO. I must say that I'm using the openSessionInView filter on my struts actions, so maybe I need something similar for this scheduled task.
Any help or suggestion will be appreciated, thanks!
Edit: Finally I found a way to fix this. I changed my regular Dao with one where I can decide when to start and commit the transaction. So before doing anything I start a transaction and then everything works OK. So I still don't know exactly what causes the problem and if someday I'll be able to use my regular DAO, for the moment I'm staying with this solution.
OpenSessionInView won't help you, because you don't have a web context. You need Spring's Declarative Transaction Management.
In most cases, what you need to do is just this XML:
<!-- JPA, not hibernate -->
<bean id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="myTxManager" />
<!-- without backing interfaces you probably also need this: -->
<aop:config proxy-target-class="true">
(Annotate your EmailService class as #Transactional to enable this)