spring事务并非spring处理事务,是spring接收到请求后,交给后台的jdbc等工具进行实现的.
事务的四个特性(ACID)
①、原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。
②、一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。
③、隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。
④、持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。
传播行为:当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。
Spring 定义了如下七中传播行为,这里以A业务和B业务之间如何传播事务为例说明:
①、PROPAGATION_REQUIRED :required , 必须。默认值,A如果有事务,B将使用该事务;如果A没有事务,B将创建一个新的事务。
②、PROPAGATION_SUPPORTS:supports ,支持。A如果有事务,B将使用该事务;如果A没有事务,B将以非事务执行。
③、PROPAGATION_MANDATORY:mandatory ,强制。A如果有事务,B将使用该事务;如果A没有事务,B将抛异常。
④、PROPAGATION_REQUIRES_NEW :requires_new,必须新的。如果A有事务,将A的事务挂起,B创建一个新的事务;如果A没有事务,B创建一个新的事务。
⑤、PROPAGATION_NOT_SUPPORTED :not_supported ,不支持。如果A有事务,将A的事务挂起,B将以非事务执行;如果A没有事务,B将以非事务执行。
⑥、PROPAGATION_NEVER :never,从不。如果A有事务,B将抛异常;如果A没有事务,B将以非事务执行。
⑦、PROPAGATION_NESTED :nested ,嵌套。A和B底层采用保存点机制,形成嵌套事务。 (个人理解:这个就是在原有的事务下新建一个事务,但是这个事务完全依赖于外层事务,只有最外层的事务commit的时候,内层的才能够实现commit)
隔离级别:
①、ISOLATION_DEFAULT:使用后端数据库默认的隔离级别
②、ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
③、ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
④、ISOLATION_REPEATABLE_READ:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生
⑤、ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的
只读:
这是事务的第三个特性,是否为只读事务。如果事务只对后端的数据库进行该操作,数据库可以利用事务的只读特性来进行一些特定的优化。通过将事务设置为只读,你就可以给数据库一个机会,让它应用它认为合适的优化措施。
事务超时:
为了使应用程序很好地运行,事务不能运行太长的时间。因为事务可能涉及对后端数据库的锁定,所以长时间的事务会不必要的占用数据库资源。事务超时就是事务的一个定时器,在特定时间内事务如果没有执行完毕,那么就会自动回滚,而不是一直等待其结束。
回滚规则:
事务五边形的最后一个方面是一组规则,这些规则定义了哪些异常会导致事务回滚而哪些不会。默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚(这一行为与EJB的回滚行为是一致的) 。但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。
Spring 编程式事务和声明式事务的区别
编程式事务处理:所谓编程式事务指的是通过编码方式实现事务,允许用户在代码中精确定义事务的边界。即类似于JDBC编程实现事务管理。管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。
声明式事务处理:管理建立在AOP(切片)之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。
简单地说,编程式事务侵入到了业务代码里面,但是提供了更加详细的事务管理;而声明式事务由于基于AOP,所以既能起到事务管理的作用,又可以不影响业务代码的具体实现。
这个部分再通俗一些讲其实就是一个是手把手告诉你什么时候做什么,怎么做,底层代码的自由度不高,管理人员(程序员)工作量大;另一个则是告诉你时间段,中间你是怎么做的不管你,我只要结果.这个的结果是简单省事儿,当时也会出现一些超脱控制之外的情况出现,不够精致.
编程式事务
主要是通过实现一个事务的方法进行操作,如果多个事务的话,比较复杂,不易于管理,但是 贵在精细.
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import com.ys.dao.AccountDao;
import com.ys.service.AccountService;
public class AccountServiceImpl implements AccountService{
private AccountDao accountDao;
private TransactionTemplate transactionTemplate;
// 这个部分是提供一个set方法为XML配置文件提供一个有效的接口
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(final String outer,final String inner,final int money) {
// 因为使用了doInTransactionWithoutResult方法,所以没有返回值,如果中间出现异常的话将会执行回滚,如果没有异常则进行正常执行,返回一个null
transactionTemplate.execute(
new TransactionCallbackWithoutResult(){
@Override
protected void doInTransactionWithoutResult(TransactionStatus arg0) {
accountDao.out(outer, money);
accountDao.in(inner, money);
}
});
}
}
等同于下面的代码:
TransactionTemplate tt = new TransactionTemplate(); // 新建一个TransactionTemplate
Object result = tt.execute(
new TransactionCallback(){
public Object doTransaction(TransactionStatus status){
updateOperation();
return resultOfUpdateOperation();
}
}); // 执行execute方法进行事务管理
源码:
public Object execute(TransactionCallback action)
throws TransactionException
{
if(transactionManager instanceof CallbackPreferringPlatformTransactionManager)
return ((CallbackPreferringPlatformTransactionManager)transactionManager).execute(this, action);
TransactionStatus status = 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(Exception ex)
{
rollbackOnException(status, ex);
throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
}
// 如果上面没有出错的话,执行commit,异常拦截则会进行rollback处理
transactionManager.commit(status);
return result; // 这个结果貌似永远都只会是个null.....(个人理解)
}
public abstract class TransactionCallbackWithoutResult implements TransactionCallback
{
public TransactionCallbackWithoutResult()
{
}
public final Object doInTransaction(TransactionStatus status)
{
doInTransactionWithoutResult(status);
return null; // 这个地方好像写死了...结果永远只有一个
}
protected abstract void doInTransactionWithoutResult(TransactionStatus transactionstatus);
}
声明式事务:
XML配置方法:
database配置 ---> 用于连接数据库
transactionmanager ---> 事务管理者设置
tx:advice ---> 事务通知者,用来规定不同事务的工作方式
tx:attributes ---> 通知者的一个子类,用法同上
aop:config ---> 切片,定义切片的位置
注解式:
transactionmanager ---> 事务管理者设置
<!-- 事物通知者annotation-driven -->
<tx:annotation-driven transaction-manager="transactionManager"/> ---> 通过事务管理者通知事务
<context:component-scan base-package="cn.jbit.service" /> ----> 扫描注解
@Transactional ---> 事务注释 (在目标类或者方法添加注解@Transactional。如果在类上添加,则说明类中的所有方法都添加事务,如果在方法上添加,则只有该方法具有事务。)
<!-- 使用注解注入事物、需要在各个service中的方法里添加、不建议使用-->