事务管理对于企业应用至关重要。它保证了用户的每一次操作都是可靠的,即便出现了异常的访问情况,也不至于破坏后台数据的完整性。
    就像银行的自助取款机,通常都能正常为客户服务,但是也难免遇到操作过程中机器突然出故障的情况,此时,事务就必须确保出故障前对账户的操作不生效,就像用户刚才完全没有使用过取款机一样,以保证用户和银行的利益都不受损失。
 
一、事务的介绍
    事务是若干个操作组合在一起,形成一个原子性的工作单元。这一组操作要么全部成功,要么全部失败。
 
    事务的特性:
    事务有四个特性,分别是ACID,也就是原子性、一致性、隔离性和持久性。
    原子性(Atomicity):事务是一个原子操作,由一系列的动作组成,要么全部成功,要么全部失败。
    一致性(Consistency):事务一旦完成,系统必须确保数据的完整性,而不会部分成功,部分失败。
    隔离性(Isolation):可能存在多个事务处理相同的数据,这时,事务之间应该隔离开来,防止数据被损坏。
    持久性(Durability):事务一旦完成,数据就被持久化到硬盘了。
 
    隔离存在的问题:
    脏读(dirty read):A事务读到了B事务未提交了数据,而B事务又回滚了,所以A事务读到的是无效数据。
    不可重复读(norepeatable read):A事务两次(或者多次)查询到的数据不相同,因为B事务在A的两次查询期间对数据进行了更新。
    幻读(phantom read):A事务两次(或者多次)查询到的数据不相同,因为B事务在A的两次查询期间插入了新的数据。
 
    因为存在隔离问题,所以有隔离级别来解决这些问题。
    隔离级别:
    read uncommitted:读未提交。
    read committed:读已提交。该级别解决了脏读。
    repeatable read:可重复读。该级别解决了脏读和不可重复读。
    serializable:串行化。解决全部问题,但是效率最低。因为它在操作的时候,完全锁定了相关的表,其他事务只能处于等待状态。
 
    Java模拟事务操作:
Connection conn = null;
try{
    conn = getConnection();
    conn.setAutoCommit(false);    //关闭事务的自动提交
    A
    B
    C
    D
    conn.commit();
}catch(){
    conn.rollback();
}
    ABCD是同一个事务内的动作。ABCD有任何一个动作抛了异常,都将进入catch块中进行事务回滚。
    
     Java模拟带保存点的事务操作:   
