码迷,mamicode.com
首页 > 编程语言 > 详细

spring事务

时间:2015-05-02 12:25:05      阅读:255      评论:0      收藏:0      [点我收藏+]

标签:

一、Spring事务管理
在JavaEE分层开发中,事务管理代码放到业务层

1、 事务管理相关API
PlatformTransactionManager  平台事务管理器                
    * void commit(TransactionStatus status)  提交事务
    * TransactionStatus getTransaction(TransactionDefinition definition) 根据事务定义信息,获得当前状态
    * void rollback(TransactionStatus status)  回滚事务
 
TransactionDefinition  事务定义信息 (配置信息 来自xml配置文件 和 注解)
    包括 (隔离、传播、超时、只读)
    * ISOLATION_xxx 事务隔离级别
    * PROPAGATION_xxx  事务传播行为
    * int getTimeout()  获得超时信息
    * boolean isReadOnly()  判断事务是否只读

TransactionStatus 事务具体运行状态
    * 每一个时刻点 事务具体状态信息

关系:     PlatformTransactionManager 根据 TransactionDefinition 进行事务管理, 管理过程中事务存在多种状态, 每个状态信息通过 TransactionStatus 表示

2、 PlatformTransactionManager 接口详解
1) 不同平台事务管理器实现
    org.springframework.jdbc.datasource.DataSourceTransactionManager    使用Spring JDBC或iBatis 进行持久化数据时使用
    org.springframework.orm.hibernate3.HibernateTransactionManager    使用Hibernate3.0版本进行持久化数据时使用
    org.springframework.orm.jpa.JpaTransactionManager    使用JPA进行持久化时使用
    org.springframework.jdo.JdoTransactionManager    当持久化机制是Jdo时使用
    org.springframework.transaction.jta.JtaTransactionManager    使用一个JTA实现来管理事务,在一个事务跨越多个资源时必须使用

* 针对不同持久层技术,选用对应事务管理器

2) TransactionDefinition 事务隔离级别
事务四大特性 : ACID  原子性、一致性、隔离性、持久性
隔离性引发并发问题: 脏读、 不可重复读、 虚读
    * 脏读 一个事务读取另一个事务 未提交数据
    * 不可重复读 一个事务读取另一个事务 已经提交 update 数据
    * 虚读  一个事务读取另一个事务 已经提交 insert 数据
事务隔离级别 为了解决 事务隔离性引发 问题
    * DEFAULT 默认级别  mysql REPEATABLE_READ 、 oracle READ_COMMITTED
    * READ_UNCOMMITED  导致所有问题发生
    * READ_COMMITTED 防止脏读、 发生不可重复读和虚读
    * REPEATABLE_READ 防止脏读、不可重复读,发生虚读
    * SERIALIZABLE 防止所有并发问题

3) TransactionDefinition 事务的传播行为
    * 不是JDBC 规范定义
    * 传播行为 针对实际开发中问题

传播行为解决问题: 一个业务层事务 调用 另一个业务层事务,事务之间关系如何处理

七种传播行为
    PROPAGATION_REQUIRED    支持当前事务,如果不存在 就新建一个
        * 删除客户 删除订单, 处于同一个事务,如果 删除订单失败,删除客户也要回滚
    PROPAGATION_SUPPORTS    支持当前事务,如果不存在,就不使用事务
    PROPAGATION_MANDATORY    支持当前事务,如果不存在,抛出异常
    
    PROPAGATION_REQUIRES_NEW    如果有事务存在,挂起当前事务,创建一个新的事务
        * 生成订单, 发送通知邮件, 通知邮件会创建一个新的事务,如果邮件失败, 不影响订单生成
    PROPAGATION_NOT_SUPPORTED    以非事务方式运行,如果有事务存在,挂起当前事务
    PROPAGATION_NEVER     以非事务方式运行,如果有事务存在,抛出异常
    
    PROPAGATION_NESTED    如果当前事务存在,则嵌套事务执行
        * 依赖于 JDBC3.0 提供 SavePoint 技术
        * 删除客户 删除订单, 在删除客户后, 设置SavePoint, 执行删除订单,删除订单和删除客户在同一个事务 ,删除订单失败, 事务回滚 SavePoint , 由用户控制是事务提交 还是 回滚

