I have following Thread and transactional method, I have get thrown an exception to test rollback of insertion of DB but notthing is changed. What am I missing?
public class CleaningThread extends Thread {
public void run() {
try {
doJob();
} catch (Exception e) {
e.printStackTrace();
}
}
#Transactional(rollbackFor=Exception.class)
private void doJob() throws Exception {
//INSERT OPERATION
final BatchSqlUpdate bs = new BatchSqlUpdate
bs.flush()
throw new Exception("Custom exception")
//UPDATE
}
}
Application Context:
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>file:conf/offclear.properties</value>
</list>
</property>
</bean>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="cleaningThread" class="CleaningThread" scope="prototype"/>
Using Spring 3.1
You're invoking method doJob() from method run() of the same class. That's why you're working with real method, not proxied one.
Actually, this question was covered in this topic: One Service method invoke inner multiple method for Spring transaction
Related
In my spring project i am using hibernate entitymanager. I have done transaction management in the project like below.
applicationContext.xml
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#xxxx:1527:selva" />
<property name="username" value="xxx" />
<property name="password" value="yyy" />
</bean>
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan">
<list>
<value>com.selva.entity</value>
</list>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="showSql" value="true" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
TestTranService.java
#Transactional
public String checkTranWork() {
try {
testTranDao.method1();
int i=0;
if(i==0)
throw new ValidationException();
testTranDao.method2();
testTranDao.method3();
} catch(Exception e) {
e.printStackTrace();
}
return null;
}
TestTranDaoImpl.java
public class TestTranDaoImpl implements TestTranDao {
public static final Logger LOGGER = Logger
.getLogger(TestTranDaoImpl.class);
#PersistenceContext
private EntityManager entityManager;
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
public EntityManager getEntityManager() {
return entityManager;
}
#Override
public void method1() {
try {
String sql = "INSERT INTO CUST(MOBNUM,CUST_NAME) values ('1','dd')";
Query query = entityManager.createNativeQuery(sql);
query.executeUpdate();
} catch(Exception e) {
e.printStackTrace();
}
}
#Override
public void method2() {
try {
String sql = "INSERT INTO CUST(MOBNUM,CUST_NAME) values ('1','dd')";
Query query = entityManager.createNativeQuery(sql);
query.executeUpdate();
} catch(Exception e) {
e.printStackTrace();
}
}
}
In my code after method 1 executing the insert statement i am throwing the exception so the first statement should be rolled back.But in my case rollback is not happened.Is their any other configuration required for rollback.
Any help will be greatly appreciated!!!
You Catch the Exceptions to log them, but then, you drop them. Don't do that!
An Exception has a meaning in a software, more than for logging, but also for all the framework around it.
Remove the try catch blocks so the #Transactional Aspect around your method can detect there's an error and rollback your transaction.
As explained by Gillaume for #Transactional to work, the method has to throw an exception then only the framework will know that rollback has to be performed.
One solution already suggested is to remove the try/catch and if there is a need to catch the exception and log in application error log file then make sure the exception is propagated not consumed.
So the updated code would look like:
#Transactional
public String checkTranWork() {
try {
testTranDao.method1();
int i=0;
if(i==0)
throw new ValidationException();
testTranDao.method2();
testTranDao.method3();
} catch(Exception e) {
e.printStackTrace();
throw e;
}
return null;
}
I need to read a property value in my UserDetailsDaoImpl. I'm using Spring Security.
It succesfully reads inside of a #Controller but not in this class maybe because it's a #Repository.
What can i do to read the property value?
UserDetailsDaoImpl:
#Repository
public class UserDetailsDaoImpl extends JdbcDaoSupport implements UserDetailsDao {
#Value("${emails_blocked}")
private String emails_blocked;
Beans:
<context:property-placeholder location="classpath:config.properties"/>
edit:
this is how i call UserDetailsDaoImpl:
#Autowired
UserDetailsDao userDetailsDao;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
try {
Authentication auth = super.authenticate(authentication);
// if reach here, means login success, else exception will be thrown
// reset the user_attempts
userDetailsDao.resetFailAttempts(authentication.getName());
return auth;
} catch (BadCredentialsException e) {
userDetailsDao.updateFailAttempts(authentication.getName());
throw e;
}
my beans updated:
<beans:bean id="userDetailsDao" class="com.setelog.spring.dao.UserDetailsDaoImpl" >
<beans:property name="dataSource" ref="dataSource" />
</beans:bean>
<beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
<beans:bean id="authenticationProvider"
class="com.setelog.spring.handler.LimitLoginAuthenticationProvider">
<beans:property name="userDetailsService" ref="customUserDetailsService" />
<beans:property name="userDetailsDao" ref="userDetailsDao" />
<beans:property name="passwordEncoder" ref="encoder" />
</beans:bean>
My Problem was that since i called a method it wouldn't load the #Value so i had to inject some beans.
Like this:
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:config.properties</value>
</list>
</property>
</bean>
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="com.setelog.spring.dao.UserDetailsDaoImpl.setEmails_Blocked"/>
<property name="arguments">
<list>
<value>${emails_blocked}</value>
</list>
</property>
</bean>
my UserDetailsDaoImpl:
static String emails_blocked;
public static void setEmails_Blocked(String emails_blocked){
UserDetailsDaoImpl.emails_blocked= emails_blocked;
}
This Answer helped me a lot:
https://stackoverflow.com/a/24649692/4790786
I have a scheduled timer task which is managed by Spring container. I can't figure a way to kill it once it throws some exception say RuntimeException. It keeps running for ever. Is there a way to access the Timer object and cancel it from the code?
This is my code:
<bean id="myTimer" class="com.aspect.MyTimer"></bean>
<bean id="timerTaskFactoryBean"
class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean">
<property name="targetObject" ref="myTimer"></property>
<property name="targetMethod" value="doSomething"></property>
</bean>
<bean id="timerTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property name="timerTask" ref="timerTaskFactoryBean"></property>
<property name="period" value="5000"></property>
</bean>
<bean class="org.springframework.scheduling.timer.TimerFactoryBean" id="timerBean">
<property name="scheduledTimerTasks">
<list>
<ref local="timerTask"></ref>
</list>
</property>
</bean>
Java class
public class MyTimer {
public void doSomething(){
System.out.println("I am running...");
try{
throw new RuntimeException();
}
catch(RuntimeException e){
ScheduledTimerTask timer = (ScheduledTimerTask) App.appContext.getBeanFactory().getBean("timerTask");
timer.getTimerTask().cancel();
System.out.println("Timer cancelled due to..." +e);
}
}
}
I guess you need to access the bean through the container and cancel it.
I've encorporated quartz scheduler in diffrent java file in my JSP Struts/Hibernate application. My execute method looks like below:
public void execute(JobExecutionContext jExeCtx) throws JobExecutionException {
try {
userDetailManager = new UserDetailManagerImpl();
userDetailManager.sendMailTxnDetailsEveryNight();
} catch (ApplicationException ex) {
java.util.logging.Logger.getLogger(JobClass.class.getName()).log(Level.SEVERE, null, ex);
}
}
Then im calling sendMailTxnDetailsEveryNight method and looks like:
public void sendMailTxnDetailsEveryNight() throws ApplicationException{
List<RemittanceTransactionBean> rBean = remittanceTransactionDao.getTodayTxnSummary();
return rBean;
}
Im getting nullpointerException at given point :
java.lang.NullPointerException
at com.mtmrs.business.user.impl.UserDetailManagerImpl.sendMailTxnDetailsEveryNight(UserDetailManagerImpl.java:754)
at com.mtmrs.util.common.JobClass.execute(JobClass.java:44)
How do i need to call the getTodayTxnSummary(); so that i dont get any error. I defined the remittanceTransactionDao in applicationContext as well:
<bean id="userDetailManager" parent="abstractTxDefinition">
<property name="target">
<bean class="com.mtmrs.business.user.impl.UserDetailManagerImpl">
<property name="remittanceTransactionDao" ref="remittanceTransactionDao"></property>
</bean>
</property>
</bean>
I tried debugging and see, the remittanceTransactionDao is null. I also tried setting below before calling method remittanceTransactionDao. This way the session variable im using in sendMailTxnDetailsEveryNight is null. I m stuck here.
remittanceTransactionDao = new RemittanceTransactionDaoHibernate(RemittanceTransaction.class);
I removed the classes and configured the follwing in my application-Context Dao.xml.
<bean name="runMeJob" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="com.mtmrs.util.common.RunMeJob" />
<property name="jobDataAsMap">
<map>
<entry key="userDetailManager" value-ref="userDetailManager" />
</map>
</property>
</bean>
<bean id="cronTrigger"
class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="runMeJob" />
<property name="cronExpression" value="0 0 10,12,14,16,18,20,22,23 * * ?" />
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobDetails">
<list>
<ref bean="runMeJob" />
</list>
</property>
<property name="triggers">
<list>
<ref bean="cronTrigger" />
</list>
</property>
</bean>
Then i removed everything about the quartz implementaion code whatever i was trying to make, and added this class:
package com.mtmrs.util.common;
import com.mtmrs.business.user.UserDetailManager;
import com.mtmrs.util.logger.MTMRSLogger;
import com.mtmrs.util.logger.ApplicationException;
import java.util.logging.Level;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
public class RunMeJob extends QuartzJobBean {
UserDetailManager userDetailManager;
public UserDetailManager getUserDetailManager() {
return userDetailManager;
}
public void setUserDetailManager(UserDetailManager userDetailManager) {
this.userDetailManager = userDetailManager;
}
#Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
System.out.print("Entering Class: Job Class , method: execute");
try {
userDetailManager.sendMailTxnDetailsEveryNight();
} catch (ApplicationException ex) {
java.util.logging.Logger.getLogger(RunMeJob.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.print("Exiting Class: Job Class , method: execute");
}
}
Also i downgraded the version of quartz jar to 1.x.
I needed to use a method in userDetailManager (ie sendMailTxnDetailsEveryNight) object as the job that run every 2 hours as specified in the trigger.
Basically i followed this link: Mykong
Hope this can be of help to someone.
In java Spring, I am facing an issue regarding transaction rollback.
Example:
I have 3 DAOs in my code (A, B, C). All of them extend JDBCTemplate:
#Transaction(propagation=new_required)
public void serviceClassProc() throws Exception {
A.db1();
B.db2();
C.db3();
}
Now with the above code if I throw an exception in B.db2(), nothing gets rolled back.
Now if I modify B.db2 as following:
#Transaction(propagation=nested,rollbackon=Exception.class)
public void db2() throws Exception{
...
throw new Exception();
}
And then call serviceClassProc(), only the transaction in B.db2, gets rolled back.
I want an implementation where all transactions inside serviceClassProc() get rolled back.
Here are the 2 configurations I am using:
<bean id="bonddao" class="com.marki.bonds.staticdata.dao.MuniStaticDataDaoImpl"> <property name="dataSource" ref="c3p0DataSource" /> </bean> <bean id="dcldao" class="com.bonds.staticdata.dao.DclSettingsDaoImpl"> <constructor-arg ref="c3p0DataSource" /> </bean> <bean id="batchlogdao" class="com.bonds.staticdata.dao.MuniFeedHandlerBatchLogDaoImpl"> <constructor-arg ref="c3p0DataSource" /> </bean>
<bean id="bondsApplication" class="com.markit.bonds.staticdata.service.MuniRefDataSyncApp"> <property name="refdataService" ref="refDataSynchService" /> <property name="mailService" ref="mailSender"></property> <property name="batchLogger" ref="batchlogdao"></property> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="c3p0DataSource" /> </bean> <tx:annotation-driven transaction-manager="transactionManager" />
Where I am going wrong? Is it wrong to have 3 DAOs all extending JDBC template? Should all of them share same JDBCTemplate?
You should add rollbackon=Exception.class to the annotation of your service method and remove the transaction annotation entirely from the DAO methods. It is a bad idea to have transaction control at DAO level.
you can use also the : **org.springframework.transaction.interceptor.TransactionAspectSupport;**
here is an example that you can handle it:
#Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class, transactionManager = "transactionManager")
public void messageHandler() {
try {
//TODO your own code
} catch (Exception ex) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
} finally {
}
}