Connection conn = null;
Savepoint savepoint = null;
try{
    conn = getConnection();
    conn.setAutoCommit(false);    //关闭事务的自动提交
    A
    B
    savepoint = conn.setSavepoint();
    C
    D
    conn.commit();
}catch(){
    if(savepoint != null){    //savepoint不为空,说明已经执行到了C或者D
        conn.rollback(savepoint);    //回滚到保存点
    }else{
        conn.rollback();     //savepoing为空,说明在执行A或者B的时候就抛了异常
    }
}
二、Spring事务的API
    在 Spring 中,事务是通过 TransactionDefinition 接口来定义的。
    Spring为了管理事务,设计了三个顶级接口,Spring的事务管理就是围绕这三个顶级接口而展开的。 

    我们重点解析事务详情,事务详情也叫事务定义,或者事务属性。
    事务详情中定义两组常量,分别用来描述 隔离级别 和 传播行为
 
    隔离级别:
        隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:
        isolation_default = -1,默认值,使用数据库的隔离级别。
        isolation_read_uncommitted = 1, 读未提交
        isolation_read_committed = 2, 读已提交
        isolation_repeatable_read = 4, 可重复读
        isolation_serializable = 8, 串行化
        1、2、4、8这四个常量值是定义在java.sql.Connection接口中
 
    传播行为:
        所谓事务的传播行为是指,如果在当前事务开始之前,一个事务上下文已经存在,此时有若干选项可以指定当前事务性方法的执行行为。
        假设现在有A、B两个操作。     
        propagation_required = 0,默认值,如果A有事务,B就使用A的事务。如果A没事务,B创建一个新事务。
        propagation_supports = 1,如果A有事务,B就使用A的事务。如果A没事务,B以非事务执行。
        propagation_mandatory = 2,如果A有事务,B就事务A的事务。如果A没事务,B会抛出异常。
        propagation_requires_new = 3,如果A有事务,将A的事务挂起,B创建一个新事务执行,如果A没事务,B也创建一个新事务执行。
        propagation_not_supported = 4,如果A有事务,将A的事务挂起,B以非事务执行。如果A没事务,B也以非事务执行。
        propagation_never = 5,如果A有事务,B将抛异常。如果A没事务,B以非事务执行。
        propagation_nested = 6,如果A有事务,B的事务将嵌套在A的事务里面执行。B的事务执行完之后,再出来继续执行A的事务,所以A事务中得有个保存点。
 
    事务超时:
        所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。
 
    事务的只读属性:
        事务的只读属性是指,对事务性资源进行只读操作或者是读写操作。所谓事务性资源就是指那些被事务管理的资源,比如数据源、 JMS 资源,以及自定义的事务性资源等等。
        如果确定只对事务性资源进行只读操作,那么我们可以将事务标志为只读的,以提高事务处理的性能。在 TransactionDefinition 中以 boolean 类型来表示该事务是否只读。
 
    事务的回滚规则:
        通常情况下,如果在事务中抛出了未检查异常(继承自 RuntimeException 的异常),则默认将回滚事务。如果没有抛出任何异常,或者抛出了已检查异常,则仍然提交事务。
        这通常也是大多数开发者希望的处理方式。但是,我们可以根据需要人为控制事务在抛出某些未检查异常时依然提交事务,或者在抛出某些已检查异常时回滚事务。
 
 
三、手动编程管理事务(基于底层API)
        根据PlatformTransactionManager、TransactionDefinition 和 TransactionStatus 三个核心接口,我们完全可以通过编程的方式来进行事务管理。
        下面给出一个小demo:
        数据库: 
  

        1. dao层

package cn.african.dao;
public interface BankDao {
    boolean transfer(Long fromId, Long toId, double amount);
}

package cn.african.dao;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
public class BankDaoImpl extends JdbcDaoSupport implements BankDao {

    @Override
    public boolean transfer(Long fromId, Long toId, double amount) {
        int f = this.getJdbcTemplate().update("update account set money = money - ? where id = ?", amount, fromId);
        //异常
        int i = 1 / 0;
        int t = this.getJdbcTemplate().update("update account set money = money + ? where id = ?", amount, toId);
        if(f > 0 && t > 0) {
            return true;
        }
        return false;
    }
}

        2. service层

package cn.african.service;
public interface BankService {
    public boolean transfer(Long fromId, Long toId, double amount);
}

package cn.african.service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import cn.african.dao.BankDao;

public class BankServiceImpl implements BankService {
    private BankDao bankDao;
    //事务详情
    private TransactionDefinition txDefinition;
    //事务管理器
    private PlatformTransactionManager txManager;

    @Override
    public boolean transfer(Long fromId, Long toId, double amount) {
        TransactionStatus txStatus = txManager.getTransaction(txDefinition);
        boolean result = false;
        try {
            result = bankDao.transfer(fromId, toId, amount);
            txManager.commit(txStatus);
        } catch (Exception e) {
            result = false;
            txManager.rollback(txStatus);
            System.out.println("转账失败");
        }
        return result;
    }

    public void setBankDao(BankDao bankDao) {
        this.bankDao = bankDao;
    }
    public void setTxDefinition(TransactionDefinition txDefinition) {
        this.txDefinition = txDefinition;
    }
    public void setTxManager(PlatformTransactionManager txManager) {
        this.txManager = txManager;
    }
}

    3. applicationContext.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/txdemo" />
        <property name="user" value="root" />
        <property name="password" value="123456" />
    </bean>

    <bean id="bankDao" class="cn.african.dao.BankDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <bean id="bankService" class="cn.african.service.BankServiceImpl">
        <property name="bankDao" ref="bankDao" />
        <property name="txManager" ref="txManager" />
        <!-- 定义事务详情 -->
        <property name="txDefinition">
            <bean class="org.springframework.transaction.support.DefaultTransactionDefinition">
                <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED" />
            </bean>
        </property>
    </bean>
