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

使用spring事务管理的几个注意事项

2017-05-15 00:00 316 查看
#正确的配置方案
基本上涉及到spring事务管理的文章都会交待通过“配置+注解”的方式实现目标。首先在xml配置文件中添加以下配置:

<!-- 定义事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="adminDataSource" />
</bean>
<!-- 使用annotation注解方式配置事务 -->
<tx:annotation-driven transaction-manager="transactionManager"  />

然后在需要启动事务管理的方法处添加
@Transactional
注解:

/*这里我是在service中直接调用jdbc操作的,所以把service中的方法加上@Transactional注解*/
@Transactional
public void invoke() {
OaTag tag = new OaTag();
oaTagMapper.insert(tag);
throw new RuntimeException();
}

例如上例的代码就会因为异常回滚,保持方法的原子性操作。

但是,会有以下几个情况,可能会导致事务不起作用。
#问题排查
实际上spring提供的对数据库操作的事物管理特性是基于jdbc的,而jdbc事务的使用方法为:

获取连接 Connection con = DriverManager.getConnection()

开启事务con.setAutoCommit(true/false);

执行CRUD

提交事务/回滚事务 con.commit() / con.rollback();

关闭连接 conn.close();
可如果我们使用spring的事务管理功能,就可以通过简单的一个
@Transactional
注解实现对整个方法的事务控制。

spring的事务管理功能是通过创建aop代理来实现的,所以最直接查找问题的方法就是看你调用的对象有没有被封装成aop代理。

/*在controller中判断调用的service对象实例是否为aop代理*/
@RequestMapping("invoke")
public void invoke(){
LOG.info("isAopProxy:{}", AopUtils.isAopProxy(platService)); #判断是否为面向切面代理,一般理解为aop即CGLIB代理的特性
LOG.info("isCglibProxy:{}", AopUtils.isCglibProxy(platService)); #直接判断是否为CGLIB代理
LOG.info("isJDKDynamicProxy:{}", AopUtils.isJdkDynamicProxy(platService)); #判断是否为JDK动态代理,我们不希望它是这种代理
platService.invoke();
}

如果你发现你所使用的对象不是aop对象,那么就要挨个排查具体原因了。

#问题原因&解决方案
##多个配置文件重复扫描
最常见的spring-mvc项目一般会包含两个配置文件:
application-context.xml
spring-mvc.xml
可能在你的项目中他们有不一样的名字,但是实际上我们通过两个文件所实现的目标是一样的。通过前者来配置
context
,是整个项目的大环境配置文件;后者用来配置
spring-mvc DispatcherServlet
,它负责的是对servlet的定义。有的时候我们会混淆两者的作用,比如当你把
<context:component-scan>
标签放在两个文件,就有可能让后调用
spring-mvc.xml
的servlet创建的service-bean,覆盖
application-context.xml
中定义的bean。所以我们需要通过在
spring-mvc.xml
中 添加:

<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>

让带了
@Service
标签的bean不会被
spring-mvc.xml
覆盖。
##public方法
我们为之添加
@Transactional
注解的方法必须是被controller直接调用的public方法。比如下面这样的调用是不可用的:

/*service*/
public void invoke() {
i();
}

@Transactional
private void i(){ #pri
OaTag tag = new OaTag();
tag.setPlatId(12);
tag.setTag("测试tag");
oaTagMapper.insert(tag);
throw new RuntimeException();
}

##数据库引擎
必须使用
InnoDB
这样的事务型数据库引擎,比如
MyISAM
是不行的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Spring