zoukankan      html  css  js  c++  java
  • Spring总结之事务

    Spring事务

    1)定义

        事务是指多个操作单元组成的集合,多个操作单元是整体不可分割的,要么都成功,要么都不成功。必须遵守四个原则(ACID)

          ●原子性(Atomicity):即事务是不可分割的最小工作单元,事务内的操作要么全做,要么全不做;

          ●一致性(Consistency):在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数据还是应该处于正确的状态,即数据完整性约束没有被破坏;如银行转帐,A转帐给B,必须保证A的钱一定转给B,一定不会出现A的钱转了但B没收到,否则数据库的数据就处于不一致(不正确)的状态。

          ●隔离性(Isolation):并发事务执行之间互不影响,在一个事务内部的操作对其他事务是不产生影响,这需要事务隔离级别来指定隔离性;

          ●持久性(Durability):事务一旦执行成功,它对数据库的数据的改变必须是永久的,不会因比如遇到系统故障或断电造成数据不一致或丢失。

    2)Spring事务隔离级别

        spring有五大隔离级别,其在TransactionDefinition接口中定义。看源码可知,其默isolation_default(底层数据库默认级别),其他四个隔离级别跟数据库隔离级别一致。

        ●ISOLATION_DEFAULT:用底层数据库的默认隔离级别,数据库管理员设置什么就是什么

         ●ISOLATION_READ_UNCOMMITTED(未提交读):最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读)

         ●ISOLATION_READ_COMMITTED(提交读):一个事务提交后才能被其他事务读取到(该隔离级别禁止其他事务读取到未提交事务的数据、所以还是会造成幻读、不可重复读)、sql server默认级别

         ●ISOLATION_REPEATABLE_READ(可重复读):可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(该隔离基本可防止脏读,不可重复读(重点在修改),但会出现幻读(重点在增加与删除))(MySql默认级别,更改可通过set transaction isolation level 级别)

         ●ISOLATION_SERIALIZABLE(序列化):代价最高最可靠的隔离级别(该隔离级别能防止脏读、不可重复读、幻读)

    丢失更新:两个事务同时更新一行数据,最后一个事务的更新会覆盖掉第一个事务的更新,从而导致第一个事务更新的数据丢失,这是由于没有加锁造成的;

    幻读:同样的事务操作过程中,不同时间段多次(不同事务)读取同一数据,读取到的内容不一致(一般是行数变多或变少)。

    脏读:一个事务读取到另外一个未提及事务的内容,即为脏读。

    不可重复读:同一事务中,多次读取内容不一致(一般行数不变,而内容变了)。

    幻读与不可重复读的区别:幻读的重点在于插入与删除,即第二次查询会发现比第一次查询数据变少或者变多了,以至于给人一种幻象一样,而不可重复读重点在于修改,即第二次查询会发现查询结果比第一次查询结果不一致,即第一次结果已经不可重现了。

    数据库隔离级别越高,执行代价越高,并发执行能力越差,因此在实际项目开发使用时要综合考虑,为了考虑并发性能一般使用提交读隔离级别,它能避免丢失更新和脏读,尽管不可重复读和幻读不能避免,但可以在可能出现的场合使用悲观锁或乐观锁来解决这些问题。

    3)Spring事务管理

        (1)编程式事务管理       

            Spring 提供的事务模版类:org.springframework.transaction.support.TransactionTemplate

            事务管理器:org.springframework.jdbc.datasource.DataSourceTransactionManager

    <?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:context="http://www.springframework.org/schema/context"  
        xmlns:jee="http://www.springframework.org/schema/jee"  
        xmlns:tx="http://www.springframework.org/schema/tx"  
        xsi:schemaLocation="    
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd  
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd  
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd  
            http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd  
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
             
       <context:property-placeholder location="jdbc.properties"/>
       <!-- 数据源 -->
       <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
             <property name="driverClassName" value="${jdbc.driverClassName}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
       </bean>
        <!-- jdbcTemplate -->
       <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
             <property name="dataSource" ref="dataSource"></property>
       </bean>
       <!-- jdbc 事务管理器-->
       <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
             <property name="dataSource" ref="dataSource"></property>
       </bean>
       <!-- TransactionTemplate -->
       <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
             <property name="transactionManager" ref="transactionManager"></property>
       </bean>
       
       <!-- dao -->
       <bean id="userDao" class="top.ruandb.dao.impl.UserDaoImpl">
             <property name="jdbcTemplate" ref="jdbcTemplate"></property>
       </bean>
       <bean id="userService" class="top.ruandb.service.impl.UserServiceImpl">
             <property name="userDao" ref="userDao"></property>
             <property name="transactionTemplate" ref="transactionTemplate"></property>
       </bean>
        
    </beans>
    public class UserServiceImpl implements UserServiceI {
        private TransactionTemplate transactionTemplate;
        private UserDaoI userDao;
        public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
            this.transactionTemplate = transactionTemplate;
        }
        public void setUserDao(UserDaoI userDao) {
            this.userDao = userDao;
        }
            //addUser()和updateUser()在同一个事务中
        @Override
        public void addUser() {
            transactionTemplate.execute(new TransactionCallbackWithoutResult() {
                @Override
                protected void doInTransactionWithoutResult(TransactionStatus status) {
                    userDao.addUser();
                    userDao.updateUser();
                }
            });
        }
    }

    (2)声明式事务管理

            使用 XML 配置声明式事务;

    <?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:context="http://www.springframework.org/schema/context"  
        xmlns:jee="http://www.springframework.org/schema/jee"  
        xmlns:tx="http://www.springframework.org/schema/tx"  
        xsi:schemaLocation="    
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd  
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd  
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd  
            http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd  
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
             
       <context:property-placeholder location="jdbc.properties"/>
       <!-- 数据源 -->
       <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
             <property name="driverClassName" value="${jdbc.driverClassName}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
       </bean>
        <!-- jdbcTemplate -->
       <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
             <property name="dataSource" ref="dataSource"></property>
       </bean>
       <!-- jdbc 事务管理器-->
       <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
             <property name="dataSource" ref="dataSource"></property>
       </bean>
       <!-- 配置事务通知 -->
       <tx:advice id="txAdvice" transaction-manager="transactionManager">
             <tx:attributes>  
                <tx:method name="insert*" propagation="REQUIRED" />  
                <tx:method name="update*" propagation="REQUIRED" />  
                <tx:method name="edit*" propagation="REQUIRED" />  
                <tx:method name="save*" propagation="REQUIRED" />  
                <tx:method name="add*" propagation="REQUIRED" />  
                <tx:method name="new*" propagation="REQUIRED" />  
                <tx:method name="set*" propagation="REQUIRED" />  
                <tx:method name="remove*" propagation="REQUIRED" />  
                <tx:method name="delete*" propagation="REQUIRED" />  
                <tx:method name="change*" propagation="REQUIRED" />  
                <tx:method name="get*" propagation="REQUIRED" read-only="true" />  
                <tx:method name="find*" propagation="REQUIRED" read-only="true" />  
                <tx:method name="load*" propagation="REQUIRED" read-only="true" />  
                <tx:method name="*" propagation="REQUIRED" read-only="true" />  
            </tx:attributes>  
       </tx:advice>
       <aop:config>
             <aop:pointcut expression="execution(* top.ruandb.service.*.*(..))" id="serviceMethod"/>
             <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod"/>
       </aop:config>
      
       <!-- dao -->
       <bean id="userDao" class="top.ruandb.dao.impl.UserDaoImpl">
             <property name="jdbcTemplate" ref="jdbcTemplate"></property>
       </bean>
       <bean id="userService" class="top.ruandb.service.impl.UserServiceImpl">
             <property name="userDao" ref="userDao"></property>
       </bean>
        
    </beans>
            使用注解配置声明式事务( @Transactional);
    
    <?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:context="http://www.springframework.org/schema/context"  
        xmlns:jee="http://www.springframework.org/schema/jee"  
        xmlns:tx="http://www.springframework.org/schema/tx"  
        xsi:schemaLocation="    
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd  
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd  
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd  
            http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd  
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
             
       <context:property-placeholder location="jdbc.properties"/>
       <!-- 数据源 -->
       <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
             <property name="driverClassName" value="${jdbc.driverClassName}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
       </bean>
        <!-- jdbcTemplate -->
       <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
             <property name="dataSource" ref="dataSource"></property>
       </bean>
       <!-- jdbc 事务管理器-->
       <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
             <property name="dataSource" ref="dataSource"></property>
       </bean>
       <!-- 注解声明式事务,织入事务管理器 -->
      <tx:annotation-driven transaction-manager="transactionManager"/>
      
       <!-- dao -->
       <bean id="userDao" class="top.ruandb.dao.impl.UserDaoImpl">
             <property name="jdbcTemplate" ref="jdbcTemplate"></property>
       </bean>
       <bean id="userService" class="top.ruandb.service.impl.UserServiceImpl">
             <property name="userDao" ref="userDao"></property>
       </bean>
        
    </beans>
    @Transactional
    public class UserServiceImpl implements UserServiceI {
        private UserDaoI userDao;
        public void setUserDao(UserDaoI userDao) {
            this.userDao = userDao;
        }
        @Override
        public void addUser() {
                    userDao.addUser();
                    userDao.updateUser();
        }
    }

    4)事务的传播行为

        事务传播行为:Spring 中,当一个 service 方法调用另外一个 service 方法的时候,因为每个 service 方法都有事

    务,这时候就出现了事务的嵌套;由此,就产生了事务传播行为;

        在 Spring 中,通过配置 Propagation,来定义事务传播行为;

            PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

            PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。

            PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。

            PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。

            PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

            PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。

  • 相关阅读:
    MyEclipse Tern was unable to complete your request in time
    12.5.2 访问被覆盖的方法
    猎头、培训与咨询的价值(2)【补1】——北漂18年(93)
    12.5.1 通过 @ISA 继承
    从柯洁对战AlphaGo,看商业智能
    jquery ajax POST 例子详解
    利用组合索引优化
    Oracle range 分区表
    Perl 面向对象上
    JSON导出CSV中文乱码解决方案
  • 原文地址:https://www.cnblogs.com/jnba/p/10832722.html
Copyright © 2011-2022 走看看