mysql事务

一、事务

        事务是一个原子操作,是一个最小执行单元,可以甶一个或多个SQL语句组成。在同一个事务当中,所有的SQL语句都成功执行时,整 个事务成功,有一个SQL语句执行失败,整个事务都执行失败。

1、事务特性

  • 原子性:事务的整个过程如原子操作一样,最终要么全部成功,或者全部失败,从最终结果来看这个过程是不可分割的。
  • 一致性:事务执行前和执行后的数据保持一致。
  • 隔离性:一个事务的执行不能被其他事务干扰。
  • 持久性:一个事务一旦提交,他对数据库中数据的改变就应该是永久性的。

2、Mysql中事务操作

        mysql中事务默认是隐式事务,执行insert、update、delete操作的时候,数据库自动开启事务、提交或回滚事务。是否开启隐式事务是由变量autocommit控制的。

隐式事务

        事务自动开启、提交或回滚,比如insert、update、delete语句,事务的开启、提交或回滚由mysql内部自动控制的。查看变量autocommit是否开启了自动提交。

显式事务

        事务需要手动开启、提交或回滚,由开发者自己控制。有2种方式手动控制事务:

-- 方式1、
-- 设置不自动提交事务
set autocommit=0;
insert into class values(null,"java1903");
insert into class values(null,"java1906");
commit; -- 提交 或者 rollback回滚;
set autocommit=1; -- 改回自动提交事务

-- 方式2、
start transaction; -- 开启事务
insert into class values(null,"java1908");
insert into class values(null,"java1911");
commit; -- 提交 或者 rollback回滚;

3、savepoint关键字

        在事务中我们执行了一大批操作,我们可以将一大批操作分为几个部分,然后指定回滚某个部分,可以使用savepoint来实现。例如下面的代码只有第一条添加语句被成功添加了。

start transaction; -- 开启事务
insert into class values(null,"java2002");
savepoint part1; -- 设置保存点
insert into class values(null,"java2005");
rollback to part1; -- 回滚至保存点
commit; -- 提交事务

        savepoint需要结合rollback to sp1一起使用,可以将保存点sp1到rollback to sp1之间的操作回滚掉。

4、只读事务

        表示在事务中执行的是一些只读操作,如查询,但是不会做insert、update、delete操作,数据库内部对只读事务可能会有一些性能上的优化。

二、mysql并发问题

1、脏读

一个事务在执行的过程中读取到了其他事务还没有提交的数据。两个事务同时操作同一数据,A事务对该数据进行了修改还没提交的时候,B事务访问了该条事务,并且使用了该数据,此时A事务回滚,那么B事务读到的就是脏数据。

2、不可重复读

        在同一事务中,多次读取同一数据返回的结果有所不同,换句话说,后续读取可以读到另一事务已提交的更新数据。

        这种情况发生在一个事务内多次读同一数据。A事务查询某条数据,该事务未结束时,B事务也访问同一数据并进行了修改。那么在A事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。

3、幻读

        当同一个查询在不同时间产生不同的行集时,就会出现所谓的虚影问题。例如,如果执行了两次SELECT,但是第二次返回了第一次没有返回的行,那么这行就是“幻影”行(幻读)。

        假设在子表的id列上有一个索引,并且你想从表中读取和锁定标识符值大于100的所有行,目的是稍后更新所选行的某些列:

SELECT * FROM child WHERE id > 100 FOR UPDATE;

        查询从id大于100的第一条记录开始扫描索引。让表包含id值为90和102的行。如果在扫描范围内的索引记录上设置的锁没有锁定在间隙(在本例中是90和102之间的间隙)中进行的插入,则另一个会话可以将id为101的新行插入到表中。如果要在同一事务中执行相同的SELECT,则会在查询返回的结果集中看到id为101的新行。

三、事务的隔离级别

        事务隔离是数据库处理的基础之一。用于在多个事务同时进行更改和执行查询时微调性能与可靠性、一致性和结果可再现性之间的平衡。隔离级别分为4种:    