重点:
PROPAGATION_REQUIRED 一个事务, 要么都成功,要么都失败
PROPAGATION_REQUIRES_NEW 两个不同事务,彼此之间没有关系  一个事务失败了 不影响另一个事务
PROPAGATION_NESTED  一个事务, 在A事务 调用 B过程中, B失败了, 回滚事务到 之前SavePoint , 用户可以选择提交事务或者回滚事务

=================================================================================================================================
3、 Spring 事务管理方式
    1) 编程式 事务管理  (了解)
    在代码中 通过 TransactionTemplate 手动进行事务管理 ,在实际开发中很少被用到
    2) 声明式 事务管理
    在配置文件中,对Bean的方法进行事务管理, 基于AOP思想 ,无需写代码, 开发中主流使用

4、 Spring 通过编程式 进行事务管理
第一步: 创建账户数据表

CREATE TABLE `account` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `money` double DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `account` VALUES (1, aaa, 1000);
INSERT INTO `account` VALUES (2, bbb, 1000);
   

 

 
第二步 : 编写转账操作程序  (数据库操作 JdbcTemplate )

AccountServiceImpl
    public class AccountServiceImpl implements AccountService {
        // 在Service中注入DAO
        private AccountDAO accountDAO;

        @Override
        public void transfer(String outAccount, String inAccount, double money) {
            accountDAO.outMoney(outAccount, money);
            accountDAO.inMoney(inAccount, money);
        }

        public void setAccountDAO(AccountDAO accountDAO) {
            this.accountDAO = accountDAO;
        }
    }

 


    

AccountDAOImpl
    public class AccountDAOImpl extends JdbcDaoSupport implements AccountDAO {

        @Override
        public void outMoney(String outAccount, double money) {
            String sql = "update account set money = money-? where name = ?";
            this.getJdbcTemplate().update(sql, money, outAccount);
        }

        @Override
        public void inMoney(String inAccount, double money) {
            String sql = "update account set money = money + ? where name = ?";
            this.getJdbcTemplate().update(sql, money, inAccount);
        }

    }    

 



配置applicationContext.xml
    <!-- 导入外部属性文件 -->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    
    <!-- 数据库连接池  -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"></property>
        <property name="jdbcUrl" value="${jdbc.url}"></property>
        <property name="user" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
    
    <!-- 业务层 -->
    <bean id="accountService" class="cn.itcast.spring.transaction.a_programing.AccountServiceImpl">
        <property name="accountDAO" ref="accountDAO"></property>
    </bean>
    
    <!-- DAO -->
    <bean id="accountDAO" class="cn.itcast.spring.transaction.a_programing.AccountDAOImpl">
        <!-- 将连接池注入给DAO ,JdbcDaoSupport 自动创建 JdbcTemplate对象 -->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

 


*********** 如果没有使用任何事务管理 , JdbcTemplate DAO 每个操作 就是单独的事务

第三步 : 在AccountService 中注入 TransactionTamplate  事务管理模板 ,完成事务管理
   

<!-- 事务管理模板 -->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <!-- 将管理器 注入给 模板 -->
        <property name="transactionManager" ref="transactionManager"></property>
    </bean>
    
    <!-- 事务管理器 -->
    <!-- org.springframework.jdbc.datasource.DataSourceTransactionManager 用来管理 jdbc操作事务的 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--  将连接池 注入给事务管理器  -->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <bean id="accountService" class="cn.itcast.spring.transaction.a_programing.AccountServiceImpl">
        <property name="accountDAO" ref="accountDAO"></property>
        <property name="transactionTemplate" ref="transactionTemplate"></property>
    </bean>

 



第四步 :使用TransactionTemplate 进行事务管理
  

 public void transfer(final String outAccount, final String inAccount,
            final double money) {
        // 使用 事务模板 管理事务
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(
                    TransactionStatus transactionStatus) {
                accountDAO.outMoney(outAccount, money);
                int d = 1 / 0;
                accountDAO.inMoney(inAccount, money);
            }
        });
    }

 


