如何深入解析JavaWeb中的事务

72次阅读
没有评论

共计 2943 个字符,预计需要花费 8 分钟才能阅读完成。

如何深入解析 JavaWeb 中的事务,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

事务,大家所熟悉的事务(Transcation),基本上会就往 Spring 事务靠。其实 Spring 事务管理基于底层数据库本身的事务处理机制。数据库事务的基础,是掌握 Spring 事务管理的基础。下面总结一下数据库事务。

一、数据库事务

它的思想:we are 伐木累。就是多个 SQL 语句(一个团队),要么所有执行 success,不然就 fail。

它最终的目标:数据不会被破坏。即事务操作成功,数据的结果和业务期待的结果是一致的。这也就是 ACID 中的一致性(Consistency)。那什么是 ACID 呢?

二、ACID

上面是思想,牛人马上根据思想建模,DBMS 中数据库事务满足 4 各特性,即原子性、一致性、隔离性和持久性。下面一一生动解释:

a)原子性

原子是物质的最小单元,即不可再分。

例如,以 MySQL 为例,每一个简单的 SQL 语句即包含在一个事务中,具有原子性。这时候有人问了,那多个 SQL 呢?

BEGIN TRANSACTION; INSERT INTO `test`.`city` (`state`, `country`, `name`) VALUES (1 ,  China ,  CHINA , 错误语句多了个 VALUE  INSERT INTO `test`.`city` (`state`, `country`, `name`) VALUES (1 ,  China ,  CHINA  COMMIT;

结果:执行不通过。行 3 -5:为一个错误 SQL。行 6 -8:是一个正确的 SQL。它们各自被包裹在各自的隐式事务中,即 Read  Uncommited。T-all 包裹了上面具有原子性的 T - 1 和 T -2,实现了更大的原子,如下图。

b)一致性

*** 目标:数据不会被破坏。(这不是废话? 确实有点)具体说,事务操作成功后,数据库所处的状态和它的业务规则是一致的,即数据不会被破坏。举个栗子:两句 UPDATE 语句,从 A 账户转账到 B 账户,不管成功失败,A 和 B 账户的总额是不变的。

c)隔离性

隔离:表示互不干扰。事务与事务之间无法干扰,即每个事务独立,不会交叉。这样可以让多个线程并发访问数据库。如图:

但是聪明的小伙伴知道,如果事务完全隔离,每次只允许一个事务能访问数据库,那其他都是阻塞。会非常慢。

但是聪明的小伙伴也知道,这样会造成数据的并发问题。(是的,在下面第三节讲)。

d)持久性

数据必须持久化到数据库 (存储在磁盘) 中。已提交的事务,即使在提交后数据库崩溃,重启数据库时也能够根据日志对未持久化的数据进行重执行操作。(同学会问,那没提交的事务呢? 那就悲剧了( ﹏))

小结:数据的一致性是最终目标,其他特性都是其要求或手段。

三、隔离性中的问题:脏读、不可重复读和幻读

对应上面的隔离性,事务并发访问的时候会出现:脏读、不可重复读和幻读。案例转自勇哥博客

脏读:A 事务读取了 B 事务未提交的更改数据。一般数据库事务默认不允许该问题出现。

比如这里查询应该是 1500,现在出现了脏读。

时间事务 A(存款)事务 B(取款)

T1 开始事务

T2

开始事务

T3

查询余额(1000 元)

T4

取出 1000 元(余额 0 元)

T5 查询余额(0 元)

T6

撤销事务(余额恢复为 1000 元)

T7 存入 500 元(余额 500 元)

T8 提交事务

不可重复读:A 事务读取了 B 事务已提交的更改数据。

幻读:A 事务读取了 B 事务提交的新增数据。

上面的案例脑补吧,主要还是看下面。

不可重复读和幻读区别:一个更改,一个新增数据。其实两个区别在于一个是新增(insert 语句),处理幻读这个操作需要加表级别的锁,将整个表锁定,防止新增数据造成幻读。另一个则是更改(update  delete),这时候避免这个情况只需要添加行级锁组织该行发生变化即可。

四、事务隔离级别

既要求高的隔离性(安全性),又要求高并发性。这种是不可能的任务。根据各种锁的操作机制出现了一个事务隔离级别。即相同情况下的输入,不同隔离级别结果不同。为啥了,当然是在并发性和安全性的抉择。如图:

按着图说的,根据程序的并发性和安全性的抉择。鱼和熊掌不可兼得也~ 但分布式的时候,可以吧安全性关键的单独分布式锁。

好了,案例说了很多下面代码实战。

这段代码地址:https://github.com/JeffLi1993/jee-component-learning

五、JDBC 事务实战

下面利用 MYSQL JDBC 驱动连接 MySQL,代码如下:

public class TransactionLevels extends BaseJDBC { public static void main(String[] args) { try { //  加载数据库驱动  Class.forName(DRIVER); //  数据库连接  Connection conn = DriverManager.getConnection(URL,USER,PWD); //  数据库元数据  DatabaseMetaData metaData = conn.getMetaData(); //  是否支持事务  boolean isSupport = metaData.supportsTransactions(); System.out.println(isSupport); //  是否支持的事务  boolean isSupportLevel = metaData.supportsTransactionIsolationLevel(Connection.TRANSACTION_SERIALIZABLE); System.out.println(isSupportLevel); //  获取默认事务  int defaultIsolation = metaData.getDefaultTransactionIsolation(); System.out.println(defaultIsolation); /**  关闭数据库连接  */ if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } catch (Exception e) { e.printStackTrace(); } } }

第 5、7 行是连接数据库

第 9 行:获取数据库元数据,这是包含数据库连接信息

第 12 行:从元数据中,判断是否支持事务

第 15 行:从元数据中,判断是否支持事务级别 TRANSACTION_SERIALIZABLE

第 18 行:这里可以看出 MySQL 默认支持的事务级别是 READ_COMMITTED,默认会隔离脏读。

具体源码如下:

因此在安全性要求不高,支持高并发的情况下,选择 MySQL 默认事务等级。但在安全性极高,几乎不会出现高并发情况下,选择更高的事务等级。根据上小节的图一幕了然。

看完上述内容,你们掌握如何深入解析 JavaWeb 中的事务的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注丸趣 TV 行业资讯频道,感谢各位的阅读!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-19发表,共计2943字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)