关键点:spring MVC 和 spring 是两个管理,自动扫描service 的bean必须在spring的配置文件中。 默认前提是:声明事务和配置没有问题,就是不回滚。
环境代码介绍:
springMVC配置文件:
<span style="white-space:pre"> </span><!-- 注解扫描包 -->
<context:component-scan base-package="com.baidu" />
<!-- 开启注解 -->
<mvc:annotation-driven />
spring 的配置文件:(没有扫描任何包文件,有spring全部扫描并加载)
<span style="white-space:pre"> </span><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 5. 使用声明式事务transaction-manager:引用上面定义的事务管理器 -->
<span style="white-space:pre"> </span><tx:annotation-driven transaction-manager="transactionManager" />
web.xml配置文件:
<!-- 配置监听器加载spring -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置spring 加载spring的配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-common.xml</param-value><span style="white-space:pre"> </span>
</context-param>
<span style="white-space:pre"> </span><!-- 配置springmvc 并加载spring的配置文件-->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<!-- 配置随着容器的启动创建springMVC -->
<load-on-startup>1</load-on-startup>
</servlet>
<span style="white-space:pre"> </span><servlet-mapping>
<span style="white-space:pre"> </span><servlet-name>springMVC</servlet-name>
<span style="white-space:pre"> </span><url-pattern>/</url-pattern>
<span style="white-space:pre"> </span></servlet-mapping>
测试代码:正常的 controller 、service impl、dao、mapper.xml,在serviceimpl加上注解事务,并排除runTimeException 事务不回滚
@Service
@Transactional
public class UserDiaryServiceImpl implements UserDiaryService {
@Resource
private UserDiaryDao userDiaryDao;
/**
* 添加用户登录记录
*/
public void saveLoginUserDiary(UserDiary userDiary) throws Exception {
userDiary.setAddTimes(new Date());
userDiary.setOperContent("登录");
userDiary.setOperType(1);
userDiary.setUserID(14L);
this.userDiaryDao.saveUserDiary(userDiary);
throw new RuntimeException("huigun");<span style="white-space:pre"> </span>//理论上该方法抛出运行时异常,上面插入的那条记录应该回滚,实际上没有回滚
}
debug信息展示:
[DEBUG] 2016-09-07 10:44:21,265 method:org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:843)
DispatcherServlet with name 'springMVC' processing POST request for [/baidu/user/login]
[DEBUG] 2016-09-07 10:44:21,269 method:org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:222)
Looking up handler method for path /user/login
[DEBUG] 2016-09-07 10:44:21,275 method:org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:229)
Returning handler method [public java.lang.String com.baidu.controller.LoginController.login(com.baidu.model.UserDiary)]
[DEBUG] 2016-09-07 10:44:21,275 method:org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:249)
Returning cached instance of singleton bean 'loginController'
[DEBUG] 2016-09-07 10:44:21,331 method:org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl.debug(JakartaCommonsLoggingImpl.java:46)
Creating a new SqlSession
[DEBUG] 2016-09-07 10:44:21,336 method:org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl.debug(JakartaCommonsLoggingImpl.java:46)
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@370bea1e] was not registered for synchronization because synchronization is not active
[DEBUG] 2016-09-07 10:44:21,372 method:org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:110)
<span style="color:#6633ff;background-color: rgb(255, 255, 255);">Fetching JDBC Connection from DataSource</span>
[DEBUG] 2016-09-07 10:44:21,373 method:org.springframework.jdbc.datasource.DriverManagerDataSource.getConnectionFromDriver(DriverManagerDataSource.java:142)
<span style="color:#3333ff;">Creating new JDBC DriverManager Connection to [jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8]</span>
[DEBUG] 2016-09-07 10:44:21,380 method:org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl.debug(JakartaCommonsLoggingImpl.java:46)
<span style="color:#ff0000;">JDBC Connection [com.mysql.jdbc.JDBC4Connection@944e79e] will not be managed by Spring</span>
[DEBUG] 2016-09-07 10:44:21,382 method:org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl.debug(JakartaCommonsLoggingImpl.java:46)
<span style="color:#3333ff;">ooo Using Connection [com.mysql.jdbc.JDBC4Connection@944e79e]</span>
[DEBUG] 2016-09-07 10:44:21,388 method:org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl.debug(JakartaCommonsLoggingImpl.java:46)
==> Preparing: insert into userdiary ( id,UserID,OperContent,OperType,Addtimes ) values (?,?,?,?,?)
[DEBUG] 2016-09-07 10:44:21,410 method:org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl.debug(JakartaCommonsLoggingImpl.java:46)
==> Parameters: null, 14(Long), 登录(String), 1(Integer), 2016-09-07 10:44:21.322(Timestamp)
[DEBUG] 2016-09-07 10:44:21,568 method:org.apache.ibatis.logging.commons.JakartaCommonsLoggingImpl.debug(JakartaCommonsLoggingImpl.java:46)
<span style="color:#ff0000;">Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@370bea1e]</span>
[DEBUG] 2016-09-07 10:44:21,569 method:org.springframework.jdbc.datasource.DataSourceUtils.doReleaseConnection(DataSourceUtils.java:327)
Returning JDBC Connection to DataSource
[DEBUG] 2016-09-07 10:44:21,576 method:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1595)
Invoking afterPropertiesSet() on bean with name 'index'
[DEBUG] 2016-09-07 10:44:21,576 method:org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1222)
Rendering view [org.springframework.web.servlet.view.JstlView: name 'index'; URL [/index.jsp]] in DispatcherServlet with name 'springMVC'
[DEBUG] 2016-09-07 10:44:21,576 method:org.springframework.web.servlet.view.AbstractView.exposeModelAsRequestAttributes(AbstractView.java:376)
Added model object 'userDiary' of type [top.lushunde.model.UserDiary] to request in view with name 'index'
[DEBUG] 2016-09-07 10:44:21,577 method:org.springframework.web.servlet.view.AbstractView.exposeModelAsRequestAttributes(AbstractView.java:376)
Added model object 'org.springframework.validation.BindingResult.userDiary' of type [org.springframework.validation.BeanPropertyBindingResult] to request in view with name 'index'
[DEBUG] 2016-09-07 10:44:21,581 method:org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:207)
Forwarding to resource [/index.jsp] in InternalResourceView 'index'
[DEBUG] 2016-09-07 10:44:21,592 method:org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
Successfully completed request
[DEBUG] 2016-09-07 10:44:21,593 method:org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:249)
Returning cached instance of singleton bean 'sqlSessionFactory'
在错误信息中蓝字和红字表示关键信息,其中红字表示作物原因:
<span style="color:#ff0000;">JDBC Connection [com.mysql.jdbc.JDBC4Connection@944e79e] will not be managed by Spring</span>
<span style="color:#ff6666;">是说 链接获取成功但是不能被spring管理。</span>
<span style="color:#ff6666;"></span><pre name="code" class="html"><span style="color:#ff0000;">Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@370bea1e]</span>
<span style="color:#ff0000;">关闭了没有事务的链接。</span>
原因就是:我们xml加载的springMVC配置中扫描了所有的bean,bean有springMVC管理,而我们通过spring添加声明时事务,spring又没有扫描和管理bean,所以事务并不会被spring管理,如debug提示信息所示,
<span style="color: rgb(255, 0, 0);">JDBC Connection [com.mysql.jdbc.JDBC4Connection@944e79e] will not be managed by Spring</span>
没有被spring管理,而是由springMVC管理,这是两个不同的管理域,储存不同地方东西,但是都可以正常注入。
解决方案:
我们将controller的文件有springMVC扫描管理,serivce、dao、intersector等使用spring扫描管理
具体修改配置文件:
springMVC的配置文件:
<!-- 注解扫描包 -->
<context:component-scan base-package="top.lushunde.controller" />
//只扫描contorller下的bean
spring的配置文件:
<!-- 注解扫描包 -->
<context:component-scan base-package="cn.dajean.mb" use-default-filters="false">
//扫描所有的bean
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
//排除不需要的扫描
</context:component-scan>////
<!-- 注解扫描包 -->
<context:component-scan base-package="cn.dajean.mb" ></context:component-scan> //扫描所有包
重新启动项目,可以回滚!