Sping学习——事务

事务简介

事务的出现是为了保证数据的完整性和一致性,为了防止意外的中断致使数据出现错误.spring

事务三大接口

  1. PlatformTransactionManager 事务管理器.
    1.DataSourceTransactionManager:只能处理一个数据源,经过JDBC进行CRUD处理.
    2.JtaTransactionManager: JTA进行事务管理.
    3.HibernateTransactionManager:Hibernate框架操做数据库.
  2. TransactionDefinition 保存了事务基础信息,例如事物的传播属性、隔离级别等.
  3. TransactionStatus 保存了事务状态信息,该事物是不是一个新的事务,是否提交是否须要回滚等.

事务四大特性

  1. 原子性:简单来讲就是事物的操做都是不可再分的,事务要么一块儿执行,要么一块儿都不执行.
  2. 一致性:事务执行后,执行先后的数据都必须是正确的,否则就要采起rollback(回滚)操做.
  3. 隔离性:多个事务一块儿并发执行时,应该始终保持互相隔离,例如两个事物同时修改一个数据时,只有其中一个事务进行commit修改数据成功后,另外一个事务才开始修改.
  4. 持久性:事务修改数据一旦成功,这个数据应该是永久保存的不受其余错误影响.

Spring中的事物管理

在Spring中事务的主要使用方式有两种,一种是编程式事务管理另外一种是声明式事务管理.编程式事务使用的是JDBC的原生API须要编写大量代码太过麻烦。所以如今Spring主要使用的是声明式事务编程,Spring中的声明式事务编程是基于AOP模式的,也就是在@before以前建立一个事物,@AfterRetuning以前确认一下事务是否须要回滚.声明式事务的最大优势就是不用写一堆代码而能够直接经过注解(基于@Transaction注解)和配置文件(基于tx和aop命名空间)完成事务管理.数据库

事务使用

@Transaction注解式

XML文件express

<!--引入事务管理器-->
     <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
         <property name="dataSource" ref="pooledDataSource"></property>
     </bean>
      <!--依赖tx名称空间,开启事务注解-->
     <tx:annotation-driven transaction-manager="transactionManager"/>

@Transaction注解主要是添加在Service组件的方法下编程

@Transactional(propagation=Propagation.REQUIRES,isolation=READ_COMMITTED)
    public void updateBook(String name,int price){
        libaryDao.updateBook(name, price);
    }

XML配置模式

<!--引入事务管理器-->
     <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
         <property name="dataSource" ref="pooledDataSource"></property>
     </bean>
    
     <aop:config>
        <!-- 配置事务切入点,哪些类哪些方法须要切入事务-->
         <aop:pointcut expression="execution(* com.libary.service*.*.*(..))" id="Point"/>
         <aop:advisor advice-ref="MyTx" pointcut-ref="Point"/>
     </aop:config>
     <!--  配置事务管理器 -->
     transaction-manager="transactionManager":
     <tx:advice id="MyTx" transaction-manager="transactionManager">
             <!--事务的属性  -->
             <tx:attributes>
                <!--tx:method 指定了哪些方法须要加事务 -->
                 <tx:method name="*"/>
                 <tx:method name="update" propagation="REQUIRED" timeout="-1"/>
                 <tx:method name="query*" read-only="true"/>
             </tx:attributes>
     </tx:advice>

与Aop的使用相同,事务使用的思想应该是,重要的事务使用xml配置,不重要的事务使用@Transaction.并发

事务属性

noRollbackFor:指定异常事务不回滚.
rollbackFor:指定异常事务回滚(编译时错误原本不回滚使其回滚,编译时错误默认是不回滚的除非使用try catch捕捉错误,可是运行错误是必定进行回滚)
timeout:事务超出指定时间即回滚,防止事务占用资源.
readOnly:只能够添加在查询事务上,能够优化事务的查询速度.
isolation:隔离级别下面重点提到.
propagation:传播行为下面重点提到.
多种事务嵌套运行时,下面的事务服从顶层事务的属性.框架

