求帮忙看下springmvc框架中注解事务失效问题

蓝川逸风 发布于 2015/10/30 09:22
阅读 3K+
收藏 0

web.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 
	xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
	
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath*:config/applicationContext*.xml</param-value>
	</context-param>
	
    <filter>
		<filter-name>encodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>encodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	
	<servlet>
		<servlet-name>zhihuiyi</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:config/drf-servlet.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
    <servlet>
        <servlet-name>InitServlet</servlet-name>
        <servlet-class>com.developerForDrf.frame.init.InitServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
   <servlet>
		<servlet-name>WeixinServlet</servlet-name>
		<servlet-class>com.developerForDrf.wechat.servlet.WeixinServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet> 
	
	
	<servlet-mapping>
		<servlet-name>zhihuiyi</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
    <servlet-mapping>
       <servlet-name>InitServlet</servlet-name>
       <url-pattern>/servlet/InitServlet.do</url-pattern>
    </servlet-mapping>
     <servlet-mapping>
       <servlet-name>WeixinServlet</servlet-name>
       <url-pattern>/WeixinServlet.do</url-pattern>
    </servlet-mapping>
   
</web-app>



applicationContext.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:p="http://www.springframework.org/schema/p"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="
	http://www.springframework.org/schema/beans 
	http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	http://www.springframework.org/schema/tx
	http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    http://www.springframework.org/schema/task   
    http://www.springframework.org/schema/task/spring-task-3.0.xsd 	
	http://www.springframework.org/schema/context 
	http://www.springframework.org/schema/context/spring-context-3.0.xsd
	http://www.springframework.org/schema/aop
	http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
	"> 
	<context:component-scan base-package="com.developerForDrf,com.developerForDrf.frame,com.developerForDrf.wechat,com.developerForDrf.business" >
    	<!-- <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> -->
    </context:component-scan>   
    <context:property-placeholder location="classpath:config/db.properties" />
	<bean name="dataSource"
		class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
		destroy-method="close">
		 <property name="driverClassName" value="${driverClassName}" /> 
		<property name="url" value="${jdbc_url}" />
		<property name="username" value="${jdbc_username}" />
		<property name="password" value="${jdbc_password}" />
		<!-- 初始化连接大小 -->
		<property name="initialSize" value="1" />
		<!-- 连接池最大使用连接数量 -->
		<property name="maxActive" value="5" />
		<!-- 连接池最大空闲 
		<property name="maxIdle" value="10" />-->
		<!-- 连接池最小空闲 -->
		<property name="minIdle" value="1" />
		<!-- 获取连接最大等待时间 -->
		<property name="maxWait" value="60000" />
		<property name="validationQuery" value="SELECT 1 FROM DUAL" />
		<property name="testOnBorrow" value="false" />
		<property name="testOnReturn" value="false" />
		<property name="testWhileIdle" value="true" />

		<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
		<property name="timeBetweenEvictionRunsMillis" value="60000" />
		<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
		<property name="minEvictableIdleTimeMillis" value="25200000" />

		<!-- 打开removeAbandoned功能 -->
		<property name="removeAbandoned" value="true" />
		<!-- 1800秒,也就是30分钟 -->
		<property name="removeAbandonedTimeout" value="1800" />
		<!-- 关闭abanded连接时输出错误日志 -->
		<property name="logAbandoned" value="true" />
		<!-- 开启Druid的监控统计功能 
		<property name="filters" value="stat" />-->
	</bean>
    <!-- 国际化的消息资源文件 -->
    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basenames">
            <list>
                <value>classpath:config/validator</value>
            </list>
        </property>
        <property name="defaultEncoding" value="UTF-8"/>
        <property name="cacheSeconds" value="60"/>
    </bean>	
  
  	<!-- 处理事务 -->
	<!-- 生成一个事务管理对象 -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property> 
	</bean> 
	
	<!-- 生成默认事务定义对象 -->
	<bean id="def" class="org.springframework.transaction.support.DefaultTransactionDefinition"></bean>
	
	<!-- 声明使用注解式事务  
	<tx:annotation-driven transaction-manager="transactionManager"/> -->  
	
	<bean id= "namedParameterJdbcDaoSupport" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcDaoSupport">
		<property name="dataSource" ref="dataSource"></property>
	</bean>	
	
</beans>



对应的servlet的配置文件

