脏读
时间 | 转账事务 A | 取款事务 B |
---|---|---|
T1 | 开始事务 | |
T2 | 开始事务 | |
T3 | 查询账户余额为 1000元 | |
T4 | 取出 500 元把余额改为 500元 | |
T5 | 查询账户余额为 500元(脏读) | |
T6 | 撤销事务余额恢复为 1000 元 | |
T7 | 汇入 100元把余额改为 600元 | |
T8 | 提交事务 |
不可重复度
时间 | 转账事务 A | 取款事务 B |
---|---|---|
T1 | 开始事务 | |
T2 | 开始事务 | |
T3 | 查询账户余额为 1000元 | |
T4 | 查询账户余额为 1000元 | |
T5 | 取出 100元把余额改为 900元 | |
T6 | 提交事务 | |
T7 | 查询账户余额为 900元(和T4读取的不一致) |
幻象读
时间 | 转账事务 A | 取款事务 B |
---|---|---|
T1 | 开始事务 | |
T2 | 开始事务 | |
T3 | 统计总存款数为 1000元 | |
T4 | 新增一个存款账户,存款为 100元 | |
T5 | 提交事务 | |
T6 | 在次统计总存款数为 10100元(幻想读) |
第一类丢失更新
时间 | 转账事务 A | 取款事务 B |
---|---|---|
T1 | 开始事务 | |
T2 | 开始事务 | |
T3 | 查询账户余额为 1000元 | |
T4 | 查询账户余额为 1000元 | |
T5 | 汇入 100元把余额改为1100元 | |
T6 | 提交事务 | |
T7 | 取出 100元把余额改为 900元 | |
T8 | 撤销事务 | |
T9 | 余额恢复为 1000元(丢失更新) |
第二类丢失更新
时间 | 转账事务 A | 取款事务 B |
---|---|---|
T1 | 开始事务 | |
T2 | 开始事务 | |
T3 | 查询账户余额为 1000元 | |
T4 | 查询账户余额为 1000元 | |
T5 | 取出 100元把余额改为 900元 | |
T6 | 提交事务 | |
T7 | 汇入100元 | |
T8 | 提交事务 | |
T9 | 打余额改为 1100元(丢失更新) |
隔离级别 | 脏读 | 不可重复读 | 幻象读 | 第一类丢失更新 | 第二类丢失更新 |
---|---|---|---|---|---|
READ UNCOMMITED | 允许 | 允许 | 允许 | 不允许 | 允许 |
READ COMMITTED | 不允许 | 允许 | 允许 | 不允许 | 允许 |
REPEATABLE READ | 不允许 | 不允许 | 允许 | 不允许 | 不允许 |
SERIALIZABLE | 不允许 | 不允许 | 不允许 | 不允许 | 不允许 |
Connection conn;
try{
conn = DriverManager.getConnection();//@1 获取数据连接
conn.setAutoCommit(false);//@2 关闭自动提交的机制
conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);//@3 设置事务隔离级别
Statement stmt = conn.createStatement();
int rows = stmt.executeUpdate("insert into t_topic values(1,"tom")");
rows = stmt.executeUpdate("update t_user set topic_nums = topic_nums+1 where user_id = 1");
conn.commit();// @4 提交事务
}catch(Exception e){
...
conn.rollback();//@5 回滚事务
}finally{
...
}
...
Statement stmt = conn.createStatement();
int rows = stmt.executeUpdate("insert into t_topic values(1,"tom")");
Savepoint svpt = conn.setSacepoint("savePoint1");//@1 设置一个保存点
rows = stmt.executeUpdate(update t_user set topic_nums = topic_nums+1 where user_id = 1");
...
conn.rollback(svpt);//@2 回滚到@1处的savePoint1,@1之前的SQL操作,在整个事务提交后依然提交,但@1到@2之间的SQL操作被撤销了
...
conn.commit();//@3 提交事务
public class SimpleThreadLocal{
private Map valueMap = Collections.synchronizedMap(new HashMap());
public void set(Object newValue){
valueMap.put(Thread.currentThread(), newValue);//@1 键为线程对象,值为本线程的变量副本
}
public Object get(){
Thread currentThread = Thread.currentThread();
Object o = valueMap.get(currentThread);//@2 返回本线程对应的变量
if(o == null && !valueMap.containsKey(currentThread)){//@3 如果在Map中不存在,放到Map中保存起来
o = initialValue();
valueMap.put(currentThread, o);
return o;
}
public void remove(){
valueMap.remove(Thread.currentThread());
}
public Object initialVlaue(){
return null;
}
}
}
package com.baobaotao.basic;
public class SequenceNumber {
private static ThreadLocal seqNum = new ThreadLocal() {//@1 通过匿名内部类覆盖 Thread Local的initialValue()方法,指定初始值
public Integer initialValue() {
return 0;
}
};
public int getNextNum() {//@2 获取下一个序列
seqNum.set(seqNum.get()+1);
return seqNum.get();
}
public static void main(String[] args) {
SequenceNumber sn = new SequenceNumber();
TestClient t1 =new TestClient(sn);//@3 3个线程共享sn,各自产生序列号
TestClient t2 =new TestClient(sn);
TestClient t3 =new TestClient(sn);
t1.start();
t2.start();
t3.start();
}
private static class TestClient extends Thread {
private SequenceNumber sn;
public TestClient(SequenceNumber sn) {
this.sn = sn;
}
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println("thread[" + Thread.currentThread().getName() + "]sn[" + sn.getNextNum() +"]");
}
}
}
}
thread[Thread-0]sn[1]
thread[Thread-0]sn[2]
thread[Thread-0]sn[3]
thread[Thread-1]sn[1]
thread[Thread-1]sn[2]
thread[Thread-1]sn[3]
thread[Thread-2]sn[1]
thread[Thread-2]sn[2]
thread[Thread-2]sn[3]
package com.baobaotao.scheme;
import java.sql.Connection;
import java.sql.Statement;
public class TopicDao {
//@1 一个非线程安全的变量
private Connection conn;
public void addTopic() {
//@2 引用非线程安全变量
Statement stat = conn.createStatement();
}
}
package com.baobaotao.scheme;
import java.sql.Connection;
import java.sql.Statement;
public class TopicDao {
//@1 使用ThreadLocal保持Connection变量
private static ThreadLocal<Connection> connThreadLocal = new ThreadLocal<Connection>();
private static Connection getConnection() {
//@2 如果connThread Local没有本线程对应的Connection创建一个新的Connection,
//并将其保存到线程本地变量中
if(connThreadLocal.get() == null) {
Connection conn = ConnectionManager.getConnection();
connThreadLocal.set(conn);
return conn;
}else {
//@3 直接返回线程本地变量
return connThreadLocal.get();
}
}
public void addTopic() {
//@4 从ThreadLocal中获取线程对应的
Statement stat = getConnection().createStatement();
}
}
TransactionDefinition
TransactionDefinition 定义了 Spring 兼容的事务属性,这些属性对事务管理控制的若干方面进行配置。
事务隔离:当前事务和其他事务的隔离的程度。在 TransactionDefinition 接口中,定义了和 java.sql.Connection 接口中同名的4个隔离级别:ISOLATION_READ_UNCOMMITTED、ISOLATION_READ_COMMITTED、ISOLATION_REPEATABLE_READ、ISOLATION_SERIALIZABLE(实际上它直接使用 Connection 的同名常量进行赋值),这些常量分别对应于 9.1.4节所描述隔离级别。此外,TransactionDefinition还定义了一个默认的隔离级别:ISOLATION_DEFAULT,它表示使用底层数据库的默认隔离级别;
事务传播:通常在一个事务中执行的所有代码都会在运行于同一事务上下文中。但是Spring也提供了几个可选的事务传播类型:例如,简单地参与到现有的事务中,或者挂起当前的事务,创建一个新的事务。在Sprig事务管理中,传播行为是一个重要的概念,Spring提供了EJB CMT所支持的事务传播类型。
事务超时:事务在超时前能运行多久,超过时间后,事务被回滚。有些事务管理器不支持事务过期的功能,这时,如果设置TIMEOUT_DEFAULT之外的其他值时,将抛出异常。
只读状态:只读事务不修改任何数据,资源事务管理者可以针对可读事务应用一些优化措施,提高运行性能。只读事务在某些情况下(例如使用Hibernate时),是一种非常有用的优化,试图在只读事务中更改数据将引发异常。
TransactionStatus
TransactionStatus 代表一个事务的具体运行状态。事务管理器通过该接口获取事务的运行期的状态信息,也可以通过该接口间接的回滚事务,它相比于在抛出异常时回滚事务的方式更具有可控性。该接口继承于 SavepointManager接口,SavepointManager接口基于JDBC3.0保存点的分段事务控制能力提供了嵌套事务的机制。
PlatformTransactionManager
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status)throws TransactionException;
void rollback(TransactionStatus status)throws TransactionException;
}
事务 | 说明 |
---|---|
org.springframework.orm.jpa.JpaTransactionManager | 使用JPA进行持久化时,使用该事务管理器 |
org.springframework.orm.hibernate3.HibernateTransactionManager | 使用 Hibernate 3.0 版本进行持久化,使用该事务管理器 |
org.springframework.jdbc.datasource.DataSourceTransactionManager | 使用 Spring JDBC 或 iBatis 等基于DataSource数据源的持久化技术时,使用该事务管理器 |
org.springframework.orm.jdo.JdoTransactionManager | 使用JDO进行持久化时,使用该事务管理器 |
org.springframework.transaction.jta.JtaTransactionManager | 具有多个数据源的全局事务使用该事务管理器(不管采用何种持久化技术) |
Spring JDBC 和 iBatis
<bean id="dataSource"@1 配置一个数据源
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}"/>
<bean id="transactionManager"@2 基于数据源的事务管理器
class="org.springfromwork.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"@3 引用数据源
/>
JPA
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource"@1 指定一个数据源
/>
<bean id="transactionManager"
class="org.springfromwork.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory"@2 指定实体管理器
/>
Hibernate
<bean id="sessionFactory"
class="org.springfromwork.orm.hibernate3.LocalSessionFactoryBean"
p:dataSource-ref="dataSource"@1 指定一个数据源
p:mappingResources="classpath:bbtForum.hbm.xml">@2 指定 Hibernate 配置文件
<property name="hibernateProperties">@3 Hibernate 其他配置属性
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.generate_statistics">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory"@4 注入会话工厂
/>
JTA
<?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:p="http://www.springframework.org/schema/p"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
<jee:jndi-lookup id="accountDs" jndi-name="java:comp/env/jdbc/account"/>
<jee:jndi-lookup id="orderDs" jndi-name="java:comp/env/jdbc/order"/>
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
</bean>
</beans>
持久化技术 | 线程绑定资源获取工具 |
---|---|
Spring JDBC 或 iBatis | org.springframework.jdbc.datasource.DataSourceUtils |
Hibernate 3.0 | org.springframework.orm.hibernate3.SessionFactoryUtils |
JPA | org.springframework.orm.jpa.EntityManagerFactoryUtils |
JDO | org.springframework.orm.jdo.PersistenceManagerFactoryUtils |
public abstract class TransactionSynchronizationManager {
//@1 用于保存每个事务线程对应的Connection 或 Session 等类型的资源
private static final ThreadLocal resources = new ThreadLocal();
//@2 用于保存每个事务线程对应事务的名称
private static final ThreadLocal currentTransactionName = new ThreadLocal();
//@3 用于保存每个事务线程对应事务的read-only状态
private staitc final ThreadLocal currentTransactionReadOnly = new ThreadLocal();
//@4 用于保存每个事务线程对应事务的隔离级别
private static final ThreadLocal currentTransactionIsolationLevel = new ThreadLocal();
//@5 用于保存每个事务线程对应事务的激活太态
private static final ThreadLocal actualTransactionActive = new ThreadLocal();
}
事务传播行为类型 | 说明 |
---|---|
PROPAGATION_REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行 |
PROPAGATION_MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起 |
PROPAGATION_NEVER | 以非事务方法执行,如果当前存在事务,则抛出异常 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行于PROPAGATION_REQUIRED类似的操作 |
在实际应用中,很少需要通过编程来进行事务管理,即便如此,Spring 还是为编程式事务管理提供了模板类 org.springframework.transaction.supper.TransactionTemplate,以满足一些特殊场合的需要;
TransactionTemplate 和那些持久化模板类一样,是线程安全的,因此,我们可以在多个业务中共享TransactionTemplate实例进行事务管理。TransactionTemplate拥有多个设置事务属性的方法,如setReadOnly(boolean readOnly)、setIsolationLevel(int isolationLevel)等。
TransactionCallback 接口只有一个方法:Object doInTransaction(TransactionStatus status)。如果操作不会返回结果,可以使用TransactionCallback 的子接口 TransactionCallbackWithoutResult。
public class ForumService{
private ForumDao forumDao;
TransactionTemplate template;//@1 通过IoC注入
public void addForum(final Forum forum){
template.execute(new TransactionCallbackWithoutResult(){
protected void doInTransactionWithoutResult(TransactionStatus status){
forumDao.addForum(forum);//@2 需要在事务环境中执行的代码
}
});
}
}
比较项 | EJB CMT | Spring |
---|---|---|
是否绑定JTA | 绑定在JTA上,即使是单数据源也如此。所以EJB不能脱离容器运行 | 可以在任何环境下使用,包括直接在Spring中声明的数据源或应用服务器JNDI中的JTA数据源 |
持久化技术支持 | 采用非开放的EJB自制持久化技术 | 通过少量配置即可和JDBC、JDO、Hibernate等持久化技术一起工作 |
目标类要求 | 必须是实现特定接口的特殊类 | 可以是任何POJO,不过在内部必须使用资源获取工具类操作数据连接或会话,如果DAO使用模板类进行构建,这种要求将自动得到满足 |
回滚原则 | 没有提供。 | 提供声明式的回滚规则 |
开放性控制 | 使用 EJB CMT,除了使用 setRollbackOnly(),没有办法影响容器的事务管理 | Spring允许用户通过AOP定制事务行为。例如,如果需要,用户可以在事务回滚中插入定制的行为,也可以增加任意的增强,就和任何AOP的增强一样 |
分布式事务 | 支持分布式事务。一般应用并不需要使用这样的功能 | Spring 不直接支持高端应用服务器所提供的跨越远程调用的事务上下文传播。此时,可以通过Spring的 Java EE服务集成来提供。此外,如果在Spring 中集成JOTM后,Spring也可以提供JTA事务的功能 |
特别篇
检查异常:
就是编译器要求你必须处理的异常。比如我们在编程某个文件的读于写时,编译器要求你必须要对某段代码try…catch… 或者 throws exception,这就是检查异常,简单的来说,你代码还没有运行,编码器就会检查你的代码,对可能出现的异常必须做出相对的处理。(比如当文件不存在时…)
如何处理检查异常:
1、继续往上抛出,(这是一个消极的方法),一直可以抛到java虚拟机来处理,通过throw exception抛出。
2、用try…catch捕获 (提示) 对于检查时的异常必须处理,或者必须捕获或者必须抛出
检查异常大概有哪些?
非检查异常:
编译器不要求强制处置的异常,虽然有可能出现错误,但是我不会在编译的时候检查。
如何处理非检查异常:
这类异常一般我们是不处理的,因为会很判断会出现什么问题,而且有些异常你也无法运行时处理,比如空指针。
非检查异常有哪些:
Exception异常进行划分,它可分为运行时异常和非运行时异常。
运行时异常:
非运行时异常:
package com.baobaotao.bbt;
import com.baobaotao.bbt.Forum;
import com.baobaotao.bbt.Topic;
public interface BbtForum {
void addTopic(Topic topic);
void updateForum(Forum forum);
Forum getForum(int ForumId);
int getForumNum();
}
package com.baobaotao.bbt;
import com.baobaotao.bbt.Forum;
import com.baobaotao.bbt.Topic;
public class BbtForumImpl implements BbtForum{
private ForumDao forumDao;
private TopicDao topicDao;
private PostDao postDao;
@Override
public void addTopic(Topic topic) {
topicDao.addTopic(topic);
postDao.addPost(topic.getPost());
}
@Override
public void updateForum(Forum forum) {
forumDao.updateForum(forum);
}
@Override
public Forum getForum(int forumId) {
return forumDao.getForum(forumId);
}
@Override
public int getForumNum() {
return forumDao.getForumNum();
}
}
声明式事务配置
<!-- @1 引入Dao和DaoSource的配置文件 -->
<import resource="classpath:applicationContext-dao.xml"/>
<!-- @2 声明事务管理器 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- @3 需要实施事务增强的目标业务Bean -->
<bean id="bbtForumTarget"
class="com.baobaotao.bbt.BbtForumImpl"
p:forumDao-ref="forumDao"
p:topicDao-ref="topicDao"
p:postDao-ref="postDao"/>
<bean id="bbtForum"@4 使用事务代理工厂类为目标业务Bean提供事务增强
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
p:transactionManager-ref="txManager"@4-1 指定事务管理器
p:target-ref="bbtForumTarget">@4-2 指定目标业务Bean
<property name="transactionAttributes">@4-3 事务属性配置
<props>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>@4-4 只读事务
<prop key="*">PROPAGATION_REQUIRED</prop>@4-5 可写事务
</props>
</property>
</bean>
异常回滚/提交规则
PROPAGATION(传播行为),ISOLATION(隔离级别-可选),readOnly(可选),-Exception(发生这些异常时回滚事务-可选),+Exception(发生这些异常时照样提交事务-可选)
<prop key="add">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="add">
PROPAGATION_REQUIRED,-XxxException,-YyyException
</prop>
异常提交的实例
<prop key="addTopic">
PROPAGATION_REQUIRED,+PessimisticLockingFailureException
</prop>
public class BbtForumImpl implements BbtForum{
...
@Override
public void addTopic(Topic topic) throws Exception {
topicDao.addTopic(topic);//@1 依旧会提交此处的数据持久化操作
if(true) throws new PessimisticLockingFailureException("fail");
postDao.addPost(topic.getPost());//@2 此处的数据持久化操作无法达到
}
...
}
<?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:p="http://www.springframework.org/schema/p"
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-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<import resource="classpath:applicationContext-dao.xml"/>
<!-- @1 不再需要为了事务AOP增强的实施而改名换姓 -->
<bean id="bbtForum"
class="com.baobaotao.bbt.BbtForumImpl"
p:forumDao-ref="forumDao"
p:topicDao-ref="topicDao"
p:postDao-ref="postDao"/>
<!-- @2 事务管理器 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- @3 使用强大的切点表达式语言轻松定义目标方法 -->
<aop:config>
<!-- @3-1 通过aop定义事务增强切面 -->
<aop:pointcut id="serviceMethod"
expression="execution(* com.baobaotao.service.*Forum.*(..))"/>
<!-- @3-2 引用事务增强 -->
<aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice"/>
</aop:config>
<!-- @4 事务增强 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- @4-1 事务属性定义 -->
<tx:attributes>
<tx:method name="get" read-only="false"/>
<tx:method name="add*" rollback-for="Exception"/>
<tx:method name="update*"/>
</tx:attributes>
</tx:advice>
</beans>
属性 | 是否必须 | 默认值 | 描述 |
---|---|---|---|
name | 是 | 与事务属性关联的方法名。可使用通配符(*) | 如"get*"、“handle*”、"on*Event"等 |
propagation | 否 | REQUIRED | 事务传播行为,可选值为:REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED |
isolation | 否 | DEFAULT | 事务隔离级别,可选值为:DEFAULT、READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE |
timeout | 否 | -1 | 事务超时的时间(以秒为单位),如果设置为-1,事务超时的时间由底层的事务系统决定 |
read-only | 否 | false | 事务是否只读 |
rollback-for | 否 | 所有运行期异常回滚 | 触发事务回滚的 Exception,用异常名称的片段进行匹配。可以设置多个,以逗号分开。如:“Exception1,Exception2” |
no-rollback-for | 否 | 所有检查型异常不回滚 | 不触发事务回滚的 Exception,用异常名称的片段进行匹配。可以设置多个,以逗号分开。如:“Exception1,Exception2” |
package com.baobaotao.bbt;
import org.springframework.transaction.annotation.Transactional;
import com.baobaotao.bbt.Forum;
import com.baobaotao.bbt.Topic;
//@1 对业务类进行事务增强的标注
@Transactional
public class BbtForumImpl implements BbtForum{
...
@Override
public void addTopic(Topic topic) throws Exception {
topicDao.addTopic(topic);
postDao.addPost(topic.getPost());
}
@Override
public Forum getForum(int forumId) {
return forumDao.getForum(forumId);
}
...
}
<?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:p="http://www.springframework.org/schema/p"
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-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aopi
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<import resource="classpath:applicationContext-dao.xml"/>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
<!-- @1 对标注@Transactional注解的Bean进行加工处理,以织入事务管理切面 -->
<tx:annotation-driven transaction-manager="txManager"/>
<!-- @2 由于该Bean实现类标注了@Transactional,所以将会被@1处的注解驱动自动织入事务 -->
<bean id="bbtForum"
class="com.baobaotao.bbt.BbtForumImpl"
p:forumDao-ref="forumDao"
p:topicDao-ref="topicDao"
p:postDao-ref="postDao"/>
</beans>
关于@Transactional的属性
属性名 | 说明 |
---|---|
propagation | 事务传播行为,通过以下枚举提供合法值:org.springframework.transaction.annotation.Propagation 例如:@Transactional(propagation=Propagation.REQUIRES_NEW) |
isolation | 事务隔离级别,通过以下枚举类提供合法值:org.springframework.transaction.annotation.Isolation 例如:@Transactional(isolation=Isolation.READ_COMMITTED) |
readOnly | 事务读写性,boolean 型:例如 @Transactional(readOnly=true) |
timeout | 超时时间,int 型,以秒为单位,例如:@Transaction(timeout=10) |
rollbackFor | 一组异常类,遇到时进行回滚,类型为:Class extends Throwable>[],默认为{}。例如:@Transactional(rollbackFor={SQLException.class}),多个异常之间可用逗号分割。 |
rollbackForClassName | 一组异常类名,遇到时进行回滚,类型为 String[] ,默认值为{}。例如:@Transactional(rollbackForClassName={“Exception”}) |
noRollbackFor | 一组异常类,遇到时不回滚,类型为:Class exteds Throwable>[],默认为{} |
noRollbackForClassName | 一组异常类名,遇到时不回滚,类型为 String[],默认值为{} |
在何处标注@Transactional注解
<tx:annotation-driven proxy-target-class="true"/>
在方法处使用注解
package com.baobaotao.bbt;
import org.springframework.transaction.annotation.Transactional;
import com.baobaotao.bbt.Forum;
import com.baobaotao.bbt.Topic;
@Transactional//@1 类级的注解,适用于类中所有 public 的方法
public class BbtForumImpl implements BbtForum{
@Transactional(readOnly=true)//@2 提供额外的注解信息,它将覆盖@1处的类级注解
@Override
public Forum getForum(int forumId) {
return forumDao.getForum(forumId);
}
}
使用不同的事务管理器
public class MultiForumService{
//@1 使用名为topic的事务管理器
@Transactional("topic")
public void addTopic(Topic topic) {
...
}
//@2 使用名为forum的事务管理器
@Transactional("forum")
public void updateForum(Forum forum) {
...
}
}
<bean id="forumTxManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="forumDataSource">@1 可以使用不同的数据源
<qualifier value="forum"/>@2 为事务管理器标识一个名字
</bean>
<bean id="topicTxManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="topicDataSource">
<qualifier value="topic"/>
</bean>
<tx:annotation-driven/>
package com.baobaotao.bbt;
...
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional("forum")//@1 绑定到forum的事务管理器中
public @interface ForumTransactional {
}
public class MultiForumService {
//@1使用名为topic的事务管理器
@TopicTransactional
public void addTopic(Topic topic) {
...
}
//@2 使用名为forum的事务管理器
@ForumTransactional
public void updateForum(Forum forum) {
...
}
}
<?xml version="1.0" encoding="UTF-8"?>
<aspectj>
<aspects>
<aspect name="org.springframework.transaction.aspectj.AnnotationTransactionAspect"/>
</aspects>
<weaver
options="-showWeaveInfo -XmessageHandlerClass:
org.springframework.transaction.aspectj.AspectJWeaverMessageHandler">
<include within="com.baobaotao.servie.impl.*"/>
</weaver>
</aspectj>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
<bean id="bbtForum"
class="com.baobaotao.bbt.BbtForumImpl"
p:forumDao-ref="forumDao"
p:topicDao-ref="topicDao"
p:postDao-ref="postDao"/>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
<tx:annotation-driven/>
</beans>
<bean id="txManager"
classs="org.springframework.transaction.jta.WebLogicJtaTransactionManager"/>
<bean id="txManager"
classs="org.springframework.transaction.jta.WebSphereUowTransactionManager"/>