</beans>

        4. 测试类

package cn.african.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.african.service.BankService;

public class TestApp {

    @Test
    public void demo01() throws Exception {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        BankService bankService = context.getBean("bankService", BankService.class);
        bankService.transfer(1L, 2L, 1000D);
        context.getClass().getMethod("close").invoke(context);
    }
}
        测试之后可以看到,数据库的数据并没有发生改变。
四、手动编程管理事务(基于TransactionTemplate)
        通过前面的示例可以发现,这种事务管理方式很容易理解,但令人头疼的是,事务管理的代码散落在业务逻辑代码中,破坏了原有代码的条理性,并且每一个业务方法都包含了类似的启动事务、提交/回滚事务的样板代码。
        幸好,Spring 也意识到了这些,并提供了简化的方法,这就是 Spring 在数据访问层非常常见的模板回调模式。
        我们再实现一个基于TransactionTemplate的demo:
        1. dao层(如上)
        2. service层
package cn.african.service;
public interface BankService {
    public boolean transfer(Long fromId, Long toId, double amount);
}

package cn.african.service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import cn.african.dao.BankDao;

public class BankServiceImpl implements BankService {
    private BankDao bankDao;
    private TransactionTemplate transactionTemplate;

    @Override
    public boolean transfer(Long fromId, Long toId, double amount) {

        return transactionTemplate.execute(new TransactionCallback<Boolean>() {
            boolean result = false;
            @Override
            public Boolean doInTransaction(TransactionStatus status) {
                try {
                    bankDao.transfer(fromId, toId, amount);
                    result = true;
                } catch (Exception e) {
                    //设置回滚
                    status.setRollbackOnly();
                    System.out.println("转账失败");
                }
                return result;
            }
        });
    }

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

    3. applicationContext.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/txdemo" />
        <property name="user" value="root" />
        <property name="password" value="123456" />
    </bean>

    <bean id="bankDao" class="cn.african.dao.BankDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <bean id="bankService" class="cn.african.service.BankServiceImpl">
        <property name="bankDao" ref="bankDao"></property>
        <property name="transactionTemplate" ref="txTemplate"></property>
    </bean>

    <bean id="txTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="txManager"></property>
    </bean>

</beans>
    4. 测试类(如上)
五、声明式事务管理
    Spring 的声明式事务管理在底层是建立在 AOP 的基础之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
    声明式事务管理有四种方式:
    1. 基于TransactionInterceptor 类来进行声明式事务管理
    2. 基于TransactionProxyFactoryBean来进行声明式事务管理
    3. 基于 <tx> 命名空间进行声明式事务管理
    4. 基于 @Transactional 注解来进行声明式事务管理
    
    
    5.1  基于TransactionInterceptor 类来进行声明式事务管理
    首先我们看一下这种方式的配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ee19_spring_day03" />
        <property name="user" value="root" />
        <property name="password" value="123456" />
    </bean>

    <bean id="bankDao" class="cn.african.dao.BankDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--这个事务拦截器就是切面-->
    <bean id="txInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
        <property name="transactionManager" ref="txManager"/>
        <property name="transactionAttributes">
            <props>
                <prop key="transfer">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>

    <bean id="bankServiceTarget" class="cn.african.service.BankServiceImpl">
        <property name="bankDao" ref="bankDao"/>
    </bean>

