up:: JDBC封装一个DbUtils工具类
事务。MySQL事务是对于更新(插入,修改,删除)来说的,查询好像没有事务不事务一说。
一:JDBC事务介绍
MySQL之所以能在实际中使用,就是因为其有事务机制。MySQL,Oracle这样的关系型数据库都是支持事务的;也有很多小众的数据库是不支持事务的。
1.事务及事务区:
(1)【commit提交】
● 应用程序在写入数据时,并不是直接把数据放入到表中,而是先把数据放在事务区中;
● 事务区是MySQL自带的 ;如果数据很小的时候,事务区中的数据放在内存中,以加快处理速度;如果数据比较大的时候,其会用一块硬盘空间作为事务缓冲;
以A借给B100元为例:
首先,程序对A的余额作了减法操作,这是一个写操作,但是其不会直接反映到数据表中,而是先把这个操作的中间结果放在事务区中;
然后,程序对B的余额作了加法的操作,同样会把处理的中间结果放在事务区中
最后,当程序对这两个更新操作全部执行完以后,会主动的向MySQL发起一个commit提交的命令,这个commit提交命令会直接作用到MySQL事务区上;当MySQL看到程序进行commit事务提交后,于是MySQL的事务区会将刚才的加和减两个操作 一次性的 写入到数据表中;
即,进行程序的写操作的时候,两次的记录更新都是面向事务区的;只有当进行commit提交的时候,才由事务区真正的反映到数据表中(啰嗦一下:对于真正写入到数据表中的操作叫做“commit提交”);
当提交成功后,事务区中的数据的数据就没有意义了,由MySQL自动的把这个事务区清空,等待下一次应用程序再向事务区中进行新数据的写入。
(2)【rollback回滚】
以A借给B100元为例:
程序【对A的余额作了减法操作】操作正常;但是,由于某种原因程序【对B的余额作了加法的操作】的时候,程序报错了;那么JDBC的应用程序会向事务区发起一个【rollback回滚命令】;MySQL收到了这个回滚命令以后,其会直接将在事务区中原本已经处理好的【对A的余额作了减法操作】给清空;
即程序一旦向MySQL提交了【rollback回滚命令】以后,无论之前做了多少数据的前置处理,MySQL都会直接将事务区清空,最终的数据表中不会产生任何实质的写入操作;
事务总结一句话:作为事务来说,要么一次性全部完成;要么将之前所有已经做的事情通过回滚全部撤销。
实际的Java代码,主要是通过控制【commit提交】和【rollback回滚】命令的时机,只有应用程序发起了这样的命令,MySQL才可以执行对应的操作。
2.JDBC两种事务模式:
(1)自动提交事务模式:
自动提交事务模式是JDBC的默认模式。在每一次执行写操作(新增、修改、删除)的时候,每完成一次SQL语句都会自动的提交事务;
如果在程序中没有显式的写【conn.setAutoCommit(true)】,其默认就是自动提交事务模式;
因为每一次执行写操作(新增、修改、删除)的以后,其都会立即提交;;所以,复杂的业务(需要多条写操作一起)的情况下,无法保证多数据的一致性;
(2)手动提交事务模式:
commit()方法和rollback()方法都是Connection接口中定义的;
话句话说,事务设置为手动提交,事务的的提交和事务回滚,都是需要通过Connection连接来调用方法实现的。很显然,因为事务本来就是对于一次数据库连接来说的嘛!!!!!
二:事务案例
比如,一个公司入职1000个员工,这1000个人要么一次性全部入职,要么一个都不入职。像这种要么全做,要么什么都不做的事情,基于数据库的事务进行处理,是非常合适的。
、
1.没有使用【手动提交事务】模式时
(1)TransactionSample类编写
TransactionSample类:
(1)没有使用事务;(2)预期要求是,1000个人要么全部入职,要么一个也不入职;(3)为了模拟过程中出现的程序报错终端,使用了一个抛出异常(没有对这个抛出的异常捕获啦,目的就是使程序中断执行);
(2)运行结果
运行结果:运行结果不符合预期(1000个人要么全部入职,要么一个都不要入职);
额外说明一点: 因为上面程序中是抛出的【RuntimeException】,而在catch块中没有对【RuntimeException】的捕获,所以异常发生的时候,程序会中断,因此最后的【System.out.println(“你好啊。”);】没有执行。
(3)原因分析
失败原因分析:
● 默认情况下,JDBC会使用自动提交的模式;
● 自动提交:在前面执行的过程中,每执行一次update,即每执行一次【pstmt.executeUpdate();】,就立马对数据进行提交。所以,上面会出现【程序中断,但数据表中却出现了5条数据】的情况。
为了解决这个问题,需要在得到数据库连接对象之后,对其进行设置,以采用【手动提交事务】模式;
2.使用【手动提交事务】模式时
(1)TransactionSample类编写(出错的时候)
事务的设置,都是针对Connection对象来的!!!
(1)当【conn.setAutoCommit(false);】关闭自动提交后,每一次执行【pstmt.executeUpdate();】的时候,所产生的中间数据会被放入到事务区中;
(2)在程序报错,捕捉异常,然后进行回滚的时候,catch块只保留了最大的【catch (Exception e)】;;;;; 然后把回滚的操作放在了catch块中,这或许也是为什么只留最大的Exception的原因吧,。
(3)异常被捕获后,程序不会中中断,会继续执行;
(2)运行结果:(出错的时候)
(3)程序没有出错,正常执行
当程序正常执行的时候:
把这个异常抛出给注释掉,这个过程会正常执行;
运行效果:
在实际开发中,大多数的应用都是需要手动事务控制的。尤其是在金融项目中,数据强一致性的业务,必须要基于数据库的事务,而且要手动控制事务。
自我感觉,在实际中,某个业务所需的全部SQL操作,需要写在一个数据库连接(Connection对象)中,技术上是可以操作的,只是见得情况不多,没有感性的认识。