Spring提供兩種方式實現編程式的交易管理,一是直接使用PlatformTransactionManager實現,二是使用org.springframework.transaction.support.TransactionTemplate。
先來看看如何使用PlatformTransactionManager,在這邊使用它的實現類別DataSourceTransactionManager,可以改寫一下 使 用 JdbcTemplate,讓它具有交易管理功能,修改一下UserDAO類別的insert()方法來作示範:
- UserDAO.java
package onlyfun.caterpillar;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.
datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.
support.DefaultTransactionDefinition;
public class UserDAO implements IUserDAO {
private DataSourceTransactionManager transactionManager;
private DefaultTransactionDefinition def;
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
transactionManager =
new DataSourceTransactionManager(dataSource);
// 建立交易的定義
def = new DefaultTransactionDefinition();
def.setPropagationBehavior(
TransactionDefinition.PROPAGATION_REQUIRED);
}
public void insert(User user) {
String name = user.getName();
int age = user.getAge().intValue();
TransactionStatus status =
transactionManager.getTransaction(def);
try {
jdbcTemplate.update("INSERT INTO user (name,age) "
+ "VALUES('" + name + "'," + age + ")");
// 下面的SQL有錯誤,用以測試交易
jdbcTemplate.update("INSER INTO user (name,age) "
+ "VALUES('" + name + "'," + age + ")");
}
catch(DataAccessException e) {
transactionManager.rollback(status);
throw e;
}
transactionManager.commit(status);
}
public User find(Integer id) {
List rows = jdbcTemplate.queryForList(
"SELECT * FROM user WHERE id=" + id.intValue());
Iterator it = rows.iterator();
if(it.hasNext()) {
Map userMap = (Map) it.next();
Integer i = new Integer(
userMap.get("id").toString());
String name = userMap.get("name").toString();
Integer age = new Integer(
userMap.get("age").toString());
User user = new User();
user.setId(i);
user.setName(name);
user.setAge(age);
return user;
}
return null;
}
}
在insert()方法中使用了DataSourceTransactionManager來進行交易管理,如果發生了例外,則catch區塊中會進行交 易的回滾(Rollback),在insert()方法中固定撰寫錯有錯誤的SQL(注意INSERT方法少寫了一個T),因此實際上資料並不會被儲存至 資料庫中。
要使用MySQL資料庫的交易處理,必須建立交易類型的表格,例如InnoDB類型的表格,我這邊用來建立表格的SQL如下所示:
CREATE TABLE user (
id INT(11) NOT NULL auto_increment PRIMARY KEY,
name VARCHAR(100) NOT NULL default '',
age INT
) TYPE = InnoDB;
id INT(11) NOT NULL auto_increment PRIMARY KEY,
name VARCHAR(100) NOT NULL default '',
age INT
) TYPE = InnoDB;
另一個實現編程式交易管理的方法是使用TransactionTemplate,它需要一個TransactionManager實例,一個例子如下所示:
...
TransactionTemplate transactionTemplate =
new TransactionTemplate(transactionManager);
...
transactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
try {
jdbcTemplate.update("INSERT INTO user (name,age) "
+ "VALUES('" + name + "'," + age + ")");
...
}
catch(DataAccessException e) {
status.setRollbackOnly();
}
return result; // commit
}
});
TransactionTemplate transactionTemplate =
new TransactionTemplate(transactionManager);
...
transactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
try {
jdbcTemplate.update("INSERT INTO user (name,age) "
+ "VALUES('" + name + "'," + age + ")");
...
}
catch(DataAccessException e) {
status.setRollbackOnly();
}
return result; // commit
}
});
如果發生了例外,則會進行回滾,否則提交交易,如果沒有返回值,則也可以使用TransactionCallbackWithoutResult:
...
transactionTemplate.execute(
new TransactionCallbackWithoutResult() {
public void doInTransactionWithoutResult(
TransactionStatus status) {
. ...
}
});
transactionTemplate.execute(
new TransactionCallbackWithoutResult() {
public void doInTransactionWithoutResult(
TransactionStatus status) {
. ...
}
});