    <bean id="bankService" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!--目标类-->
        <property name="target" ref="bankServiceTarget"/>
        <!--配置切面-->
        <property name="interceptorNames">
            <list>
                <idref bean="txInterceptor"/>
            </list>
        </property>
    </bean>
</beans>
    首先,我们配置了一个 TransactionInterceptor 来定义相关的事务规则,他有两个主要的属性:一个是 transactionManager,用来指定一个事务管理器,并将具体事务相关的操作委托给它;
    另一个是 Properties 类型的 transactionAttributes 属性,它主要用来定义事务规则,该属性的每一个键值对中,键指定的是方法名,方法名可以使用通配符,而值就表示相应方法的所应用的事务属性。
    指定事务属性的具体的书写规则如下: 
传播行为 [,隔离级别] [,只读属性] [,超时属性] [不影响提交的异常] [,导致回滚的异常] 
    其中传播行为是必须的,其他都是可选的。
    超时属性的取值必须以“TIMEOUT_”开头,后面跟一个int类型的值,表示超时时间,单位是秒。
    不影响提交的异常是指,即使事务中抛出了这些类型的异常,事务任然正常提交。必须在每一个异常的名字前面加上“+”。异常的名字可以是类名的一部分。比如“+RuntimeException”、“+tion”等等。
    导致回滚的异常是指,当事务中抛出这些类型的异常时,事务将回滚。必须在每一个异常的名字前面加上“-”。异常的名字可以是类名的全部或者部分,比如“-RuntimeException”、“-tion”等等。
    给一个书写例子:    
<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED,TIMEOUT_20,+AException,+BException,-CException</prop>
    使用 PROPAGATION_REQUIRED 事务传播行为,事务的隔离级别是 ISOLATION_READ_COMMITTED,超时时间为20秒,当事务抛出 AException 或者 BException 类型的异常,则仍然提交,当抛出 CException 类型的异常时必须回滚事务。
    这里没有指定"readOnly",表示事务不是只读的。
    由于Spring是通过感知异常来决定是否回滚,所以此时在Service中,我们不能再去捕获异常,这个异常必须要让Spring知道。所以Service实现类改成了:
package cn.african.service;
import cn.african.dao.BankDao;

public class BankServiceImpl implements BankService {
    private BankDao bankDao;

    @Override
    public boolean transfer(Long fromId, Long toId, double amount) {
        //这种方式,在这里不能自己去捕获异常,这个异常必须由spring感知
        return bankDao.transfer(fromId, toId, amount);
    }

    public void setBankDao(BankDao bankDao) {
        this.bankDao = bankDao;
    }
}
    5.2   基于TransactionProxyFactoryBean来进行声明式事务管理
    前面的声明式事务虽然好,但是却存在一个非常恼人的问题:配置文件太多。我们必须针对每一个目标对象配置一个 ProxyFactoryBean;
    为了缓解这个问题,Spring 为我们提供了 TransactionProxyFactoryBean,用于将TransactionInterceptor 和 ProxyFactoryBean 的配置合二为一。   
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ee19_spring_day03" />
        <property name="user" value="root" />
        <property name="password" value="123456" />
    </bean>

    <bean id="bankDao" class="cn.african.dao.BankDaoImpl">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <bean id="bankServiceTarget" class="cn.african.service.BankServiceImpl">
        <property name="bankDao" ref="bankDao"/>
    </bean>

    <bean id="bankService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="target" ref="bankServiceTarget"/>
        <property name="transactionManager" ref="txManager"/>
        <property name="transactionAttributes">
            <props>
                <prop key="transfer">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>
</beans>
    5.3   基于 <tx> 命名空间进行声明式事务管理
    前面两种声明式事务配置方式奠定了 Spring 声明式事务管理的基石。在此基础上,Spring 2.x 引入了 <tx> 命名空间,结合使用 <aop> 命名空间,配置变得更加简单和灵活。
 另外,得益于 <aop> 命名空间的切点表达式支持,声明式事务也变得更加强大。
<?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:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ee19_spring_day03" />
        <property name="user" value="root" />
        <property name="password" value="123456" />
    </bean>

    <bean id="bankDao" class="cn.african.dao.BankDaoImpl">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="bankService" class="cn.african.service.BankServiceImpl">
        <property name="bankDao" ref="bankDao"/>
    </bean>

    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="transfer" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!--如果事务的默认配置就能满足需求,上面元素的配置可以简化为以下方式-->
    <!-- <tx:advice id="txAdvice" transaction-manager="txManager" /> -->

