事务管理
标签: 事务管理 mysql
对登录注册程序添加事务管理:
pom.xml添加:
<!--aop使用aspectj切入点表达式-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.1.6.RELEASE</version>
</dependency>
spring-mybatis.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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.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">
<!--引入配置文件-->
<context:property-placeholder
ignore-resource-not-found="true"
location="classpath:/db.properties"/>
<!--数据源配置-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${password}"/>
<property name="maxActive" value="${jdbc.pool.maxActive}"/>
<property name="maxIdle" value="${jdbc.pool.maxIdle}"/>
<property name="minIdle" value="${jdbc.pool.minIdle}"/>
<property name="maxWait" value="${jdbc.pool.maxWait}"/>
<!-- 检查链接是否关闭的sql -->
<property name="validationQuery" value="select 1"/>
<property name="testOnBorrow" value="true"/>
</bean>
<!--mybatis与spring的整合,不需要mybatis自己的配置映射文件-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--配置连接数据库数据源-->
<property name="dataSource" ref="dataSource"/>
<!--配置Mapper文件所在位置-->
<property name="mapperLocations" value="classpath:/mybatis/*Mapper.xml"/>
</bean>
<!--MapperScannerConfigurer将会扫描basePackage并自动装配-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.wenjie.dao"/>
<!--<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>-->
</bean>
添加事务管理配置:
<!-- 配置JDBC数据源的局部事务管理器,使用DataSourceTransactionManager 类 -->
<!-- 该类实现PlatformTransactionManager接口,是针对采用数据源连接的特定实现-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 配置DataSourceTransactionManager时需要依注入DataSource的引用 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--配置事务增强处理,指定事务管理器-->
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" rollback-for="Exception" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- 配置一个切入点,匹配com.wenjie.service.impl包下所有类,所有方法的执行 -->
<aop:config>
<aop:pointcut id="myPointcut" expression="execution(* com.wenjie.service.impl.*.*(..))"/>
<!-- 通知器,指定在myPointcut切入点应用myAdvice事务增强处理 -->
<aop:advisor advice-ref="myAdvice" pointcut-ref="myPointcut"/>
</aop:config>
<!--由于需要事务控制,所以不能让spring自动扫描注入,spring会把它当做普通bean对象-->
<bean id="loginService" class="com.wenjie.service.impl.LoginServiceImpl"/>
<bean id="registerService" class="com.wenjie.service.impl.RegisterServiceImpl"/>
</beans>
Propagation取值:
REQUIRED(默认值):在有transaction状态下执行;如当前没有transaction,则创建新的transaction;
SUPPORTS:如当前有transaction,则在transaction状态下执行;如果当前没有transaction,在无transaction状态下执行;
MANDATORY:必须在有transaction状态下执行,如果当前没有transaction,则抛出异常IllegalTransactionStateException;
REQUIRES_NEW:创建新的transaction并执行;如果当前已有transaction,则将当前transaction挂起;
NOT_SUPPORTED:在无transaction状态下执行;如果当前已有transaction,则将当前transaction挂起;
NEVER:在无transaction状态下执行;如果当前已有transaction,则抛出异常IllegalTransactionStateException。
spring-mvc.xml注释service层自动注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<!--自动扫描且只扫描@Controller-->
<context:component-scan base-package="com.wenjie.controller">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--对service进行注入-->
<!--<context:component-scan base-package="com.wenjie.service"/>-->
<!-- 激活基于注解的配置 @RequestMapping, @ExceptionHandler,数据绑定 ,@NumberFormat ,
@DateTimeFormat ,@Controller ,@Valid ,@RequestBody ,@ResponseBody等 -->
<mvc:annotation-driven/>
<!-- 视图解析器配置,使用内部资源视图解析器,使用位于/WEB-INF/pages/目录下的后缀为jsp的文件作为视图 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/pages/"
p:suffix=".jsp"/>
</beans>
演示RegisterServiceImpl
现在如果RegisterServiceImpl和LoginServiceImpl有异常外抛,则会执行回滚,数据库里面不会进行操作。
package com.wenjie.service.impl;
import com.wenjie.dao.UserDao;
import com.wenjie.entity.User;
import com.wenjie.service.RegisterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* Created by Fate on 2016/7/4.
*/
public class RegisterServiceImpl implements RegisterService {
@Autowired
UserDao userDao;
public boolean register(String username, String password, String age) throws Exception {
User result = userDao.findByName(username);
if (result != null) {
return false;
}
User user = new User();
user.setName(username);
user.setPassword(password);
user.setAge(age);
user.setId(100);
int re = userDao.createUser(user);
userDao.createUser(user);
return re == 1;
}
}
利用主键唯一进行测试:
正常事务管理,报错:
数据库没有改变:
去掉事务管理:
也报错:
但是数据库插入了第一条数据:
注意:
. 如果你在RegisterServiceImpl和LoginServiceImpl中catch 住异常,不再抛出,异常没办法到事务管理器中,就不会触发回滚操作。
. 在配置了事务代理的Service业务逻辑实现类的方法里,若将异常捕获,并且在catch块中不对事务做显式提交(或其他应该做的操作如关闭资源等)=生吞掉异常!
. spring的事务边界是在调用业务方法之前开始的,业务方法执行完毕之后来执行commit or rollback(Spring默认取决于是否抛出runtime异常或unchecked异常)。如果抛出runtime exception并在你的业务方法中没有catch到的话,事务就会回滚。
. 所以一般不需要在业务方法中catch异常,如果非要catch,在做完你想做的工作后(比如关闭文件等)一定要抛出runtime exception,否则spring会将你的操作commit,这样就会产生脏数据,你的catch代码就是画蛇添足。
. 因此可以在上层做try……catch异常的捕捉处理
. 这里实际上反应了为什么要引入Service层的概念。
将事务管理放在Service层而不是dao层。可以将多次不同dao的操作放到同一个事务里。