1、引子
收款人、付款人,转账的金额,要求不能出现付款人的钱被扣除而收款人没有收到钱的情况发生。
sql事务操作
try{
//开启事务;
update account set money=money-100 where name='tom';
update account set money=money+100 where name='jerry';
//提交事务;
}catch(Exception e){
//回滚事务;
}
2、使用JDBC原生API模拟转账功能
jack转出1000块tom收入1000块
这样做显然是不符合前面说的那个事务的标准的,所以我们要进行修改:
正确的事务操作逻辑
注意这里
setAutoCommit(false)
就是说执行executeUpdate不是自动提交了,是由事务来操作。
3、使用DBUtils操作事务
这里如果我们使用Apache自己搞的DBUtils去简化JDBC的操作的时候,我们会发现,构造的QueryRunner这个核心类有些构造方法构造出的对象是不支持事务操作的!!(因为一些构造方法传入的是连接池,在同一个事务中两个对数据库的操作使用的可能是不同的连接)
比如:
支持事务的是如下构造的:
支持事务的QueryRunner构造方法
为什么这个可以?因为我们在对数据库进行具体操作的时候是要手动传Connection的,我们只要传相同的即可
正确代码如下:
代码1
代码2
然后相应的加try/catch/finally块,在catch块中加
conn.rollback();
4、对上述转账操作的原理分析:三层思想
分为3层:
- DAO:(data access object)数据访问层,用于增删改查
- Service:业务层,修改密码、找回密码类似的操作
-
Web层(就是View层):给用户看的
三层示意图
三层包的命名方法:
- com.itheima:公司域名倒写
- com.itheima.dao:dao层
- com.itheima.service:service层
- com.itheima.domain:javabean
- com.itheima.utils:工具
- com.itheima.web/view:web层
具体的三层思想实现的步骤:
【步骤一】:导入JDBC相关的jar包和工具类.
【步骤二】:创建包结构.
【步骤三】:编写各层的类,实现功能转账功能Test-->Service-->DAO
三层
上一篇文章我们学习了三层思想的基本思路,现在我们实地实践一下。
1、基本
项目结构- c3p0-0.9.1.2.jar:c3p0连接池
- mchange-commons-java-0.2.11.jar: c3p0连接池依赖的jar包
- commons-dbutils-1.6.jar:Apach公司自己搞的一个简化JDBC数据库操作的jar包
- mysql-connector-java-5.1.37-bin.jar:连接数据库必备jar包
2、DAO层(数据访问层)和Service层(业务层)
AccountDaoDAO直接操作数据库。
AccountService
位于view层和DAO层之间
如本篇开头所示的View、Service、DAO层图示,当我们在DAO层遇到异常时,就要使劲抛,因为DAO层只处理数据库的读取工作的,其他的业务处理(异常也算是业务处理一部分)不去做;
在Service遇到异常就要使劲解决,不能想着抛给View层,因为View层是直接接触用户的层,我们不大可能让用户来解决我们程序出现的问题
3、View层
View层4、总结
在Service层中,有数据库链接的获取,开启事务,提交事务,回滚事务,关闭链接等操作,很显然这些和我们Service层的业务层功能有所违背.
我们应该使用一个链接管理类,(这个类一般放到utils包中)专门负责数据库链接的获取,开启事务,提交事务,回滚事务,关闭链接,更为合适。
之前的初级版本主要是在事务处理方面的逻辑还交给了Service层去做,这与我们业务层的逻辑不大符合,这是不对的。
1、分离事务处理方面的逻辑
创建ConntionManager工具类,使当前线程下的Connection对象数据共享
上图中的Connection是存在一个叫做ThreadLocal的对象中的,在:
https://www.jianshu.com/p/7be7f73690fd有详细介绍。
注意这里
getConnectionFromtl()
的方法是关键!
然后在AccountService中就可以删除之前直接操作事务的代码,改为由这个工具类进行操作。
开启和提交事务 回滚和关闭连接
Tip:设置事务的隔离级别
设置隔离级别
在开启事务之前,设置事务的隔离级别,具体的内容自己去网上搜
网友评论