主要讲事务的基本概念和处理方法
前面Spring提供的AOP就是实现了事务处理。
(一)事务的概念
定义:事务就是一连串步骤依次执行的过程,这些步骤都是同时成功和同时失败的。
事务处理有两个关键概念:提交(Commit)和回滚(Rollback)
提交就是在一个事务内部全部执行成功了,就可以提交。
回滚就是在一个事务内部只要有一个步骤失败了,那这个事务回滚,所有已经执行和未经执行的步骤都会回到事务开始的状态。
事务的4个特性:ACID
原子性:Atomicity 一致性:Consistency 隔离性:Isolation 持久性:Durabulity
1、原子性:
原子性说明事务是一个整体,这个整体一荣俱荣,一损俱损的。保证事务是否完全完成。
2、一致性:
说明事务开始和事务结束,其逻辑状态都是一致的。比如去银行取钱,一个是账户余额,一个是交易流水,在事务开始之前,逻辑状态应该是原先有100元,没有进行取款就不存在交易流水。到事务结束,假设取款50元,那按照业务逻辑来说应该是账户余额还剩50元,且同时产生了一笔交易流水。这样不管是在事务开始还是结束,其逻辑状态都是一致的,没有问题。如果在事务结束,账户余额还剩50元,但是没有交易流水,那这个就在事务结束的时候逻辑状态就不一致了,不符合事务的一致性。所以事务的一致性确保了逻辑的正确性。当处理事务的过程中,有任何一个步骤失败,都应该将所有事务中涉及的数据都恢复到事务还未开始的状态。
3、隔离性
确保一个事务在执行过程中,对另一个事务是不可见的,这样就不会存在两个事务同时去修改同一个数据。
4、持久性
一旦事务提交了,事务对数据的改变的动作是持久的,一直保存在系统中,可以保存在数据库的事务日志中。如果想恢复数据,可以使用数据库的事务日志。
(二)传统事务处理的3种方式:
关系型数据库的事务处理、传统的JDBC事务处理、分布式事务处理
1、关系型数据库的事务处理:
Begin Transaction //通知事务开始处理
//事务处理的过程
Commit/Rollback
End Transaction//事务结束,一并执行
事务之间的隔离程度:Isolation Level
read uncommited:不管事务是否提交均支持访问
read commited:只允许读取已经提交的记录
repeatable read:只允许读取在事务开始之前拍的快照,事务开始后的不管是提交的还是没提交的记录都不读不到
大多数默认 read commited
2、传统的JDBC的事务处理
package com.gc.acion;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import javax.sql.DataSource;
public class JDBCTransaction {
Connection conn = null;
PreparedStatement ps = null;
private DataSource dataSource;
public void setDataSource(DataSource dataSource){
this.dataSource = dataSource;
}
public void startTransaction(){
try {
//通过数据源获取数据库连接池链接
conn = dataSource.getConnection();
//不自动提交
conn.setAutoCommit(false);
String sql1 = "delete from tbstudent";
String sql2 = "insert into tbstudent value(001,'wangyj')";
//创建执行对象1
ps = conn.prepareStatement(sql1);
//执行sql1
ps.executeUpdate();
//创建执行对象2
ps = conn.prepareStatement(sql2);
//执行sql2
ps.execute();
//提交
conn.commit();
} catch (SQLException e) {
if(conn != null){
try {
//事务处理失败,回滚
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}finally{
try {
//关闭采用栈的方式,后进先关
if(ps != null){
ps.close();
}
if(conn != null){
conn.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
3、分布式事务处理
针对多个数据库进行事务处理(比如前两个是银行内用同一个数据库完成的转账,而分布式针对的是跨行之间的转账,涉及两个数据库甚至多个数据库的事务处理)
分布式事务需要多个不同的事务管理器合作。
(三)Spring的事务处理
Spring提供了两种事务处理方式:编程式事务处理、声明式事务处理
1、先来了解一下Spring的事务处理
Spring的事务处理是基于动态AOP机制,为了实现动态AOP,Spring在默认情况下会使用Java动态代理机制。动态代理机制要求代理对象必须要实现一个接口。
Spring事务中心接口是org.springframework.transaction.PlatformTransactionManager;
Spring事务处理常用的一些接口源码:
PlatformTransactionManager:
package org.springframework.transaction;
public abstract interface PlatformTransactionManager {
public abstract TransactionStatus getTransaction(
TransactionDefinition paramTransactionDefinition)
throws TransactionException;
public abstract void commit(TransactionStatus paramTransactionStatus)
throws TransactionException;
public abstract void rollback(TransactionStatus paramTransactionStatus)
throws TransactionException;
}
TransactionDefinition:
package org.springframework.transaction;
public abstract interface TransactionDefinition {
public static final int PROPAGATION_REQUIRED = 0;
public static final int PROPAGATION_SUPPORTS = 1;
public static final int PROPAGATION_MANDATORY = 2;
public static final int PROPAGATION_REQUIRES_NEW = 3;
public static final int PROPAGATION_NOT_SUPPORTED = 4;
public static final int PROPAGATION_NEVER = 5;
public static final int PROPAGATION_NESTED = 6;
public static final int ISOLATION_DEFAULT = -1;
public static final int ISOLATION_READ_UNCOMMITTED = 1;
public static final int ISOLATION_READ_COMMITTED = 2;
public static final int ISOLATION_REPEATABLE_READ = 4;
public static final int ISOLATION_SERIALIZABLE = 8;
public static final int TIMEOUT_DEFAULT = -1;
public abstract int getPropagationBehavior();
public abstract int getIsolationLevel();
public abstract int getTimeout();
public abstract boolean isReadOnly();
public abstract String getName();
}
TransactionStatus:
package org.springframework.transaction;
import java.io.Flushable;
public abstract interface TransactionStatus extends SavepointManager, Flushable {
public abstract boolean isNewTransaction();
public abstract boolean hasSavepoint();
public abstract void setRollbackOnly();
public abstract boolean isRollbackOnly();
public abstract void flush();
public abstract boolean isCompleted();
}
2、编程式事务处理(手动编写代码进行事务管理)
Spring通过org.springframework.transaction.support.TransactionTemplate;来提供编程式事务的处理。TransactionTemplate是无状态且线程安全的。
package org.springframework.transaction.support;
import java.lang.reflect.UndeclaredThrowableException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.TransactionSystemException;
public class TransactionTemplate extends DefaultTransactionDefinition implements
TransactionOperations, InitializingBean {
protected final Log logger = LogFactory.getLog(super.getClass());
private PlatformTransactionManager transactionManager;
public TransactionTemplate() {
}
public TransactionTemplate(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public TransactionTemplate(PlatformTransactionManager transactionManager,
TransactionDefinition transactionDefinition) {
super(transactionDefinition);
this.transactionManager = transactionManager;
}
public void setTransactionManager(
PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public PlatformTransactionManager getTransactionManager() {
return this.transactionManager;
}
public void afterPropertiesSet() {
if (this.transactionManager == null)
throw new IllegalArgumentException(
"Property 'transactionManager' is required");
}
public <T> T execute(TransactionCallback<T> action)
throws TransactionException {
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
return ((CallbackPreferringPlatformTransactionManager) this.transactionManager)
.execute(this, action);
}
TransactionStatus status = this.transactionManager.getTransaction(this);
Object result;
try {
result = action.doInTransaction(status);
} catch (RuntimeException ex) {
rollbackOnException(status, ex);
throw ex;
} catch (Error err) {
rollbackOnException(status, err);
throw err;
} catch (Throwable ex) {
rollbackOnException(status, ex);
throw new UndeclaredThrowableException(ex,
"TransactionCallback threw undeclared checked exception");
}
Object result;
this.transactionManager.commit(status);
return result;
}
private void rollbackOnException(TransactionStatus status, Throwable ex)
throws TransactionException {
this.logger.debug(
"Initiating transaction rollback on application exception", ex);
try {
this.transactionManager.rollback(status);
} catch (TransactionSystemException ex2) {
this.logger.error(
"Application exception overridden by rollback exception",
ex);
ex2.initApplicationException(ex);
throw ex2;
} catch (RuntimeException ex2) {
this.logger.error(
"Application exception overridden by rollback exception",
ex);
throw ex2;
} catch (Error err) {
this.logger.error(
"Application exception overridden by rollback error", ex);
throw err;
}
}
}
如上源码可以看到:
1、需要TransactionTemplate提供PlatformTransactionManager的实例。前面说到PlatformTransactionManager的实现类很多。
2、要实现TransactionTemplate,只需要调用execute方法。在该方法中要用到TransactionCallback的doInTransaction()方法
3、所以基于第2点要实现TransactionCallback接口,doInTransaction并且在doInTransaction()进行数据库操作。
4、如果操作成功,则提交this.transactionManager.commit(status);
5、如果操作失败,则回滚rollbackOnException(status, ex);
6、result是事务执行结果。
通过TransactionTemplate实现编程式事务的处理实例:
package com.gc.acion;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
public class HelloDAO {
private DataSource dataSource;
private PlatformTransactionManager transactionManager;
//通过依赖注入中的set注入来完成管理
public void setDataSource(DataSource dataSource){
this.dataSource = dataSource;
}
public void setTransactionManager(PlatformTransactionManager transactionManager){
this.transactionManager = transactionManager;
}
public Object create(String msg){
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
Object result = transactionTemplate.execute(new TransactionCallback(){
//重写doInTransaction方法,进行具体数据库操作
@Override
public Object doInTransaction(
TransactionStatus paramTransactionStatus) {
// TODO Auto-generated method stub
Connection conn = null;
PreparedStatement ps = null;
int objResult = -1;
//数据库事务处理
try {
conn = dataSource.getConnection();
ps = conn.prepareStatement("insert into tbstudent values(001, 'wangyj')");
objResult = ps.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return objResult;
}
});
return result;
}
}
因为前面使用了set依赖注入的方式,所以要有xml配置。
<!-- 设定dataSource -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>oracle.jdbc.driver.OracleDriver</value>
</property>
<property name="url">
<value>jdbc:oracle:thin:@127.0.0.1:1521:oral</value>
</property>
<property name="username">
<value>hr</value>
</property>
<property name="password">
<value>hr1234</value>
</property>
</bean>
<!-- 设定transactionManager -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<!-- 设定事务处理实现类 HelloDAO-->
<bean id="HelloDAO" class="com.gc.acion.HelloDAO">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
</bean>
这样在HelloDAO中create方法对数据进行处理的时候,Spring会自动对这个操作使用事务处理,不用在写commit和rollback方法了,
因为TransactionCallback还有一个无参数返回的实现类TransactionCallbackWithoutResult,所以还有另一个方法实现:
package com.gc.acion;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
public class HelloDAO {
private DataSource dataSource;
private PlatformTransactionManager transactionManager;
//通过依赖注入中的set注入来完成管理
public void setDataSource(DataSource dataSource){
this.dataSource = dataSource;
}
public void setTransactionManager(PlatformTransactionManager transactionManager){
this.transactionManager = transactionManager;
}
public Object create(String msg){
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
Object result = transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(
TransactionStatus paramTransactionStatus) {
// TODO Auto-generated method stub
JdbcTemplate jdbctemplate = new JdbcTemplate(dataSource);
jdbctemplate.update("insert into tbstudent values(001, 'wangyj')");
}
});
return result;
}
}
xml配置文件依赖注入同上。
3、声明式事务处理(事务处理放在配置文件中处理)
声明式事务处理主要借助于AOP的实现,所以要引入两个相关jar包:
aopalliance-1.0.jar和cglib-2.1.3.jar
Java代码:
package com.gc.acion;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
public class ByeDAO {
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
//通过set方式依赖注入
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
jdbcTemplate = new JdbcTemplate(dataSource);
}
//这里不处理事务,事务的处理都放在配置文件中
public void create(DataSource dataSource){
jdbcTemplate.update("insert into tbstudent values(001, 'wangyj')");
}
}
xml配置:
<!-- 设定dataSource -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>oracle.jdbc.driver.OracleDriver</value>
</property>
<property name="url">
<value>jdbc:oracle:thin:@127.0.0.1:1521:oral</value>
</property>
<property name="username">
<value>hr</value>
</property>
<property name="password">
<value>hr1234</value>
</property>
</bean>
<!-- 设定transactionManager -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<!-- 事务处理实现类ByeDAO -->
<bean id="ByeDAO" class="com.gc.acion.ByeDAO">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
</bean>
<!-- 声明式事务处理代理类 -->
<bean id="ByeDAOProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="target">
<ref bean="ByeDAO"/><!-- 被代理类 -->
</property>
<property name="transactionAttributes">
<props key="creat*">PROPAGATION_REQUIRED</props><!-- 对ByeDAO类中的create方法进行事务管理,如果当前没有事务就新建一个事务 -->
</property>
</bean>
transactionAttributes 属性:
PROPAGATION
事务传播行为类型 | 说明 |
PROPAGATION_REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
|
小结:
事务的基础知识和相关概念
传统事务的处理:关系型数据库,JDBC,分布式数据库
Spring事务处理:编程式事务处理和声明式事务处理