
Originally Posted by
bdangubic
post your code, configuration and what you are trying to do...
sorry I go back here late.
If use JdbcTemplate to manipulate database, my understanding is even within the same thread, when call getJdbcTemplate().update(), a new db connection from the connection pool will be used to update the db. Hence, if in a multi-threading env, how to make all threads' jobs rollback if one thread's job fails by using Spring transaction management?
I wrote a small demo, below is the code. The code only rolls back the one that is failed. I need to find a way to handle rollback all threads' job if one thread job fails.
Thanks a million.
Code:
<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/schem...-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schem...ing-tx-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<tx:annotation-driven />
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/spring</value>
</property>
<property name="username">
<value>user</value>
</property>
<property name="password">
<value>password</value>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="bookShop"
class="mytest.bookshop.JdbcBookShop" >
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="bookShopUtil"
class="mytest.bookshop.BookShopRunUtil" >
<property name="bookShop" ref="bookShop" />
</bean>
</beans>
Code:
public class JdbcBookShop extends JdbcDaoSupport {
@Transactional(propagation = Propagation.REQUIRED)
public void updateBookInfo( final String actionName ) throws RuntimeException {
String isbn = "0001";
String userName = "rose";
int price = 11;
try {
if (actionName.equalsIgnoreCase("BOOK")) {
getJdbcTemplate().update(
"UPDATE BOOK SET PRICE = 2000 " +
"WHERE ISBN = ?",
new Object[] { isbn });
}
else if (actionName.equalsIgnoreCase("ACCOUNT")){
getJdbcTemplate().update(
"UPDATE ACCOUNT SET BALANCE = BALANCE - ? " +
"WHERE USERNAME = ?",
new Object[] { price, userName });
//SQLException here, bad column name
getJdbcTemplate().update(
"UPDATE BOOK_STOCK SET STOCKK = STOCK - 1 " +
"WHERE ISBN = ?",
new Object[] { isbn });
}
}
catch (RuntimeException e) {
System.out.println(e.getMessage());
throw e;
}
}
public class BookShopRunUtil {
......
@Transactional(propagation = Propagation.REQUIRED)
public void runThreadPool() {
//create thread pool, and generate two threads
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 5, 6L,TimeUnit.SECONDS, new LinkedBlockingQueue(5));
Callable callable = null;
Collection collection = new ArrayList();
try {
callable = new UnitTask("ACCOUNT", bookShop);
collection.add(callable);
callable = new UnitTask("BOOK", bookShop);
collection.add(callable);
List<Future<Boolean>> returnList = (List<Future<Boolean>>)threadPoolExecutor.invokeAll(collection);
boolean success = true;
for( int i = 0; i < returnList.size(); i++ ) {
if( returnList.get(i).get().booleanValue() == false ) {
success = false;
break;
}
}
if( !success ) {
throw new Exception("RuntimeException occurs in Main");
}
}
catch (InterruptedException ex) {
....
}
catch (Exception ex) {
System.err.println(ex.getMessage());
throw ex;
}
}
}
public class UnitTask implements Callable{
private String actionTable;
private BookShop bookShop;
public UnitTask(String actionTable, BookShop bookShop){
this.actionTable= actionTable;
this.bookShop = bookShop;
}
public Boolean call() {
String threadName = Thread.currentThread().getName();
Boolean returnVal;
try{
bookShop.updateBookInfo(actionTable);
returnVal = true;
}
catch(RuntimeException e){
System.out.println(threadName + e.getMessage());
returnVal = false;
}
return returnVal;
}
}