- try {
- .....
- connection.setAutoCommit(false);
- .....
- // 一连串SQL操作
- connection.commit();
- } catch(SQLException) {
- // 发生错误,撤消所有变更
- connection.rollback();
- }
在Spring中对JDBC的事务管理加以封装,Spring事务管理的抽象关键在于org.springframework.transaction.PlatformTransactionManager接口的实现:
...
- public interface PlatformTransactionManager {
- TransactionStatus getTransaction(TransactionDefinition
- definition) throws TransactionException;
- void commit(TransactionStatus status)
- throws TransactionException;
- void rollback(TransactionStatus status)
- throws TransactionException;
- }
PlatformTransactionManager接口有许多具体的事务实现类,例如DataSourceTransactionManager、HibernateTransactionManager、JdoTransaction- Manager、JtaTransactionManager等,通过依赖于PlatformTransactionManager接口及各种的技术实现,Spring在事务管理上可以让开发人员使用一致的编程模型,即使所使用的是不同的事务管理技术。
TransactionException是Unchecked Exception。事务的失败通常都是致命的错误,Spring不强迫您一定要处理,而是让您自行选择是否要捕捉异常。
getTransaction() 方法根据一个TransactionDefinition对象来回传一个TransactionStatus对象,TransactionDefinition接口的实例定义了事务的隔离程度(Isolation level)、传播行为(Propagation behavior)、超时(Timeout)、只读(Read-only)等,TransactionStatus代表着一个新的事务发起或已经存在的事务,您可以通过它来控制事务的执行或调查的状态:
...
- public interface TransactionStatus {
- boolean isNewTransaction();
- void setRollbackOnly();
- boolean isRollbackOnly();
- }
Spring提供编程式的事务管理(Programmatic transaction management)与声明式的事务管理(Declarative transaction management):
l 编程式的事务管理
编程式的事务管理可以清楚地控制事务的边界,也就是让您自行实现事务开始时间、撤消操作的时机、结束时间等,可以实现细粒度的事务控制。
l 声明式的事务管理
然而多数的情况下,事务并不需要细粒度的控制,而是采用声明式的事务管理,好处是Spring事务管理的相关API可以不用介入程序之中,从对象的角度来看,它并不知道自己正被纳入事务管理之中,在不需要事务管理的时候,只要在设置文件上修改一下设置,即可移去事务管理服务。
5.3.2 JDBC编程事务管理
Spring提供两种方式实现编程式的事务管理,一是直接使用PlatformTransaction- Manager实现,二是使用org.springframework.transaction.support.Transaction- Template。
先来看看如何使用PlatformTransactionManager,在这里使用它的实现类DataSourceTransactionManager,可以改写一下之前5.2.1节中的JdbcTemplateDemo项目,让它具有事务管理功能,修改一下UserDAO类的insert() 方法来作示范:
ProgrammaticTransactionDemo 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 ‘‘,