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

Spring学习(十四)Spring中如何使用事务?

2015-09-11 15:58 453 查看

一、为什么要使用事务?

如果我们一个业务逻辑只执行一次sql,是不需要使用事务的。但如果要执行多条sql语句才能完成一个业务逻辑的话,这个时候就要使用事务了。
因为这几条sql可能有的执行成功,有的执行失败。
而事务就是对一组sql语句进行统一的提交或回滚操作,为了保证数据执行的一致性,这组sql不是全部成功就是全部失败。


举个例子吧:

我们要实现转账的功能。首先要在账户a中扣100元,然后在账户b中加100元,这里涉及两次sql操作。大概像下面代码这样操作:

boolean flag1 = accountDao.minus(map)==1;
if(flag1){
// 减成功
map.put("toAccount", toAccount);
boolean flag2 = accountDao.plus(map)==1;
if(flag2){
// 加成功
return true;
}else{
/** 加失败 [减生效了] 回滚
*  为这个转账的过程添加事务控制
// 自定义异常
throw new PayException();
}
}else{
// 减失败
return false;
}


如果账户a减钱成功,账户b加钱失败(比如账户输入错误,数据库中没有这个账户,sql执行失败), 这里显然要把a账户减的钱还回来。即回滚。所以在这里需要添加事务控制。

二、如何在spring中添加事务?

spring中的事务 作为 局部事务 , 配置方式依赖于持久层使用的技术

spring整合jdbc

spring整合hibernate

spring中即提供了编程式事务的管理方式,也提供了声明式事务的管理方式:【编程式事务 TransactionTemplate 模板类 将事务的管理过程封装模板类中】

【声明式事务 AOP】

提供根接口 PlatFormTransactionManager 事务管理器接口

用于描述spring中事务如何管理[如何创建、如何提交、如何回滚]

声明式事务

底层采用AOP技术实现,将事务管理过程(创建、提交、回滚)封装在一个事务通知bean[AfterAdvice ThrowsAdvice]中;

通过在ioc容器中配置切入点的方式,将这个事务通知bean提供的事务管理功能引用给需要事务的核心业务逻辑方法(DAO)

在容器中添加配置如下:(这里orm用的mybatis)

applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="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 http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd"> 
<context:component-scan base-package="com"/>

<bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/etoak"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>

<bean id="ssf" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="ds"></property>
<property name="mapperLocations">
<list>
<value>classpath:com/etoak/dao/AccountDaoIf-mapper.xml</value>
</list>
</property>
</bean>

<bean id="accountDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="sqlSessionFactory" ref="ssf"></property>
<property name="mapperInterface" value="com.etoak.dao.AccountDaoIf"></property>
</bean>

<!--
配置声明式事务!
1 aop命名空间、schema文件
tx命名空间、schame文件(用于提供声明式事务的支持)
2 配置事务通知bean [Advice]
[before after around throws]
管理事务的使用方式[创建、提交、回滚]
transaction-manager: 设置事务管理器
事务管理器 PlatFormTransactionManager
- DataSourceTransactionManager
-->
<tx:advice id="tran" transaction-manager="tm">
<tx:attributes>
<!--
tx:method 为不同类型的方法添加不同的事务属性
-->
<tx:method name="pay"
isolation="DEFAULT"
propagation="REQUIRED"
read-only="false"
timeout="-1"
rollback-for="com.etoak.util.PayException"/>
<tx:method name="add*"/>
<tx:method name="del*"/>
<tx:method name="sel*" read-only="true"/>
<tx:method name="update*" timeout="10"/>
</tx:attributes>
</tx:advice>

<!--
配置事务管理器bean
-->
<bean id="tm" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="ds"></property>
</bean>

<!--
3 配置切入点
描述需要将通知[tran]提供的功能[事务管理功能]引用给哪个/哪些方法
-->
<aop:config>
<aop:pointcut
expression="execution(* com.etoak.service.*.*(..))"
id="pc"/>
<aop:advisor advice-ref="tran" pointcut-ref="pc"/>
</aop:config>
</beans>


配置好了,还要写一个异常类,在需要事务管理的地方抛出自己定义的异常,从而启用事务。

public class PayException extends Exception{
@Override
public String getMessage() {
return "减操作成功,加操作失败,失败原因:没有这个账户.转账失败,我要回滚";
}
}


在web.xml中添加异常页面配置:

<error-page>
<exception-type>com.etoak.util.PayException</exception-type>
<location>/error.jsp</location>
</error-page>


方法里面添加事务管理:

public class PayService {

@Autowired
private AccountDaoIf accountDao;

// 提供转账服务
public boolean pay(String fromAccount , String toAccount , Double money)throws Exception{

// 调用DAO
double yue = accountDao.查询余额(fromAccount);
if(yue>=money){
Map map = new HashMap();
map.put("fromAccount", fromAccount);
map.put("money" , money);
boolean flag1 = accountDao.minus(map)==1;
if(flag1){
// 减成功
map.put("toAccount", toAccount);
boolean flag2 = accountDao.plus(map)==1;
if(flag2){
// 加成功
return true;
}else{
/** 加失败 [减生效了] 回滚
*  为这个转账的过程添加事务控制
*  添加声明式事务
*  以AOP的方式进行添加
*  将事务的管理过程封装在一个事务通知bean
*  以配置、引用的方式将事务通知bean添加给需要事务的方法
*  切入点指向的是哪 : 服务层中Service对象提供的pay()
*
*  声明式事务回滚的方式:检测到异常时
*/
// 自定义异常
throw new PayException();
}
}else{
// 减失败
return false;
}
}else{
return false;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: