本文仅基于3.0+版本作为测试)
假定spring<wbr>容器中定义了两个事务管理器:<span style="word-wrap:normal; word-break:normal; color:rgb(255,0,0)">transactionManagerX</span>,<span style="word-wrap:normal; word-break:normal; color:rgb(0,0,255)">transactionManagerY</span>,分管两个数据源datasourceX和datasourceY.</wbr>
<tx:annotation-driven<wbr>transaction-manager="transactionManagerX"<wbr>/></wbr></wbr>
<tx:annotation-driven<wbr>transaction-manager="transactionManagerY"<wbr>/></wbr></wbr>
(spring容器中的定义顺序如上)
有如下应用代码:
public<wbr>interface<wbr>TestEntityService<wbr>{</wbr></wbr></wbr>
public<wbr>void<wbr>methodX();</wbr></wbr>
public<wbr>void<wbr>methodY();</wbr></wbr>
}
<wbr></wbr>
接口实现类1
public<wbr>class<wbr><span style="word-wrap:normal; word-break:normal; color:rgb(255,0,0)">TestEntityServiceImpl</span><wbr>implements<wbr>TestEntityService<wbr>{</wbr></wbr></wbr></wbr></wbr>
@Resource
private<wbr>TestEntityDao<wbr>testEntityDao;//实际操作的是<span style="word-wrap:normal; word-break:normal; color:rgb(255,0,0)">datasourceX</span>.</wbr></wbr>
@Transactional
public<wbr>void<wbr>methodX()<wbr>{</wbr></wbr></wbr>
testEntityDao.xxx();
testEntityDao.zzz();
}
public<wbr>void<wbr>methodY()<wbr>{</wbr></wbr></wbr>
}
}
<wbr></wbr>
接口实现类2
public<wbr>class<wbr><span style="word-wrap:normal; word-break:normal; color:rgb(0,0,255)">AnotherTestEntityService<wbr>Impl</wbr></span><wbr>implements<wbr>TestEntityService<wbr>{</wbr></wbr></wbr></wbr></wbr>
@Resource
private<wbr>TestEntityDao<wbr>anOtherTestEntityDao;//实际操作的是<span style="word-wrap:normal; word-break:normal; color:rgb(0,0,255)">datasourceY</span>.</wbr></wbr>
@Transactional
public<wbr>void<wbr>methodX()<wbr>{</wbr></wbr></wbr>
testEntityDao.mmm();
testEntityDao.nnn();
}
public<wbr>void<wbr>methodY()<wbr>{</wbr></wbr></wbr>
}
}
假设方法methodX需要事务控制的,通常我们是直接在方法上添加@Transactional标注,
但是好像spring3.0(具体版本没弄清)之前的Transactional标注不支持区分使用哪个事务管理器。3.0之后的版本Transactional增加了个string类型的value属性来特殊指定加以区分。
例如@Transactional("aaaaa"),即显示的要求spring用id="aaaaa"的事务管理器来管理事务。该属性亦可省略(省略的话用容器中缺省的transactionManager)
对于该属性的用法做了如下测试来
methodX()事务生效测试结果 |
@Transactional
("transactionManagerX")
<wbr></wbr>
|
@Transactional
("transactionManagerY")
<wbr></wbr>
|
@Transactional
("transactionManagerZ")
<wbr>transactionManagerZ为未定义过的</wbr>
|
@Transactional<wbr><wbr></wbr></wbr> |
TestEntityServiceImpl(实际使用datasourceX) | Y | N | Y | Y |
AnotherTestEntityService<wbr>Impl<wbr>(实际使用datasourceY)</wbr></wbr> | N | Y | N | N |
如果调换两个事务管理器在容器中的定义顺序,如
<tx:annotation-driven<wbr>transaction-manager="transactionManagerY"<wbr>/></wbr></wbr>
<tx:annotation-driven<wbr>transaction-manager="transactionManagerX"<wbr>/></wbr></wbr>
得到的结果
methodX()事务生效测试结果 |
@Transactional
("transactionManagerX")
<wbr></wbr>
|
@Transactional
("transactionManagerY")
<wbr></wbr>
|
@Transactional
("transactionManagerZ")
<wbr>transactionManagerZ为未定义过的</wbr>
|
@Transactional<wbr><wbr></wbr></wbr> |
TestEntityServiceImpl(实际使用datasourceX) | Y | N | N | N |
AnotherTestEntityService<wbr>Impl<wbr>(实际使用datasourceY)</wbr></wbr> | N | Y | Y | Y |
分析结果(其实源码就可以反应出):容器指定一个默认的事务管理器
<wbr></wbr>
1.当在@Transactional("xxx")中正确指定了需要使用的事务管理器时,事务控制正常。
2.如果@Transactional指定了未定义过的事务管理器,spring以缺省默认的事务管理器来处理。(如果程序正好使用的是缺省事务管理器同一个数据源,事务控制将生效)。
3.如果@Transactional不指定事务管理器,使用缺省。
4.如果@Transactional指定了不匹配的事务管理器(实际用到的数据源和指定的事务管理器控制的数据源不一致),事务控制将失效.
注:spring容器缺省事务管理器:以加载顺序,首先加载的作为缺省。例如
如果
<tx:annotation-driven<wbr>transaction-manager="transactionManagerX"<wbr>/></wbr></wbr>
<tx:annotation-driven<wbr>transaction-manager="transactionManagerY"<wbr>/></wbr></wbr>
定义在同一个文件中,则第一个transactionManagerX作为缺省。
定义在不同文件,则按文件的加载顺序,首先加载的作为缺省。
建议:实际代码中需要用到@Transactional时,即使默认只有一个transactionManager,@Transactional也将其标明。以提高新增数据源后代码可读性,另外防止定义多个数据源后,以前缺省的不被spring默认为缺省了(比如哪天上线新定义了一个数据源,刚好新定义的transactionManager被先加载了,那就悲剧了。)
<wbr></wbr>
<wbr></wbr>
二.bean的配置使用
容器中加了<tx:annotation-driven<wbr>>(需要增加一些xsd)之后,需要事务控制的的service,不需要再具体的bean上做其他的配置,例如用代理包装。直接配置即可</wbr>
<bean<wbr>id="testEntityService"<wbr>class="com.xxx.impl.TestEntityServiceImpl"/></wbr></wbr>
spring将由JdkDynamicAopProxy 生成代理过的类提供使用。
这种用法的效果和下面配置使用效果一样。都是由JdkDynamicAopProxy 生成代理对象提供使用。
我觉得区别是下面的方法在事务控制的代码可读性上不好,因为哪个方法需要事务控制和控制粒度都在配置文件中,和代码分开了。
<bean<wbr>id="testEntityService3"<wbr>class="org.springframework.transaction.interceptor.TransactionProxyFactoryB<wbr>ean"></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><property<wbr>name="transactionManager"<wbr>ref="transactionManagerX"<wbr>/></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><property<wbr>name="target"></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><bean<wbr>class="com.xxxx.impl.TestEntityServiceImpl"<wbr>/></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr></property></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><property<wbr>name="proxyInterfaces"<wbr>value="com.xxxx.TestEntityService"/></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><property<wbr>name="transactionAttributes"></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><props></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><prop<wbr>key="*">PROPAGATION_REQUIRED</prop></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr></props></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
<wbr><wbr><wbr><wbr><wbr></property></wbr></wbr></wbr></wbr></wbr>
</bean>
<wbr></wbr>
方法的可见度和<wbr>@Transactional</wbr>
@Transactional<wbr>注解应该只被应用到<wbr>public<wbr>可见度的方法上。<wbr>如果你在<wbr>protected、private<wbr>或者<wbr>package-visible<wbr>的方法上使用<wbr>@Transactional<wbr>注解,它也不会报错,<wbr>但是这个被注解的方法将不会展示已配置的事务设置。</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
@Transactional<wbr>注解可以被应用于接口定义和接口方法、类定义和类的<wbr>public<wbr>方法上。然而,请注意仅仅<wbr>@Transactional<wbr>注解的出现不足于开启事务行为,它仅仅<wbr>是一种元数据,能够被可以识别<wbr>@Transactional<wbr>注解和上述的配置适当的具有事务行为的beans所使用。上面的例子中,其实正是<wbr><tx:annotation-driven/>元素的出现<wbr>开启<wbr>了事务行为。</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
Spring团队的建议是你在具体的类(或类的方法)上使用<wbr>@Transactional<wbr>注解,而不要使用在类所要实现的任何接口上。你当然可以在接口上使用<wbr>@Transactional<wbr>注解,但是这将只能当你设置了基于接口的代理时它才生效。因为注解是<wbr>不能继承<wbr>的。</wbr></wbr></wbr></wbr></wbr></wbr>
<wbr></wbr>
实际开发中,多半喜欢将持久化操作的代码集中抽出为另一个方法(因为不想事务被无关的业务代码托的持续太长),然后在抽取出来的方法上加上@Transactional,这样的结果是被抽离出的代码即使加了事务标记,也根本起不到事务控制的效果(不管是private和public)。
例如:
public<wbr>class<wbr>TestEntityServiceImpl<wbr>implements<wbr>TestEntityService<wbr>{</wbr></wbr></wbr></wbr></wbr>
@Resource
private<wbr>TestEntityDao<wbr>testEntityDao;//实际操作的是datasourceX.</wbr></wbr>
@Transactional
public<wbr>void<wbr>methodX()<wbr>{</wbr></wbr></wbr>
testEntityDao.xxx();
testEntityDao.zzz();
}
public<wbr>void<wbr>methodY()<wbr>{</wbr></wbr></wbr>
methodX()<wbr></wbr>
}
}
如果执行TestEntityService.methodY();事务是不生效的。只有TestEntityService.methodY();才生效。
从spring实现这些的原理(动态代理和aop)上来看,只拦截外部调用,方法的内部调用通常是不被aop支持的。
从网上扒到一篇文章,可以解决这个问题。
相关推荐
Spring 的 Annotation-Driven 配置事务管理器详解(多数据源配置) Spring 框架提供了强大的事务管理机制,通过使用 Annotation-Driven 配置,可以方便地管理事务。在多数据源配置中,spring 的 Annotation-Driven...
- Annotation-driven配置:在Spring应用上下文中启用注解驱动的事务管理。 理解并熟练运用Spring声明式事务管理,可以有效提高应用程序的事务处理能力,同时降低事务管理的复杂性。通过合理的配置,可以确保数据的...
2. **基于XML的AOP事务切面**:使用`<tx:annotation-driven>`标签,可以自动为标记了@Transactional注解的方法添加事务管理。这种方式更简洁,不需要显式创建事务代理。 3. **基于Java的@Configuration注解**:通过...
然后,通过`<tx:annotation-driven>`启用基于注解的事务管理,这使得Spring能够扫描并处理带有`@Transactional`注解的方法。 总之,Spring的事务管理提供了一种强大且灵活的方式来管理企业级应用中的事务,确保数据...
<tx:annotation-driven transaction-manager="transactionManager" /> ``` ### 4. **Programmatic Transaction Management(编程式事务管理)** 编程式事务管理允许开发者手动控制事务的开始、提交、回滚。虽然...
XML配置中,<tx:annotation-driven/>元素用于启用声明式事务管理,而则定义了事务管理器。Java配置中,我们可以使用@Configuration和@EnableTransactionManagement注解来开启事务管理,并通过@Bean方法创建事务管理...
最后,通过`<tx:annotation-driven>`启用基于注解的事务管理,指定事务管理器为之前配置的`transactionManager`。这样,我们就可以在Service层的方法上添加`@Transactional`注解来开启事务。 例如,一个简单的...
<tx:annotation-driven transaction-manager="transactionManager" /> ``` 然后在业务或DAO类中使用`@Transactional`注解来标记需要进行事务管理的方法。 3. **基于XML的声明式事务** 在XML配置文件中直接定义...
### Spring的Annotation方式详解 #### 引言 随着Spring框架的发展,其依赖注入(DI)机制也经历了从XML配置向注解驱动的重大转变。自Spring 3.0版本起,框架引入了一系列注解来简化依赖配置,使得开发人员能够在不...
在使用Spring的事务管理时,需要指定事务管理器,例如:<tx:annotation-driven transaction-manager="txManager" />,这里的txManager就是指定的事务管理器。 Spring的事务管理是通过AOP来实现的,使用ASM来操作...
### Spring框架中的Annotation注解详解 #### 一、Spring与Annotation的基本概念 Spring框架通过引入Annotation,极大地简化了Java开发中的依赖注入(Dependency Injection, DI)和面向切面编程(AOP)的过程。...
然后,我们需要开启基于注解的事务管理,这可以通过`<tx:annotation-driven>`标签完成。 ```xml <tx:annotation-driven transaction-manager="transactionManager" /> ``` 3. 注解驱动事务 接下来,我们可以在服务...
- 非注解方式通常涉及XML配置,需要在`<tx:annotation-driven>`或`<aop:config>`标签中进行配置。 - **事务管理器配置**:首先需要定义一个事务管理器,如`PlatformTransactionManager`接口的实现类,常见的有`...
### Spring事务配置详解 #### 一、Spring事务配置概述 Spring框架提供了强大的事务管理功能,支持编程式事务管理和声明式事务管理。其中声明式事务管理是通过AOP(面向切面编程)技术来实现的,它能让我们在不修改...
通过`<jdbc:initialize-database>`、`<tx:annotation-driven>`等特定的标签,可以方便地配置数据源、事务管理等。 八、Profile配置 Spring支持基于环境的配置,通过`profile`属性,我们可以定义在特定环境下生效的...
1. **@Component** - 这是Spring的基类注解,用于标记一个Java类为Spring管理的Bean。例如,`@Component`可以放在`Office`、`Car`和`Boss`类上,声明它们为Spring容器中的Bean。Spring会通过扫描包路径自动发现这些...
为了使上述注解生效,需要在Spring的配置文件中启用自动扫描功能。这可以通过`<context:component-scan/>`元素来实现,例如: ```xml <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi=...