<?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:p="http://www.springframework.org/schema/p"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc 
		http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
		http://www.springframework.org/schema/tx
		http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context-4.0.xsd">
		
	<!-- 自动扫描controller包下的所有类,使其认为spring mvc的控制器 ,多个可以用逗号隔开-->
	<context:component-scan base-package="com.developerForDrf,com.developerForDrf.frame,com.developerForDrf.wechat,com.developerForDrf.business" >
		<!--<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>	
		<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />  -->  	
	</context:component-scan>
	<mvc:annotation-driven />
	
	<!-- 对模型视图名称的解析,即在模型视图名称添加前后缀 -->
	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver"
		p:order="100"
		p:viewClass="org.springframework.web.servlet.view.JstlView"
		p:prefix="/" p:suffix=".jsp" />
		
	
	<!-- 处理Mutipart文件上传的bean -->
	<bean id="multipartResolver"
		class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<property name="defaultEncoding">
			<value>UTF-8</value>
		</property>
		<property name="maxUploadSize">
			<value>32505856</value><!-- 上传文件大小限制为31M,31*1024*1024 -->
		</property>
		<property name="maxInMemorySize">
			<value>4096</value>
		</property>
	</bean>
		
	<!-- 基于注释的事务,当注释中发现@Transactional时,使用id为“transactionManager”的事务管理器  -->
    <!-- 如果没有设置transaction-manager的值,则spring以缺省默认的事务管理器来处理事务,默认事务管理器为第一个加载的事务管理器 -->
    <tx:annotation-driven transaction-manager="transactionManager" />
    
	<!-- 拦截器 -->
	<mvc:interceptors>
		<mvc:interceptor>
			<mvc:mapping path="/**" />
			<bean class="com.developerForDrf.frame.interceptors.AuthInterceptor" />
		</mvc:interceptor>
	</mvc:interceptors>	
	
	<mvc:resources location="/resources/" mapping="resources/**" />
	
</beans>



事务是在service层中做的,代码段:

@Transactional(readOnly=false,propagation=Propagation.REQUIRED,rollbackFor=Exception.class)
	public String test(String openid,int account)throws Exception{
		String flag = "0";
		int f = 0;
		f = memberDao.updateUserAccount(openid, account);
		memberDao.updateSubscribe(openid, 1);
		//抛异常
		if(f==0){
			throw new Exception("测试异常");	
		}
		return flag;
	}



test()方法中的两个调用dao层的动作,第一个是正常的,第二个是有意弄错的,但是执行的时候并没有回滚。

请各位路过的大神帮忙卡看!!!


加载中
0
_Mr_Right_
_Mr_Right_

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


放上面那个文件

检查下 你的表引擎是否支持事务

ps:你的配置文件 有点乱

蓝川逸风
蓝川逸风
我去掉这个注释还是一样的,之前有测试过了。 ps:为什么说这个文件有点乱啊,给点建议
0
一只小桃子
一只小桃子
<!-- 声明使用注解式事务 
    <tx:annotation-driven transaction-manager="transactionManager"/> -->


你都把这行注释了 当然没效果了

蓝川逸风
蓝川逸风
我之前有测试过applicationContext.xml文件和servlet.xml文件都加上这句,但是事务还是无效的
0
求是科技
求是科技
目前也遇到了同样的问题,我们的配置几乎是一样的,同样事务没有起效果
求是科技
求是科技
哥们,你解决了没??
蓝川逸风
蓝川逸风
应该是某些细节我们没有注意到
0
holo
holo

1.首先你要开启这个配置。

    <!-- 声明使用注解式事务 

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

2.你的测试代码写的有问题。

   throw new RuntimeException();

   就应该可以了。参考spring的文档,不是所有异常都支持事物回滚,具体哪些支持请把文档看一下。



    

蓝川逸风
蓝川逸风
第一个建议已经把注释给去掉了。 第二个建议我代码里加了RuntimeException还是没有解决。 我把配置文件发出来想大家看看是不是有什么其他的细节我没注意到的。谢谢
0
CoderLeon
CoderLeon

我试了下没问题啊,直接throw会回滚。先update,再insert,然后thorw异常。更新和插入都没有生效到表里。

还有一种是catch住异常,不直接抛,在catch地方手动rollback。

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

0
蓝川逸风
蓝川逸风

问题补充:

sql执行的操作是这样的

/**
	 * 执行sql语句
	 * 
	 * @param sql
	 * @param args
	 * @return 成功条数
	 */

	public int executeSQL(String sql, Object...args) throws DataAccessException{
		return namedParameterJdbcDaoSupport.getJdbcTemplate().update(sql, args);
	}



0
蓝川逸风
蓝川逸风

引用来自“CoderLeon”的评论

我试了下没问题啊,直接throw会回滚。先update,再insert,然后thorw异常。更新和插入都没有生效到表里。

还有一种是catch住异常,不直接抛,在catch地方手动rollback。

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

public int updateUserAccount(String openid,int account)throws RuntimeException {
		int flag = 0;
		String sql = "update TB_MEMBER set ACCOUNT=ACCOUNT+? where OPENID=?";
		String sql2 = "update TB_MEMBER set ACCOUNTA=ACCOUNT+? where OPENID=?";
		List params = new ArrayList();
		params.add(account);
		params.add(openid);
		try {
			flag = this.baseDao.executeSQL(sql, params.toArray());
			flag = this.baseDao.executeSQL(sql2, params.toArray());
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("求回滚啊");
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
		}
		return flag;
	}