1、读未提交( Read Uncommitted)

        SELECT语句以非锁定方式执行。因此,使用这个隔离级别,这样的读取是不一致的。这也被称为脏读。

2、读已提交( Read Committed)

        每个一致性读取,即使在同一个事务中,也会设置和读取自己的新快照。对于锁读(SELECT with For UPDATE或For SHARE)、UPDATE语句和DELETE语句,InnoDB只锁索引记录,而不锁它们之前的空白,因此允许在被锁的记录旁边自由插入新记录。间隙锁定仅用于外键约束检查和重复键检查。由于禁用了间隙锁定,因此可能会出现幻读问题,因为其他事务可以将新行插入间隙。

        使用READ COMMITTED有额外的效果:

  • 对于UPDATE或DELETE语句,InnoDB只对更新或删除的行持有锁。不匹配行的记录锁在MySQL计算完WHERE条件后释放。这大大降低了死锁的概率,但死锁仍然可能发生。
  • 对于UPDATE语句,如果一行已经被锁定,InnoDB执行“半一致”读取,将最新提交的版本返回给MySQL,以便MySQL可以确定该行是否符合UPDATE的WHERE条件。如果行匹配(必须更新),MySQL再次读取该行,这一次InnoDB要么锁定它,要么等待锁定它。        

3、可重复读( Repeatable Read)

        这是InnoDB默认的隔离级别。同一事务中的一致性读取,读取由第一次读取建立的快照。这意味着,如果在同一个事务中发出几个普通(非锁定)SELECT语句,这些SELECT语句彼此之间也是一致的。

        对于锁定读(SELECT with For UPDATE或For SHARE)、UPDATE和DELETE语句,锁定取决于语句是使用具有唯一搜索条件的唯一索引,还是使用具有唯一搜索条件的范围类型搜索条件。

  • 对于具有唯一查询条件的唯一索引,InnoDB只锁定找到的索引记录,而不锁定之前的空白记录。
  • 对于其他搜索条件,InnoDB锁定扫描的索引范围,使用间隙锁或下一键锁来阻止其他会话插入到范围所覆盖的间隙中。

4、串行化( Serializable)

        Serializable 是最严格的隔离级别。在Serializable隔离级别下,所有事务按照次序依次执行,因此,脏读、不可重复读、幻读都不会出现。虽然 Serializable 隔离级别下的事务具有最高的安全性,但是,由于事务是串行执行,所以效率会大大下降,应用程序的性能会急剧降低。如果没有特别重要的情景,一般都不会使用Serializable隔离级别。

  • 23
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
关于mysql事务处理 public static void StartTransaction(Connection con, String[] sqls) throws Exception { if (sqls == null) { return; } Statement sm = null; try { // 事务开始 System.out.println("事务处理开始!"); con.setAutoCommit(false); // 设置连接不自动提交,即用该连接进行的操作都不更新到数据库 sm = con.createStatement(); // 创建Statement对象 //依次执行传入的SQL语句 for (int i = 0; i < sqls.length; i++) { sm.execute(sqls[i]);// 执行添加事物的语句 } System.out.println("提交事务处理!"); con.commit(); // 提交给数据库处理 System.out.println("事务处理结束!"); // 事务结束 //捕获执行SQL语句组中的异常 } catch (SQLException e) { try { System.out.println("事务执行失败,进行回滚!\n"); con.rollback(); // 若前面某条语句出现异常时,进行回滚,取消前面执行的所有操作 } catch (SQLException e1) { e1.printStackTrace(); } } finally { sm.close(); } } 通常都是上述的写法, 在mysql 不支持事务的时候 , 中间的 setAutoCommit 的事务操作是不是都不生效. 现在innoDB支持 事务了, 上述的 java 代码是否能实现 以下的 事务隔离的 操作, 在修改的时候处于锁定状态 或者 只可以通过存储过程来实现, 单行的锁定 BEGIN; SELECT book_number FROM book WHERE book_id = 123 FOR UPDATE; --这里for update , 以前用Oracle的时候也是有这个行锁 // ... UPDATE book SET book_number = book_number - 1 WHERE book_id = 123; COMMIT;

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

游王子og

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值