以下文章来源于何先振,责编小何

当我们使用JDBC技术操作数据库的时候,需要实现一个业务逻辑。往往我们会给数据库发送多条SQL语句。
例如,转账业务逻辑,我们新建一张用户账户表。

添加两个账户信息。

要想完成转账业务逻辑,张三给李四转账100元。
需要修改张三的账户信息减100,李四的账户信息加100。这里涉及到两个update的语句。

执行这两条SQL,成功完成了转账操作。

但是这是理想情况,两条SQL语句都执行成功了。
在Java程序中使用JDBC操作数据库时,很容易因为一些错误,导致一个SQL执行成功,一个SQL执行不成功,影响到我们的业务逻辑出错。
例如:我们通过前面几节封装的通用工具类实现转账功能。中间模拟一个网络异常。

调用的是工具类中通用增删改的方法。

执行后发现,程序出错。

转账业务逻辑出现错误,张三减去的100元,没有加到李四上,直接消失了。

按照正常逻辑:要么转账成功,要么转账失败。如果转账失败需要把钱退回张三的账户上。
为了业务逻辑能正常,我们需要通过数据库的事务来保证。
什么是数据库事务呢?
事务是一组逻辑操作的单元,使数据从一种状态变成另外一种状态。
一组逻辑操作的单元:就是一个或多个SQL操作。
例如:刚刚转账就是两个update的操作。这两个update看成一个整体构成了一个事务,实现了这个转账的业务逻辑。
从一种状态变成另外一种状态:就是事务执行的结果,只会有两种状态要么转账成功,张三少了一百,李四多了一百。要么转账失败,张三钱没变,李四钱也没变。
这也是事务的原则,保证所有事务都可以作为一个工作单元来执行,即使出现问题也不能改变这种执行方式。要么全部执行成功被提交,要么全部执行失败事务被回滚。
默认情况下,MySQL会把每一条DML语句当成一个事务,一旦执行就会自动提交。
我们可以修改这种默认规则,改成手动提交事务。
如果执行成功就提交事务,如果执行过程中出现异常就回滚事务。但是注意要保证这组SQL操作完才关闭连接。因为关闭连接也会导致事务提交。
通过事务解决问题
修改事务手动提交实现转账功能,首先需要获取连接对象。通过setAutoCommit(false),关闭自动提交事务。

然后利用方法的重载,在新建一个工具类的通用增删改方法,新增连接对象入参。因为一个事务要共用一个连接对象。

将原来执行完关闭资源的方法,连接对象修改为null,因为要保证一个事务的SQL都被执行完了才关闭。

最终重载支持事务的通用增删改方法:

调用修改好的通用增删改方法。

没有出现异常,手动提交事务。使用commit()方法。

如果出现异常了,使用rollback()方法回滚事务。

最后都执行完了,才关闭连接。

没转账之前的用户账户金额。

中间模拟了网络异常。

执行程序,程序出现异常。

转账失败,数据库事务回滚,数据还是跟没转账时一样。

去掉模拟网络异常的代码。

执行程序,转账成功。

金额正常被转了过去。

注意点:
DML语句我们是可以取消他的默认事务提交机制,改成手动控制提交。但是DDL语句是不行的。每次创建一个表就会自动提交事务。
如果使用了数据库连接池,我们关闭了连接对象,连接对象会被放回到池子里,给其它事务使用。
所以如果设置了手动提交事务,关闭资源时需要恢复默认,避免影响其它事务使用这个连接对象。

至于什么是数据库连接池,后面章节会接着讲解。

扫码进微信答疑群