    <aop:config>
        <aop:pointcut expression="execution(* cn.african.service..*.*(..))" id="txPointcut"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>

</beans>
    由于使用了切点表达式,我们就不需要针对每一个业务类创建一个代理对象了。
    另外,如果配置的事务管理器 Bean 的名字取值为“transactionManager”,则我们可以省略 <tx:advice> 的 transaction-manager 属性,因为该属性的默认值即为“transactionManager”。
 
    5.4. 基于 @Transactional 注解来进行声明式事务管理
    除了基于命名空间的事务配置方式,Spring 2.x 还引入了基于 Annotation 的方式,具体主要涉及@Transactional 标注。@Transactional 可以作用于接口、接口方法、类以及类方法上。
    当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。
   删除通知配置和aop编程的配置,添加注解驱动:
<?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:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/ee19_spring_day03" />
        <property name="user" value="root" />
        <property name="password" value="123456" />
    </bean>

    <bean id="bankDao" class="cn.african.dao.BankDaoImpl">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="bankService" class="cn.african.service.BankServiceImpl">
        <property name="bankDao" ref="bankDao"/>
    </bean>
    <!-- 使用事务注解时,必须要开启注解驱动 -->
    <tx:annotation-driven transaction-manager="txManager"/>

</beans>
        transaction-manager 属性的默认值是 transactionManager,如果事务管理器 Bean 的名字即为该值,则可以省略该属性。
        虽然 @Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 小组建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。
        另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。
 
结束语
        1.  基于 TransactionDefinition、PlatformTransactionManager、TransactionStatus 编程式事务管理是 Spring 提供的最原始的方式,通常我们不会这么写,但是了解这种方式对理解 Spring 事务管理的本质有很大作用。
        2.  基于 TransactionTemplate 的编程式事务管理是对上一种方式的封装,使得编码更简单、清晰。
        3.  基于 TransactionInterceptor 的声明式事务是 Spring 声明式事务的基础,通常也不建议使用这种方式,但是与前面一样,了解这种方式对理解 Spring 声明式事务有很大作用。
        4.  基于 TransactionProxyFactoryBean 的声明式事务是上中方式的改进版本,简化的配置文件的书写,这是 Spring 早期推荐的声明式事务管理方式,但是在 Spring 2.0 中已经不推荐了。
        5.  基于 <tx> 和 <aop> 命名空间的声明式事务管理是目前推荐的方式,其最大特点是与 Spring AOP 结合紧密,可以充分利用切点表达式的强大支持,使得管理事务更加灵活。
        6.  基于 @Transactional 的方式将声明式事务管理简化到了极致。开发人员只需在配置文件中加上一行启用相关后处理 Bean 的配置,然后在需要实施事务管理的方法或者类上使用 @Transactional 指定事务规则即可实现事务管理,而且功能也不必其他方式逊色。

Spring之事务管理的更多相关文章

  1. Spring的事务管理

    事务 事务:是逻辑上一组操作,要么全都成功,要么全都失败. 事务特性(ACID) 原子性:事务不可分割 一致性:事务执行的前后,数据完整性保持一致 隔离性:一个事务执行的时候,不应该受到其他事务的打扰 ...

  2. spring笔记--事务管理之声明式事务

    事务简介: 事务管理是企业级应用开发中必不可少的技术,主要用来确保数据的完整性和一致性, 事务:就是一系列动作,它们被当作一个独立的工作单元,这些动作要么全部完成,要么全部不起作用. Spring中使 ...

  3. Spring应用——事务管理

    事务基础:请参看:http://www.cnblogs.com/solverpeng/p/5720306.html 一.Spring 事务管理 1.前提:事务管理器 在使用 Spring 声明式事务管 ...

  4. spring+mybatis事务管理

    spring+mybatis事务管理 最近在和朋友做一个项目,考虑用springmvc+mybatis来做,之前在公司工作吧,对于数据库这块的配置也有人再弄,最近因为这个项目,我就上网学习了一些关于数 ...

