spring-事务详细讲解(五)

Date: 2017-11-15 00:00:01

spring-事务(五)

文章说明:本文不会只做复制粘贴的动作,在讨论一个问题的时候,理论部分总是词不达意,所以会从网上找合适的描述文章作为本篇的开篇,后续的深入讨论基本都是自己实践经验所得。

先来看一下spring整块的逻辑图

前言

对于spring事务,我将分两大部分部分讲解:

  • 事务的基本配置与实践:申明式事务,编程式事务。
  • 事务内部处理:数据库隔离级别,事务的传播性;

sping事务概述(转载)

事务一般发生在和持久层打交道的地方,比如数据库。
假设一个工作由两件事共同组成,那么这两件事要么全部完成,这个工作才算完成。要么全部回退到初始状态。不存在只完成一件,还有一件事没完成的。这项工作可称为一个事务。常用的场景就是银行转账。A向B转账100元这项工作由两件事组成:A帐户减100元,B账户加100元。这两件事要么同时完成,要么同时都回退到初始状态。如果只完成其中一件,另一件没完成,那就出岔子了。。

事务有四个特性:ACID

  • 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。
  • 一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。
  • 隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。
  • 持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。

事务的大概基本原理

Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行:

1.获取连接 Connection con = DriverManager.getConnection()
2.开启事务con.setAutoCommit(true/false);
3.执行CRUD
4.提交事务/回滚事务 con.commit() / con.rollback();
5.关闭连接 conn.close();

使用Spring的事务管理功能后,我们可以不再写步骤1,2,3 和 4,5 的代码,而是由Spirng 自动完成。后面将会讲解原理

真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。
mysql的数据处理引擎如果是MyISAM的话,则事务无效,因为该引擎不支持数据库事务。

spring编程式事务管理器

spring有申明式事务,编程式事务,都是通过管理器来完成了,只是各自封装了一下,方便用户调用而已。

Spring提供了许多内置事务管理器实现:

  • DataSourceTransactionManager:位于org.springframework.jdbc.datasource包中,数据源事务管理器,提供对单个javax.sql.DataSource事务管理,用于Spring JDBC抽象框架、iBATIS或MyBatis框架的事务管理;
  • HibernateTransactionManager:位于org.springframework.orm.hibernate3包中,提供对单个org.hibernate.SessionFactory事务支持,用于集成Hibernate框架时的事务管理;该事务管理器只支持Hibernate3+版本,且Spring3.0+版本只支持Hibernate3.2+版本;
  • JpaTransactionManager:位于org.springframework.orm.jpa包中,提供对单个javax.persistence.EntityManagerFactory事务支持,用于集成JPA实现框架时的事务管理;
  • JtaTransactionManager:位于org.springframework.transaction.jta包中,提供对分布式事务管理的支持,并将事务管理委托给Java EE应用服务器事务管理器;
  • JdoTransactionManager:位于org.springframework.orm.jdo包中,提供对单个javax.jdo.PersistenceManagerFactory事务管理,用于集成JDO框架时的事务管理;
  • OC4JjtaTransactionManager:位于org.springframework.transaction.jta包中,Spring提供的对OC4J10.1.3+应用服务器事务管理器的适配器,此适配器用于对应用服务器提供的高级事务的支持;
  • WebSphereUowTransactionManager:位于org.springframework.transaction.jta包中,Spring提供的对WebSphere 6.0+应用服务器事务管理器的适配器,此适配器用于对应用服务器提供的高级事务的支持;
  • WebLogicJtaTransactionManager:位于org.springframework.transaction.jta包中,Spring提供的对WebLogic8.1+应用服务器事务管理器的适配器,此适配器用于对应用服务器提供的高级事务的支持。

spring事务实战-基本配置

spring声明式事务

第一种配置:单独开启事务

单独开启为需要手动加入@Transactional来告诉spring这个方法或者类需要加入事务。

在spring配置文件的applicationContext.xml中设置:
第一步:在配置文件中开启事务

   <!--1. 配置数据源-->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>


    <!--2. 设置事务实例-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--3. 添加事务,开启事务注解-->
    <tx:annotation-driven transaction-manager="transactionManager"/>

第二步:应用事务
@Transactional 告诉spring则个方法需要添加事务增强功能。

@Transactional
    public void serviceFG() {
        userInfoExtendService.serviceG();

        try {
            userInfoExtendService.serviceF();
        } catch (Exception e) {
            //e.printStackTrace();
        }
    }

这样一个简单的事务就完成了。

Transactional说明

参数名称 功能描述
readOnly 该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)
rollbackForClassName 该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。指定单一异常类名称:@Transactional(rollbackForClassName=”RuntimeException”),指定多个异常类名称:@Transactional(rollbackForClassName={“RuntimeException”,”Exception”})
rollbackFor 该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:指定单一异常类:@Transactional(rollbackFor=RuntimeException.class),指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})
noRollbackFor 该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class),指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})
noRollbackForClassName 该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:指定单一异常类名称:@Transactional(noRollbackForClassName=”RuntimeException”)指定多个异常类名称:@Transactional(noRollbackForClassName={“RuntimeException”,”Exception”})readOnly
propagation 该属性用于设置事务的传播行为
isolation 该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置
timeout 该属性用于设置事务的超时秒数,默认值为-1表示永不超时

