一、编程式事务控制
JDBC的事务管理在Spring2.0下有两种编程式的实现
- PlatformTransactionManager
- TransactionTemplate
1、PlatformTransactionManager 事务管理器
package org.springframework.transaction;
public abstract interface PlatformTransactionManager
{
//根据事务定义TransactionDefinition,获取事务
public abstract TransactionStatus getTransaction(TransactionDefinition paramTransactionDefinition)
throws TransactionException;
//提交事务
public abstract void commit(TransactionStatus paramTransactionStatus)
throws TransactionException;
//回滚事务
public abstract void rollback(TransactionStatus paramTransactionStatus)
throws TransactionException;
}
(1)TransactionDefinition : 事务的一些基础信息,如超时时间、隔离级别、传播属性等
(2)TransactionStatus : 事务的一些状态信息,如是否是一个新的事务、是否已被标记为回滚
在使用的过程中常常使用它的最终实现类DataSourceTransactionManager。
public abstract class AbstractPlatformTransactionManager
implements PlatformTransactionManager, Serializable{
}
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean{
}
具体实现步骤:
1. 实例化的时候,需要用个数据源作参数
2. 建立事务的定义,使用DefaultTransactionDefinition类,直接new个新的就可以了
3. 调用DefaultTransactionDefinition类的setPropagationBehavior方法,参数是TransactionDefinition的常量,例如PROPAGATION_REQUIRED等。
4. 在使用到具体的SQL操作之前,创建一个TransactionStatus类的实例: TransactionStatus status = transactionManager.getTransaction(def)。
其中,transactionManager是DataSourceTransactionManager类的实例,def是DefaultTransactionDefinition的实例
5. 之后使用具体的SQL操作,发生异常了,就使用transactionManager.rollback(status)
6. 正常操作的话,就使用transactionManager.commit(status)
举例:
public void insert(){
PlatformTransactionManager tran = new DataSourceTransactionManager(dataSource);
DefaultTransactionDefinition def = new DefaultTransactionDefinition();//事务定义类
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = tran.getTransaction(def);//返回事务
try {
JdbcTemplate template = new JdbcTemplate(dataSource);
template.update("Insert into userinfo(username,password) values('aaaaa','bbbbb')");
template.update("Insert into userinfo(username,password) values('ccccc','ddddd')");
tran.rollback(status);
} catch (Exception e) {
tran.rollback(status);
e.printStackTrace();
}
}
由于Spring容器底层采用ThreadLocal存储事务当前线程的Connection,所以DataSourceTransactionManager中操作Connection对象和JdbcTemplate中操作的Connection是同一个对象(详情见另一博文:《Spring中事务之如何保证同一个Connection对象》),因此能够DataSourceTransactionManager能够代理管理JdbcTemplate的事务。
PlatformTransactionManager源码详细分析见:
http://www.07net01.com/2015/05/842465.html
2、TransactionTemplate 事务模板
TransactionTemplate模板类用于简化事务管理,事务管理由模板类定义,而具体操作需要通过TransactionCallback回调接口或TransactionCallbackWithoutResult回调接口指定,通过调用模板类的参数类型为TransactionCallback或TransactionCallbackWithoutResult的execute方法来自动享受事务管理。
TransactionTemplate模板类使用的回调接口:
- TransactionCallback:通过实现该接口的“T doInTransaction(TransactionStatus status) ”方法来定义需要事务管理的操作代码;
- TransactionCallbackWithoutResult:继承TransactionCallback接口,提供“void doInTransactionWithoutResult(TransactionStatus status)”便利接口用于方便那些不需要返回值的事务操作代码。
具体步骤:
1. 在具体的SQL语句操作签,实例化它:
TransactioinTemplate transactionTemplate = new TransactionTemplate(trasactionManager);
2. 然后就是具体的SQL操作,不过写起来有点复杂:
transactionTemplate.execute(
new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
// 这里执行SQL的操作
// 发生异常的时候status.setRollbackOnly(),正常的时候直接返回结果
}
}
);
3.如果没有返回值,可以使用TransactionCallbackWithoutResult类。里面的方法调用一样,只不过用了TransactionCallbackWithoutResult的匿名继承。
举例:
public void update(){
DataSourceTransactionManager tran = new DataSourceTransactionManager(dataSource);
TransactionTemplate tranTemplate = new TransactionTemplate(tran);
tranTemplate.execute(new TransactionCallback() {
@Override
public Object doInTransaction(TransactionStatus status) {
int retInt = 0;
try {
JdbcTemplate template = new JdbcTemplate(dataSource);
template.update("udpate userinfo set password = 'mbbbb' where username = 'aaaaa' ");
template.update("udpate userinfo set password = 'mdddd' where username = 'ccccc' ");
retInt = 1;
} catch (Exception e) {
status.setRollbackOnly();//通知回滚
e.printStackTrace();
}
return new Integer(retInt);
}
});
}
二、XML配置(AOP)事务控制
在Spring配置文件中配置如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="org.gjt.mm.mysql.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/test?userUnicode=true&characterEncoding=UTF-8" />
<property name="username" value="root" />
<property name="password" value="5" />
<!-- 连接池启动时的初始值 -->
<property name="initialSize" value="1" />
<!-- 连接池的最大值 -->
<property name="maxActive" value="500" />
<!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
<property name="maxIdle" value="2" />
<!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
<property name="minIdle" value="1" />
</bean>
<!-- 配置DataSourceTransactionManager事务 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置通知 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="*" read-only="true" propagation="NOT_SUPPORTED" />
</tx:attributes>
</tx:advice>
<!-- 配置事务管理切面 -->
<aop:config>
<aop:pointcut id="transactionPointcut"
expression="execution(* com.haiwi.service.impl.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="transactionPointcut" />
</aop:config>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="bookService" class="com.ufgov.fm.server.serviceimpl.BookServiceImpl">
<property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>
</beans>
下面是Spring中Propagation类的事务属性详解:
- REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
- SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
- MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
- REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
- NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
- NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。
service代码如下
package com.haiwi.service;
public interface BookService {
public void insertBook();
}
package com.haiwi.service.impl;
import org.springframework.jdbc.core.JdbcTemplate;
import com.haiwi.service.BookService;
public class BookServiceImpl implements BookService {
JdbcTemplate jdbcTemplate ;
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void insertBook() {
jdbcTemplate.update("update book set book_type='编程语言' where cate = '001'");
jdbcTemplate.update("update book set book_type='数据库' where cate = '002'");
jdbcTemplate.update("update book set book_type='操作系统' where cate = '003'");
}
}