2018.5.4
仅为个人理解 不足之处欢迎指正~
什么是事务管理?
事务管理是对于一系列数据库操作进行管理,一个事务包含一个或多个SQL语句,是逻辑管理的工作单元(原子单元)
事务管理的核心在于 回 滚
什么情况下需要事务管理?
对数据库中的数据进行批量操作或多表操作时,为了保证数据的正确性和一致性,需要添加事务管理机制进行管理
举例说明:
银行转账操作细分为两个步骤:(A向B转账100元)
(1)A用户账户余额减少100元
(2)B用户账户余额增加100元
那么假如当执行完(1)步骤而未完成(2)步骤时
情况发生变化 如服务器宕机 或者用户取消转账
那此时A的余额减少而B的余额没有增加 势必会造成错误
不进行事务管理的情况
由于之前的项目是各种登录注册之类的业务 较难模拟真实的需要事务管理的操作
我们假想以下操作:
连续注册两个用户 其中第一个用户合理 第二个用户的用户名超过了数据库中定义的最大长度
将这两个插入过程等价于转账中的减少余额与增加余额
第二个插入失败 则第一个插入的结果应该撤销
在UserService.java中增加一个测试方法:
和他的实现:
编写Controller接受指令:
package controller;
import javax.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import pojo.User;
import service.UserService;
@Controller
public class TestController
{
@Resource
UserService userService;
@RequestMapping("/shiwuguanli")
public ModelAndView shiwuguanli()
{
ModelAndView mv = new ModelAndView("welcome");
userService.add2User();
return mv;
}
}
运行程序并测试:
服务器报错 此时查看数据库:
发现第一个插入操作完成 第二个未完成
使用注解进行事务管理
第一步:
在spring-mybatis配置文件中加入:
注:jdbcDataSource为自己配置的数据池名称
第二步:
在所需事务管理的方法上加注解@Transactional
再次运行测试
页面同样报错,但数据库中没有出现任何一条插入信息
注意点:
1.注解需要加在Service的实现中 而不是接口或其他位置
2.不要使用try catch捕获异常 这样将不会进行事务回滚
若需要捕获异常又需要事务回滚 推荐使用以下方法:
@Transactional
@Override
public void add2User()//事务管理测试
{
try
{
User user=new User("放得下","mima1","电话1","邮箱1");
User user2=new User("放不下放不下放不下放不下放不下放不下放不下放不下",
"mima1","电话1","邮箱1");
userdao.addUser(user);
userdao.addUser(user2);
}
catch(Exception e)
{
System.out.println("服务器异常");
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
通过
手动回滚
页面不会报错 数据库中也不会多出数据
使用AOP进行事务管理
我们将刚才的@Transactional去除
开始使用AOP方式进行事务管理:
在spring-mybatis的配置文件中加入以下语句:
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" isolation="DEFAULT"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="shiwuguanli"
expression="execution(* service.UserService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="shiwuguanli"/>
</aop:config>
其中:
代表“add开头 任意后缀的方法” 我们之前使用的方法是add2User 所以包含在这之中
<tx:method>中的标签有很多
name:方法名的匹配模式,通知根据该模式寻找匹配的方法。
propagation:设定事务定义所用的传播级别。
isolation:设置事务的隔离级别。
timeout:指定事务的超时(秒)。
read-only:该属性为true指示事务是只读的
no-rollback-for:以逗号分隔的异常类的列表,目标方法可以跑出这些异常而不会导致通知执行回滚
rollback-for:以逗号分隔的异常类的列表,当目标方法跑出这些异常时会导致通知执行回滚。默认情况下,该列表为空,因此不在no-rollback-for列表中的任何运行时异常都会导致回滚。
这里不做详细解释 一般可以采用默认的配置形式
这里表示的是将刚才的txAdvice织入
在调用UserService中所属的所有方法时会调用事务管理 但是要满足上面的name
运行测试成功 页面没有报错信息 数据库中没有插入数据
同时控制台输出了捕获的异常
其他代码:
本文基于之前的各篇SSM学习记录 其他代码没有做出改动
项目结构如下:
这一个测试中没有创建新的view层页面 仅用浏览器指令完成
总结:
本文仅演示了一种简单的需要事务管理的情景
而事物的四大特征:原子性、一致性、隔离性、持久性
还可以衍生出其他很多种需要事务管理的情况
尤其是隔离性所要求的 本业务的数据不会受到其他业务的干扰 非常重要
具体情况具体分析
谢谢~