深入解读Spring Framework事务管理(第四弹:基于@Transactional注解的声明式事务管理)

基于注解的声明式事务,主要使用的是@Transactional注解,下面我们来具体看一下。

使用@Transactional注解实现事务的例子

// 这个service我们要将他事务化
@Transactional
public class DefaultFooService implements FooService {

    Foo getFoo(String fooName);

    Foo getFoo(String fooName, String barName);

    void insertFoo(Foo foo);

    void updateFoo(Foo foo);
}

当我们在Spring IoC容器中定义上面这个POJO时,我们只需要在XML配置里添加一行就可以使这个bean的实例事务化。

<!-- from the file 'context.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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 这个service对象我们要让他支持事务 -->
    <bean id="fooService" class="x.y.service.DefaultFooService"/>

    <!-- 基于注解的事务配置 -->
    <tx:annotation-driven transaction-manager="txManager"/>
    <!-- 事务管理器(PlatformTransactionManager)仍然是需要的 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 配置数据源 -->

    <!-- 其他的bean定义 -->

</beans>

<tx:annotation-driven/>标签里的transaction-manager属性值是PlatformTransactionManager对象的bean的名字,如果不写的话默认就叫“transactionManager”。我们这个例子里没有用默认,指定的是叫“txManager”。

当使用代理时,@Transactional注解要加在public的方法上。如果给protected、private或者包访问的方法添加@Transactional注解,不会产生错误,但是事务并不会生效。如果要给非public的方法添加注解可以参考AspectJ。

尽管我们可以把@Transactional注解加在接口定义、接口中的方法定义、类定义或者类中的public方法定义的前面,不过Spring建议我们在类或者类的方法上加注解,而不要在接口上加注解。然而光有@Transactional注解还是不够让事务生效的,@Transactional注解仅仅是一个元数据,要使用这个元数据,还需要<tx:annotation-driven/>来配置bean的事务行为。
<tx:annotation-driven/>的设置

XML AttributeAnnotation AttributeDefaultDescription
transaction-managerN/AtransactionManager要使用的事务管理器的名字。只有在事务管理器的名字不是transactionManager的时候才是必须的
modemodeproxy默认值“proxy”使得注解了的bean使用Spring的AOP框架来代理。候选的“aspectj”模式使用了Spring的AspectJ transaction aspect对目标类进行编织,通过修改目标类的字节码来让任何的方法调用都能产生事务
proxy-target-classproxyTargetClassfalse只在代理模式生效。控制使用@Transactional注解的类将会创建什么类型的事务代理。如果proxy-target-class的属性值设为true,那就创建基于类的代理,如果设为false,那就会创建标准JDK的基于接口的代理。
orderorderOrdered.LOWEST_PRECEDENCE定义添加了@Transactional注解的bean上的事务通知的顺序。不指定顺序意味着有AOP底层系统决定通知的顺序

@EnableTransactionManagement和<tx:annotation-driven/>只会查找在同一个应用上下文中定义的bean的@Transactional注解。也就是说,如果在一个DispatcherServlet的WebApplicationContext中添加了注解驱动的配置,那么只会在controllers中查找@Transactional beans,而不是在services里查找。

在决定方法的事务设置时,会取最精确的配置,比如:

@Transactional(readOnly = true)
public class DefaultFooService implements FooService {

    public Foo getFoo(String fooName) {
        // do something
    }

    // 这里的事务设置更优先
    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    public void updateFoo(Foo foo) {
        // do something
    }
}

@Transactional的设置

@Transactional注解是一个用来定义一个接口、类或者方法的事务化语义的元数据。@Transactional注解的默认设置如下:
传播行为是PROPAGATION_REQUIRED
隔离级别是ISOLATION_DEFAULT
事务是可读可写的
事务超时是使用系统底层组件的默认值,不支持超时的时候就没有超时设置
任何的RuntimeException都会触发回滚,checked Exception不会。
@Transactional注解的各种属性如下:

PropertyTypeDescription
valueString指定事务管理器使用的可选限定符
propagationenum: Propagation指定传播行为
isolationenum: Isolation指定隔离级别
readOnlyboolean设置事务是可读可写还是只读
timeoutint (以秒为单位)事务超时
rollbackForClass对象数组,必须是继承自Throwable的指定会触发回滚的异常类的数组
rollbackForClassName类名的数组,类必须是继承自Throwable的指定会触发回滚的异常类名的数组
noRollbackForClass对象数组,必须是继承自Throwable的指定不会触发回滚的异常类的数组
noRollbackForClassName类名的数组,类必须是继承自Throwable的指定不会触发回滚的异常类名的数组

@Transactional使用多个事务管理器

一般来讲我们只需要使用一个事务管理器,不过也存在需要多个的情况。@Transactional的value属性可以指定要使用的不同的PlatformTransactionManager。这可以是bean的名称或者事务管理器bean的修饰值。比如下面的代码:

public class TransactionalService {

    @Transactional("order")
    public void setSomething(String name) { ... }

    @Transactional("account")
    public void doSomething() { ... }
}

可以和下面的事务管理器的bean绑定:

<tx:annotation-driven/>

<bean id="transactionManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    ...
    <qualifier value="order"/>
</bean>

<bean id="transactionManager2" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    ...
    <qualifier value="account"/>
</bean>

这样,TransactionalService中的两个方法将会分别运行在独立的事务管理器中,通过”order”和”account”的修饰符区分。<tx:annotation-driven/>的默认目标bean名称transactionManager会在指定的修饰符没有找到时使用。

自定义快捷注解

先自定义快捷注解,例如:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional("order")
public @interface OrderTx {
}

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Transactional("account")
public @interface AccountTx {
}

然后我们就能这么用:

public class TransactionalService {

    @OrderTx
    public void setSomething(String name) { ... }

    @AccountTx
    public void doSomething() { ... }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值