================================================================================================================
在实际开发中,因为编程式事务管理 存在代码侵入,所有不常使用, 通常通过 声明式事务管理

5、 通过TransactionProxyFactoryBean 对业务类创建代理,实现声明式事务管理
    *无需修改Service代码
    *通过applicationContext.xml 配置为AccountService 对象创建代理

必须配置事务管理器
   

<!-- 事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

 



为目标Service创建代理    
   

<bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <!-- 目标 -->
        <property name="target" ref="accountService"></property>
        <!-- 针对接口代理 -->
        <property name="proxyInterfaces" value="cn.itcast.spring.transaction.b_transactionproxyfactorybean.AccountService"></property>
        <!-- 增强  事务管理-->
        <property name="transactionManager" ref="transactionManager"></property>
        <property name="transactionAttributes">  <!-- 事务管理属性 -->
             <!-- 针对目标对象 每个方法 ,设置隔离级别、传播行为、是否只读 -->
             <props>
                 <!-- key就是方法名 -->
                 <!-- value prop格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception -->
                 <prop key="transfer">PROPAGATION_REQUIRED</prop>
             </props>
        </property>
    </bean>

 


使用该方式,在Test程序中,注入代理对象
    public class AccountServiceTest {
        @Autowired
        @Qualifier("accountServiceProxy") // 注入代理对象
        private AccountService accountService;
        ...
    }

事务属性设置 prop格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
    PROPAGATION 事务传播行为
    ISOLATION, 事务隔离级别
    readOnly  表示事务是只读的,不能进行修改操作
    -Exception 发生这些异常事务进行回滚 (默认发生任何异常事务都会回滚)
    +Exception 事务将忽略这些异常,仍然提交事务

*** 基于TransactionProxyFactoryBean 创建代理对象,进行事务管理,缺点需要为 每个Bean 都创建单独代理对象,开发量巨大

6、 基于tx配置 ,为目标对象进行自动代理 (重点 )
    在applicationContext.xml 引入 tx 和 aop 两个名词空间
    
    <!-- 使用tx定义 事务管理增强 -->
   

<tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!-- 方法的事务管理属性 -->
        <tx:attributes>
            <!--
                name="transfer" 事务管理方法名
                isolation="DEFAULT" 默认隔离级别
                propagation="REQUIRED"  默认传播行为
                read-only="false"  是否只读
                no-rollback-for=""  发生异常不会滚  类似+Exception
                rollback-for=""  发生异常回滚 类似-Exception
                timeout="-1"  不超时
            -->
            <tx:method name="transfer"/>
        </tx:attributes>
    </tx:advice>

 


    
   

<!-- 使用Aop 进行自动代理 -->
    <aop:config>
        <!-- 定义切点 -->
        <aop:pointcut expression="execution(* cn.itcast.spring.transaction.c_txconfig.AccountService+.*(..))" id="mypointcut"/>
        <!-- 定义切面 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="mypointcut"/>
    </aop:config>

 



*** 定义 事务管理 tx:advice 将增强代码 应用切点上

7、 基于注解的声明式事务管理 (重点)
    第一步 :在需要管理事务 类或者方法 上添加 @Transactional
    第二步: 在applicationContext.xml 配置
          

 <!-- 事务管理器 -->
            <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <property name="dataSource" ref="dataSource"></property>
            </bean>
            
            <!-- 注解事务管理 -->
            <tx:annotation-driven transaction-manager="transactionManager"/>

 


    
配置事务属性 通过@Transactional配置
    @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, readOnly = false, noRollbackFor = ArithmeticException.class, rollbackFor = NullPointerException.class, timeout = -1)
    * isolation 隔离级别
    * propagation 传播行为
    * readOnly 是否只读
    * noRollbackFor 发生异常不回滚
    * rollbackFor 发生异常回滚
    * timeout 超时时间 -1 不超时

spring事务

标签:

原文地址:http://www.cnblogs.com/chentaiyan/p/4471662.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!