用这种手动回滚的办法也不行。



0
蓝川逸风
蓝川逸风

引用来自“CoderLeon”的评论

我试了下没问题啊,直接throw会回滚。先update,再insert,然后thorw异常。更新和插入都没有生效到表里。

还有一种是catch住异常,不直接抛,在catch地方手动rollback。

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

引用来自“蓝川逸风”的评论

public int updateUserAccount(String openid,int account)throws RuntimeException {
		int flag = 0;
		String sql = "update TB_MEMBER set ACCOUNT=ACCOUNT+? where OPENID=?";
		String sql2 = "update TB_MEMBER set ACCOUNTA=ACCOUNT+? where OPENID=?";
		List params = new ArrayList();
		params.add(account);
		params.add(openid);
		try {
			flag = this.baseDao.executeSQL(sql, params.toArray());
			flag = this.baseDao.executeSQL(sql2, params.toArray());
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("求回滚啊");
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
		}
		return flag;
	}


用这种手动回滚的办法也不行。



这是执行数据库语句的代码:

/**
	 * 执行sql语句
	 * 
	 * @param sql
	 * @param args
	 * @return 成功条数
	 */

	public int executeSQL(String sql, Object...args) throws DataAccessException{
		return namedParameterJdbcDaoSupport.getJdbcTemplate().update(sql, args);
	}

会不会是JdbcTemplate 的问题?

JdbcTemplate 与事务管理(http://blog.csdn.net/sprita1/article/details/8084909)

JdbcTemplate操作采用的是JDBC默认的AutoCommit模式,也就是说我们还无法保证数据操作的原子性(要么全部生效,要么全部无效),如:

JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

jdbcTemplate.update("UPDATE user SET age = 10 WHERE id = 'erica'");

jdbcTemplate.update("UPDATE user SET age = age+1 WHERE id = 'erica'");

由于采用了AutoCommit模式,第一个update操作完成之后被自动提交,数据库中”erica”对应的记录已经被更新,如果第二个操作失败,我们无法使得整个事务回滚到最初状态。对于这个例子也许无关紧要,但是对于一个金融帐务系统而言,这样的问题将导致致命错误。

0
holo
holo

引用来自“ervern”的评论

1.首先你要开启这个配置。

    <!-- 声明使用注解式事务 

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

2.你的测试代码写的有问题。

   throw new RuntimeException();

   就应该可以了。参考spring的文档,不是所有异常都支持事物回滚,具体哪些支持请把文档看一下。



    

http://git.oschina.net/esuper/spring-mvc-sample-jdbctemplate/tree/master
最近很忙,我自己弄了一个web mvc的功能,来测试你说的jdbcTemplate的事物回滚功能。至于你引用的那篇博客,说的是spring控制事物的几种实现方式,具体你的配置代码哪里有问题,没看到代码偶也不清楚。最好是你开启spring的日志,还有就是跟进代码debug看。
0
蓝川逸风
蓝川逸风

引用来自“ervern”的评论

1.首先你要开启这个配置。

    <!-- 声明使用注解式事务 

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

2.你的测试代码写的有问题。

   throw new RuntimeException();

   就应该可以了。参考spring的文档,不是所有异常都支持事物回滚,具体哪些支持请把文档看一下。



    

引用来自“ervern”的评论

http://git.oschina.net/esuper/spring-mvc-sample-jdbctemplate/tree/master
最近很忙,我自己弄了一个web mvc的功能,来测试你说的jdbcTemplate的事物回滚功能。至于你引用的那篇博客,说的是spring控制事物的几种实现方式,具体你的配置代码哪里有问题,没看到代码偶也不清楚。最好是你开启spring的日志,还有就是跟进代码debug看。
DEBUG 15-11-04 12:39:24 org.springframework.beans.factory.support.DefaultListableBeanFactory(249) Returning cached instance of singleton bean 'org.springframework.transaction.interceptor.TransactionInterceptor#0'
DEBUG 15-11-04 12:39:24 org.springframework.beans.factory.support.DefaultListableBeanFactory(249) Returning cached instance of singleton bean 'transactionManager'
DEBUG 15-11-04 12:39:24 org.springframework.jdbc.datasource.DataSourceTransactionManager(367) Creating new transaction with name [com.developerForDrf.business.service.MemberServiceImpl.test]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; '',-java.lang.RuntimeException
DEBUG 15-11-04 12:39:24 org.springframework.jdbc.datasource.DataSourceTransactionManager(206) Acquired Connection [com.mysql.jdbc.JDBC4Connection@105cd8a] for JDBC transaction
DEBUG 15-11-04 12:39:24 org.springframework.jdbc.datasource.DataSourceTransactionManager(223) Switching JDBC Connection [com.mysql.jdbc.JDBC4Connection@105cd8a] to manual commit

这是调用测试接口的debug输出日志,看不太懂什么意思。。。



返回顶部
顶部