  5. spring,mybatis事务管理配置与@Transactional注解使用[转]

    spring,mybatis事务管理配置与@Transactional注解使用[转] spring,mybatis事务管理配置与@Transactional注解使用 概述事务管理对于企业应用来说是至关 ...

  6. Spring高级事务管理难点剖析

    1Spring事务传播行为 所谓事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播.Spring支持7种事务传播行为 PROPAGATION_REQUIRED(加入已有事务) 如果当前没 ...

  7. CSDN上看到的一篇有关Spring JDBC事务管理的文章(内容比较全) (转)

    JDBC事务管理 Spring提供编程式的事务管理(Programmatic transaction manage- ment)与声明式的事务管理(Declarative transaction ma ...

  8. Mybatis整合Spring实现事务管理的源码分析

    一:前言 没有完整看完,但是看到了一些关键的地方,这里做个记录,过程会有点乱,以后逐渐补充最终归档为完整流程:相信看过框架源码的都知道过程中无法完全确定是怎样的流程,毕竟不可能全部都去测试一遍 ,但是 ...

  9. Hibernate与Spring的事务管理

    什么是事务 这个问题比较大,按照我的理解就是,一个事务内的n个操作,要么全部完成,一旦有一个操作有问题,那么所有的操作都全部回滚. Jdbc的事务 首先,大家已经知道了,事务说白了就是一个词----统 ...

随机推荐

  1. 【Python】 子进程创建与使用subprocess

    subprocess *****本文参考了Vamei大神的http://www.cnblogs.com/vamei/archive/2012/09/23/2698014.html 运用subproce ...

  2. Post Office

    Post Office poj-1160 题目大意:给你在数轴上的n个村庄,建立m个邮局,使得每一个村庄距离它最近的邮局的距离和最小,求距离最小和. 注释:n<=300,m<=min(n, ...

  3. ElasticSearch之 控制相关度原理讲解

    控制相关度 相关度评分背后的理论 如何计算评分的 Lucene 使用布尔模型(Boolean model) 查找匹配文档 并主要的借鉴了 词频/逆向文档频率(term frequency/invers ...

  4. .NET Core初体验 在window上构建第一个app

    ASP.NET Core 是一个跨平台,高性能的开源框架,用于构建现代化的,基于云的互联网应用程序.使用 ASP.NET Core ,您可以: 构建Web应用程序和服务,IoT应用程序和移动后端. 在 ...

  5. JavaScript(第二十四天)【事件对象】

    JavaScript事件的一个重要方面是它们拥有一些相对一致的特点,可以给你的开发提供更多的强大功能.最方便和强大的就是事件对象,他们可以帮你处理鼠标事件和键盘敲击方面的情况,此外还可以修改一般事件的 ...

  6. 20162328蔡文琛week07

    学号 2016-2017-2 <程序设计与数据结构>第X周学习总结 教材学习内容总结 多态引用在不同的时候可以指向不同类型的对象. 多态引用在运行时才将方法调用用于它的定义绑定在一起. 引 ...

  7. defaultdict使用及__missing__理解

    import collections import re WORD_RE = re.compile(r'\w+') index = collections.defaultdict(list) #用li ...

  8. maven添加oracle驱动

    由于oracle商业版权问题,maven是不可以直接下载jar包的,所以..   先将ojdbc14.jar放到用户目录,win7放到C:\Users\Administrator然后在cmd执行   ...

  9. 【审核】检查iOS项目中是否使用了IDFA

    (1)什么是IDFA 关于IDFA,在提交应用到App Store时,iTunes Connect有如下说明: 这里说到检查项目中是否包含IDFA,那如何来对iOS项目(包括第三方SDK)检查是否包含 ...

  10. 亚马逊AWS学习——VPC里面几个概念的关系

    VPC中涉及几个概念: VPC 子网 路由表 Internet网关 安全组 今天来讲讲这几个概念之间的关系. 1. VPC 说的就是VPC,当然VPC范围是最大的,VPC即virtual privat ...