全局事务配置

在spring配置文件的applicationContext.xml中设置:

   <!--1. 配置数据源-->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>


    <!--2. 设置事务实例-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--3. 添加事务,开启事务注解-->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    <!--4. 设置全局事务范围-->
    <aop:config>
        <aop:pointcut id="serviceOperation"
                      expression="execution(* com.spring.test.*.service.*.*(..)) || execution(* com.spring.test.*.business.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation"/>
    </aop:config>

   <!-- 5. 设置请求类型-->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <!-- the transactional semantics... -->
        <tx:attributes>
            <!-- all methods starting with 'get' are read-only -->
            <!--<tx:method name="get*" read-only="true"/>-->
            <!-- other methods use the default transaction settings (see below) -->
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

com.spring.test.*.service.*.*(..) 这个表示com.spring.test.* 这个包下所有的包,在这个所有包下面的sercie包下的所有包下的所有方法都添加事务。
*:代表一层文件夹;
*():代表任意方法。也可以service*(..);
(..):表示方法的任意参数。
对于这种正则表达式不懂的,可以看spring aop正则表达式。

第二步:代码

package com.spring.test.service.impl;

public void serviceFG() {
        userInfoExtendService.serviceG();

        try {
            userInfoExtendService.serviceF();
        } catch (Exception e) {
            //e.printStackTrace();
        }
    }

由于该方法在上面配置的表达式中,所以serviceFG不用添加注解也拥有了事务哦。
上面都是对jdbc的事务配置,hibernate与jpa等其他事务的配置

spring编程式事务

手动编写spring事务

  <!--数据源-->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>

    <!--使用jdbc模板操作数据库-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg ref="dataSource"/>
    </bean>

    <!--设置dao,用来操作数据库的-->
    <bean id="userInfoDao" class="com.test.spring.dao.impl.UserInfoDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>

    <!--设置事务实例-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean> 

    <bean id="userInfoExtendService" class="com.test.spring.service.impl.UserInfoExtendServiceImpl">
        <property name="userInfoDao" ref="userInfoDao"/>
        <!--第一种编程式事务-->
        <property name="txManager" ref="transactionManager"/>
        <property name="txDefinition">
            <bean class="org.springframework.transaction.support.DefaultTransactionDefinition">
                <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
            </bean>
        </property>
        <!--第二种编程式事务,使用模版的方式,和第一种是一样的,只不过template封装了第一种方式而已,使用更方便而已-->
        <property name="transactionTemplate" ref="transactionTemplate"/>

    </bean>

第二步代码:

public class UserInfoExtendServiceImpl{

    private UserInfoDao userInfoDao;

    private TransactionDefinition txDefinition;
    private PlatformTransactionManager txManager;

    private TransactionTemplate transactionTemplate;
    public PlatformTransactionManager getTxManager() {
        return txManager;
    }

    public void setTxManager(PlatformTransactionManager txManager) {
        this.txManager = txManager; 

    public void setTxDefinition(TransactionDefinition txDefinition) {
        this.txDefinition = txDefinition;
    }

    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }

    public void setUserInfoDao(UserInfoDao userInfoDao) {
        this.userInfoDao = userInfoDao;
    }

    //第一种,纯手动编写
    public void serviceJ() {
        TransactionStatus txStatus = txManager.getTransaction(txDefinition);
        try {
            UserInfoVo infoVo = new UserInfoVo();
            infoVo.setAge(1000);
            infoVo.setUserName("J");
            userInfoDao.save(infoVo);
            txManager.commit(txStatus);
        } catch (Exception e) {
            txManager.rollback(txStatus);
            System.out.println("Transfer Error!");
        }
    }

    //第二种,使用模版管理
    public boolean transfer() {
        return (Boolean) transactionTemplate.execute(new TransactionCallback() {
            public Object doInTransaction(TransactionStatus status) {
                Object result = true;
                try {
                    UserInfoVo infoVo = new UserInfoVo();
                    infoVo.setAge(1000);
                    infoVo.setUserName("transfer");
                    userInfoDao.save2(infoVo);
                } catch (Exception e) {
                    status.setRollbackOnly();
                    result = false;
                    System.out.println("Transfer Error!");
                }
                return result;
            }
        });
    }


}    

参考

http://blog.csdn.net/soonfly/article/details/70304793(事务理论)
http://www.uml.org.cn/j2ee/201610201.asp
https://www.ibm.com/developerworks/cn/education/opensource/os-cn-spring-trans/

猜你喜欢

转载自blog.csdn.net/piaoslowly/article/details/81743640