您的位置:首页 > 编程语言 > Java开发

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

2016-12-31 19:55 519 查看
基于注解的声明式事务,主要使用的是@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() { ... }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