事务

为什么写这系列的文章

在日常的工作和开发中,接触最多的便是与数据库打交道,无论你使用什么框架进行开发都绕不开事务的管理. 在Java开发中你可能会接触很多ORM框架,无论是Hibernate、MyBatis、还是Spring Jdbc 都会遇到事务的相关操作,再到中大型项目,你还会遇到单一数据源本地事务、多数据源本地事务、分布式事务、分布式多数据源事务等各种奇葩环境,数据的一致性也会面临各种挑战,在这时如何游刃有余的处理数据一致性就考验你对事务的理解,也正是这系列文章写作的真正原因.

由于我换工作原因,先后在峰鸟科技、人人网、国家电网待过一段时间,先后接触了不同的ORM框架

峰鸟科技在这里由于SQL比较灵活,同时考虑到性能问题,这里直接使用的Spring JDBC,为了提高开发效率,我也开发了一个简单ORM框架,用来将javabean 和 数据库表信息进行关联,提供了简单的增删改查和分页功能,这时候也是我初步接触框架的开发,接触反射、代理等功能

人人网在这里先后使用 Python 和 Java 进行开发,用过MyBatis、Django-orm、sqlalchemy、JPA、Jade等ORM框架。其中Jade是人人网自行开发的ORM框架,使用简单,支持条件化语句、支持多数据源切换和多数据源事务功能,相对MyBatis来说,使用方式和功能更加友好,强大。

国家电网在这里主要使用的MyBaits,第一次看见Spring事务注解可以添加到类上而不是方法上,这也说明你懂的还是不多

通过不同的经历,也先后接触到了JDBC事务、Spring事务、Hibernate事务、MyBaits事务、多数据源事务、分布式事务的使用和解决方案,这里总结一下

事务概念

事务(Transaction):一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。

数据库事务(Database Transaction):是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。事务是数据库运行中的逻辑工作单位,由DBMS中的事务管理子系统负责事务的处理。

ACID

  1. atomicity 原子性 原子性:操作这些指令时,要么全部执行成功,要么全部不执行。只要其中一个指令执行失败,所有的指令都执行失败,数据进行回滚,回到执行指令前的数据状态。
  2. consistency 一致性 一致性:事务的执行使数据从一个状态转换为另一个状态,但是对于整个数据的完整性保持稳定。
  3. isolation 隔离性 隔离性:在该事务执行的过程中,无论发生的任何数据的改变都应该只存在于该事务之中,对外界不存在任何影响。只有在事务确定正确提交之后,才会显示该事务对数据的改变。其他事务才能获取到这些改变后的数据。
  4. durability 持久性 持久性:当事务正确完成后,它对于数据的改变是永久性的。

并发事务导致的问题

在许多事务处理同一个数据时,如果没有采取有效的隔离机制,那么并发处理数据时,会带来一些的问题。

脏读(Dirty Read)

当一个事务读取另一个事务尚未提交的修改时,产生脏读。

同一事务内不是脏读。 一个事务开始读取了某行数据,但是另外一个事务已经更新了此数据但没有能够及时提交。这是相当危险的,因为很可能所有的操作都被回滚,也就是说读取出的数据其实是错误的。

非重复读(Nonrepeatable Read)

一个事务对同一行数据重复读取两次,但是却得到了不同的结果。同一查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发生非重复读。

幻读(Phantom Reads)

事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据(这里并不要求两次查询的SQL语句相同)。这是因为在两次查询过程中有另外一个事务插入数据造成的。

当对某行执行插入或删除操作,而该行属于某个事务正在读取的行的范围时,会发生幻像读问题。

丢失修改(Lost Update)

第一类:当两个事务更新相同的数据源,如果第一个事务被提交,第二个却被撤销,那么连同第一个事务做的更新也被撤销。

第二类:有两个并发事务同时读取同一行数据,然后其中一个对它进行修改提交,而另一个也进行了修改提交。这就会造成第一次写操作失效。

事务隔离

为了兼顾并发效率和异常控制,在标准SQL规范中,定义了4个事务隔离级别.

读未提交(Read Uncommitted)

直译就是"读未提交",意思就是即使一个更新语句没有提交,但是别的事务可以读到这个改变。

Read Uncommitted允许脏读。

读已提交(Read Committed)

直译就是"读提交",意思就是语句提交以后,即执行了 Commit 以后别的事务就能读到这个改变,只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别。

Read Commited 不允许脏读,但会出现非重复读。

可重复读(Repeatable Read):

直译就是"可以重复读",这是说在同一个事务里面先后执行同一个查询语句的时候,得到的结果是一样的。

Repeatable Read 不允许脏读,不允许非重复读,但是会出现幻象读。

串行读(Serializable)

直译就是"序列化",意思是说这个事务执行的时候不允许别的事务并发执行。完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞。

Serializable 不允许不一致现象的出现。

通过不同的隔离级别,可以防止一些并发事务问题,同时级别越高则相应性能越低,这个设置需要根据实际场景进行设置.

原文发布于微信公众号 - 777开发日记(gh_773193545262)

原文发表时间:2018-11-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏企鹅号快讯

JDBC编程

前面我们已经讨论了数据库的安装和简单的使用,还没完成的可以先去Mysql的安装和Mysql数据库的简单操作回顾一下哦!今天我们来简单学习JDBC编程的准备和链...

35480
来自专栏微信公众号:Java团长

抢红包案例分析以及代码实现(二)

上一篇文章中使用ssm+mysql实现,存在并发超发问题,这里我们使用悲观锁的方式来解决这个逻辑错误,并验证数据一致性和性能状况。

12110
来自专栏jojo的技术小屋

原 web安全、XSS、CSRF、注入攻击

作者:汪娇娇 时间:2017年8月15日 当时也是看了一本书《白帽子讲web安全》,简单的摘录然后做了个技术分享,文章不是很详细,建议大家结合着这本书看哈。 w...

55070
来自专栏owent

理解Raft算法

之前已经有Paxos算法,用于解决分布式系统最终一致性问题,而且已经有了zookeeper这个成熟的开源实现。那么这个Raft算法有啥用呢?按照Raft官网的说...

57630
来自专栏Java后端技术栈

并发控制中的乐观锁与悲观锁

在多用户环境中,在同一时间可能会有多个用户更新相同的记录,这会产生冲突。这就是著名的并发性问题。

13570
来自专栏散尽浮华

zabbix问题记录

zabbix部署好,在使用一段时间后,出现了不少报错,在此简单做一记录。 1)Zabbix监控界面报错“Lack of free swap space”解决 公...

46680
来自专栏个人分享

Spark BlockManager的通信及内存占用分析(源码阅读九)

  之前阅读也有总结过Block的RPC服务是通过NettyBlockRpcServer提供打开,即下载Block文件的功能。然后在启动jbo的时候由Drive...

14620
来自专栏FreeBuf

负载恶意软件HawkEye的VB Inject样本分析

恶意软件HawkEye的利用大多都是通过钓鱼邮件分发,利用office直接启动HawkEye主体或者一些经过加密的程序,本文中的VB Inject属于后者,也把...

9010
来自专栏Ryan Miao

CentOS(linux)安装PostgreSQL

PostgreSQL是一个功能强大的开源数据库系统。经过长达15年以上的积极开发和不断改进,PostgreSQL已在可靠性、稳定性、数据一致性等获得了业内极高的...

21920
来自专栏芋道源码1024

75 道 BAJT 高级 Java 面试题,你能答上几道?

希望大家在每天闲暇之余学习其中几道题目,日积月累,去 BAJT 面试时,一切都水到渠成。

24530

扫码关注云+社区

领取腾讯云代金券