当前位置: 首页 > 科技观察

JavaWeb图解&深入讲解:

时间:2023-03-13 17:14:46 科技观察

事务你一定知道,大家熟悉的事务(Transcation)基本都依赖于Spring事务。实际上,Spring的事务管理是基于底层数据库本身的事务处理机制。数据库事务的基础是掌握Spring事务管理的基础。本文总结了数据库事务。1、数据库事务的思路:我们厌倦了日志记录。即多条SQL语句(一队),或者全部执行成功,或者失败。它的最终目标:数据不会被破坏。即事务操作成功,数据结果与业务预期结果一致。这就是ACID中的一致性(Consistency)。那么什么是酸?第二,ACID是基于idea的,师傅们立马按照idea建模。DBMS中的数据库事务满足四个特性,即原子性、一致性、隔离性和持久性。下面一一生动讲解:a)原子性原子是物质的最小单位,即不能再分。比如以MySQL为例,每条简单的SQL语句都包含在一个事务中,是原子的。这时候有人问了,多条SQL呢?开始交易;INSERTINTO`test`.`city`(`state`,`country`,`name`)VALUES('1','China','CHINA','错误语句有更多的VALUE');INSERTINTO`test`.`city`(`state`,`country`,`name`)VALUES('1','China','CHINA');COMMIT;结果:执行失败。第3-5行:对于错误SQL。第6-8行:是一个正确的SQL。它们每个都包含在自己的隐式事务中,ReadUncommited。T-all将上面的原子T-1和T-2包裹起来,实现一个更大的原子,如下图所示。b)一致性***目标:数据不会被破坏。(这不是废话吗?确实有点)具体来说,事务操作成功后,数据库的状态与其业务规则一致,即数据不会被破坏。举个栗子:两条UPDATE语句,从A账户转账到B账户,无论成功与否,A账户和B账户的总金额不变。c)Isolation隔离:指互不干扰。交易之间没有干扰,即每笔交易都是独立的,不会重叠。这允许多个线程并发访问数据库。如图:但是聪明的朋友都知道,如果事务是完全隔离的,一次只允许一个事务访问数据库,那么其他的都是阻塞的。会很慢。但是聪明的朋友也知道这样会造成数据的并发问题。(是的,在下面的第三部分)。d)持久化数据必须持久化到数据库(存储在磁盘上)。对于一个已提交的事务,即使提交后数据库崩溃,在重启数据库时也可以根据日志重新执行未持久化的数据。(有同学会问,那未提交的事务呢?那就悲剧了(>﹏<))总结:数据一致性是最终目的,其他特性是它的要求或手段。3、隔离问题:脏读、不可重复读、幻读对应上面的隔离。当并发访问事务时,会出现:脏读、不可重复读、幻读。案例转自勇哥的博客脏读:A事务读取B事务未提交的变更数据。一般的数据库事务默认不允许出现这个问题。比如这里查询应该是1500,现在出现了脏读。时间交易A(存款)交易B(取款)T1开始交易T2开始交易T3查询余额(1000元)T4取款1000元(余额0元)T5查询余额(0元)T6取消交易(余额恢复到1000元)T7存入500元(余额为500元),T8提交不可重复读:事务A读取事务B提交的变化数据。幻读:A事务读取B事务提交的新数据。补一下上面的案例,主要看下面的。不可重复读和幻读的区别:一种是改变,一种是添加数据。其实两者的区别在于,一个是new(insert语句),而幻读操作需要表级的锁来锁住整张表,防止new数据引起的幻读。另一个是更新删除。这时,要避免这种情况,只需要加一个行级锁,防止行发生变化即可。第四,事务隔离级别既要高隔离(安全),又要高并发。这是一项不可能完成的任务。根据各种锁的运行机制,出现了事务隔离级别。即相同情况下的输入,不同隔离级别的结果是不同的。为什么,当然是并发性和安全性之间的选择。如图:根据图片,根据程序的并发性和安全性进行选择。鱼和熊掌不可兼得~但是在分布式的时候,可以使用一个单独的分布式锁,这对安全性很关键。好了,案例已经说了很多,下面代码的实战。这段代码地址:https://github.com/JeffLi1993/jee-component-learning5.JDBC事务实践接下来使用MYSQLJDBC驱动连接MySQL。代码如下:publicclassTransactionLevelsextendsBaseJDBC{publicstaticvoidmain(String[]args){try{//加载数据库驱动Class.forName(DRIVER);//数据库连接Connectionconn=DriverManager.getConnection(URL,USER,PWD);//数据库metadataDatabaseMetaDatametaData=conn.getMetaData();//是否支持事务booleanisSupport=metaData.supportsTransactions();System.out.println(isSupport);//是否支持事务booleanisSupportLevel=metaData.supportsTransactionIsolationLevel(Connection.TRANSACTION_SERIALIZABLE);System.out.println(isSupportLevel);//获取默认事务intdefaultIsolation=metaData.getDefaultTransactionIsolation();System.out.println(defaultIsolation);/**关闭数据库连接*/if(conn!=null){try{conn.close();}catch(SQLExceptione){e.printStackTrace();}}}catch(Exceptione){e.printStackTrace();}}}第5、7行是连接数据库第9行:获取数据库元数据,其中包含数据库连接信息第12行:从元数据中判断是否支持事务第15行:从元数据中判断是否支持事务级别TRANSACTION_SERIALIZABLE。第18行:这里我们可以看到MySQL默认支持的事务级别是READ_COMMITTED,脏读默认会被隔离。具体源码如下:因此,当安全性要求不高,支持高并发时,选择MySQL默认事务级别。但是在安全性高,几乎没有高并发的情况下,选择更高的事务级别。根据上一节的图,一目了然。【本文为专栏作家“李强强”原创稿件,转载请联系作者获得授权】点此查看该作者更多好文