事务传播行为

传播行为的做用

事物的传播行为主要是为了处理当有多个事务嵌套执行时,其中某个事务出现了错误,有哪些事务须要进行回滚.
如如下状况优化

TestTx()
{
    A事务(REQUIRED)
    {
        B事务(REQUIRED_NEW)
        {
            C事务(REQUIRED)
            {
            }
        }
        D事务(REQUIRED)
        {
            E事务(REQUIRED)
            {
            }
        }
        F事务(REQUIRED_NEW)
    }     
}

传播行为

image

注意

平常事务管理中主要特别注意的事务是REQUIRED和REQUIRED_NEW
REQUIRED。
REQUIRED:REQUIRED的意思是与他的上层事务同生共死,你们共用一个事物。即如上代码,若是D出现错误了A也出现错误,你们一块儿进行rollback。
REQUIRED_NEW:REQUIRED_NEW的意思是我本身玩我本身的,我本身有一个事物,例如F出现错误了,与A事务有太多关系。F进行rollback,A不rollback。
特殊状况:如上代码,若是D出现错误了,那么即使F是REQUIRED_NEW也不会执行,由于到D已经就直接抛出错误了。
重要的一点:
1.无论哪里出错,已经执行完的REQUIRED_NEW都不会出错。
2.嵌套事务中由最顶层事务来决定Timeout等属性。spa

事物的隔离级别

事务并发会出现的问题:

  1. 脏读:事务A修改数据事务B读取数据,事务A进行数据修改后还未正式提交,事务B已经读取数据。可是事务A将数据rollback了.则事务B读出了假数据.脏读通常是绝对不可容许的.
例:x=10;
   A事务修改x=5但还未commit;
   B读出x=5;
   A进行rollback,x=10;
   B读出的x=5是假数据
  1. 不可重复读:事务B读取了数据,事务A修改了数据并无rollback,事务B再读取数据,第一次读取数据不一样.
例:x=10;
   B事务读取x=10;
   A事务修改x=5并commit;
   B再次读取x=5,两次读取x不一样;
  1. 幻读:事务B读取数据,事务A添加了数据,事务B再次读取发现数据多了不少出来.
例:x=10;
   B事务读取x=10;
   A事务添加y=20,i=30;
   B再次读取读出x=10,,y=20,i=30.多出大量数据。

隔离级别

使用@Transaction的isolation=Propagation.?属性设置隔离级别.代理

例:@Transactional(propagation=Propagation.REQUIRES_NEW,isolation=READ_COMMITTED)

READ_UNCOMMITTED(读未提交):容许脏读、不可重读读、幻读.
READ_COMMITTED(读已提交):容许不可重读和幻读,不容许脏读.
REPEATABLE READ(可重复读):容许幻读,不容许脏读和不可重复读.
SERIALIZABLE(串行化):不容许脏读、不可重复读、幻读.code

特别注意

最后特别要注意的是千万不要在某个Service组件中调用Service的事务方法(即不要调用本类方法),要记住Spring中的事物使用是基于AOP的,因此事务须要用代理对象,而直接在本类中调用的方法是没法进行事务的。本类方法的嵌套无论调用多少个都是单个事务.

例:
@Service
public class LibaryService{
    @Autowired
    LibaryDao libaryDao;
  
  @Transaction(propagation=Propagation.REQUIRES_NEW)
  public int updateBook(String name,int price)
  {
     libaryDao.update(name,price);
  }
  
  @Transaction(propagation=Propagation.REQUIRES_NEW)
  public Book QueryBook(int Id)
  {
    libaryDao.QueryBook(Id);
  }
  
 //如下代码只有errorway()会被当成一个事物。而下方的updateBook()和QueryBook()由于是调用了本类方法,没有使用代理对象,因此不会通过事务处理。
 @Transaction
  public void errorway()
  {
    updateBook("三毛流浪记",56);
    QueryBook("射雕英雄传");
  }
相关文章
相关标签/搜索