学科分类
目录
SSM框架

基于Annotation方式的声明式事务

Spring的声明式事务管理还可以通过Annotation(注解)的方式来实现。这种方式的使用非常简单,开发者只需做两件事情:

① 在Spring容器中注册事务注解驱动,其代码如下:

<tx:annotation-driven transaction-manager="transactionManager"/>

② 在需要使用事务的Spring Bean类或者Bean类的方法上添加注解@Transactional。如果将注解添加在Bean类上,则表示事务的设置对整个Bean类的所有方法都起作用;如果将注解添加在Bean类中的某个方法上,则表示事务的设置只对该方法有效。

使用@Transactional注解时,可以通过其参数配置事务详情。@Transactional注解可配置的参数信息如表1所示。

表1 @Transactional注解的参数及其描述

参数名称 描述
value 用于指定需要使用的事务管理器,默认为"",其别名为transactionManager。
transactionManager 指定事务的限定符值,可用于确定目标事务管理器,匹配特定的限定值(或者Bean的name值),默认为"",其别名为value。
isolation 用于指定事务的隔离级别,默认为Isolation.DEFAULT(即底层事务的隔离级别)。
noRollbackFor 用于指定遇到特定异常时强制不回滚事务。
noRollbackForClassName 用于指定遇到特定的多个异常时强制不回滚事务。其属性值可以指定多个异常类名。
propagation 用于指定事务的传播行为,默认为Propagation.REQUIRED。
read-only 用于指定事务是否只读,默认为false。
rollbackFor 用于指定遇到特定异常时强制回滚事务。
rollbackForClassName 用于指定遇到特定的多个异常时强制回滚事务。其属性值可以指定多个异常类名。
timeout 用于指定事务的超时时长,默认为TransactionDefinition.TIMEOUT_DEFAULT(即底层事务系统的默认时间)。

从表1可以看出,@Transactional注解与<tx:method>元素中的事务属性基本是对应的,并且其含义也基本相似。

为了让读者更加清楚的掌握@Transactional注解的使用,接下来对上一小节的案例进行修改,以Annotation方式来实现项目中的事务管理,具体实现步骤如下。

(1)在src目录下,创建一个Spring配置文件applicationContext-annotation.xml,在该文件中声明事务管理器等配置信息,如文件1所示。

文件1 applicationContext-annotation.xml

 1    <?xml version="1.0" encoding="UTF-8"?>
 2    <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 4        xmlns:aop="http://www.springframework.org/schema/aop"
 5        xmlns:tx="http://www.springframework.org/schema/tx" 
 6        xmlns:context="http://www.springframework.org/schema/context"
 7        xsi:schemaLocation="http://www.springframework.org/schema/beans 
 8        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
 9        http://www.springframework.org/schema/tx 
 10        http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
 11        http://www.springframework.org/schema/context 
 12        http://www.springframework.org/schema/context/spring-context-4.3.xsd
 13        http://www.springframework.org/schema/aop 
 14        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
 15        <!-- 1.配置数据源 -->
 16        <bean id="dataSource" 
 17        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
 18            <!--数据库驱动 -->
 19            <property name="driverClassName" value="com.mysql.jdbc.Driver" />
 20            <!--连接数据库的url -->
 21            <property name="url" value="jdbc:mysql://localhost/spring" />
 22            <!--连接数据库的用户名 -->
 23            <property name="username" value="root" />
 24            <!--连接数据库的密码 -->
 25            <property name="password" value="root" />
 26        </bean>
 27        <!-- 2.配置JDBC模板 -->
 28        <bean id="jdbcTemplate" 
 29                class="org.springframework.jdbc.core.JdbcTemplate">
 30            <!-- 默认必须使用数据源 -->
 31            <property name="dataSource" ref="dataSource" />
 32        </bean>
 33        <!--3.定义id为accountDao的Bean -->
 34        <bean id="accountDao" class="com.itheima.jdbc.AccountDaoImpl">
 35            <!-- 将jdbcTemplate注入到AccountDao实例中 -->
 36            <property name="jdbcTemplate" ref="jdbcTemplate" />
 37        </bean>
 38        <!-- 4.事务管理器,依赖于数据源 -->
 39        <bean id="transactionManager" class=
 40         "org.springframework.jdbc.datasource.DataSourceTransactionManager">
 41            <property name="dataSource" ref="dataSource" />
 42        </bean>    
 43        <!-- 5.注册事务管理器驱动 -->
 44        <tx:annotation-driven transaction-manager="transactionManager"/>
 45    </beans>

与基于XML方式的配置文件相比,文件5-3通过注册事务管理器驱动,替换了文件1中的第5步编写通知和第6步编写aop,这样大大减少了配置文件中的代码量。

需要注意的是,如果案例中使用了注解式开发,则需要在配置文件中开启注解处理器,指定扫描哪些包下的注解。这里没有开启注解处理器是因为在配置文件中已经配置了AccountDaoImpl类的Bean,而@Transactional注解就配置在该Bean类中,所以可以直接生效。

(2)在AccountDaoImpl类的transfer()方法上添加事务注解,添加后的代码如下所示。

@Transactional(propagation = Propagation.REQUIRED, 
            isolation = Isolation.DEFAULT, readOnly = false)
public void transfer(String outUser, String inUser, Double money) {
    // 收款时,收款用户的余额=现有余额+所汇金额
    this.jdbcTemplate.update("update account set balance = balance +? "
            + "where username = ?",money, inUser);
    // 模拟系统运行时的突发性问题
    int i = 1/0;
    // 汇款时,汇款用户的余额=现有余额-所汇金额
    this.jdbcTemplate.update("update account set balance = balance-? "
            + "where username = ?",money, outUser);
}

上述方法已经添加了@Transactional注解,并且使用注解的参数配置了事务详情,各个参数之间要用英文逗号“,”进行分隔。

小提示:

在实际开发中,事务的配置信息通常是在Spring的配置文件中完成的,而在业务层类上只需使用@Transactional注解即可,不需要配置@Transactional注解的属性。

(3)在TransactionTest类中,创建测试方法annotationTest(),编辑后的代码如下所示。

@Test
public void annotationTest(){
    ApplicationContext applicationContext = 
new ClassPathXmlApplicationContext("applicationContext-annotation.xml");
    // 获取AccountDao实例
    AccountDao accountDao = 
(AccountDao)applicationContext.getBean("accountDao");
    // 调用实例中的转账方法
    accountDao.transfer("Jack", "Rose", 100.0);
    // 输出提示信息
    System.out.println("转账成功!");
}

从上述代码可以看出,与XML方式的测试方法相比,该方法只是对配置文件的名称进行了修改。程序执行后,会出现与XML方式同样的执行结果,这里就不再做重复演示,读者可自行测试。

点击此处
隐藏目录