spring事务

一、事务的基本原理
Spring事务 的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。对于纯JDBC操作数据库,想要用到事务,可以按照以下步骤进行:
    获取连接 Connection con = DriverManager.getConnection()
    开启事务con.setAutoCommit(true/false);
    执行CRUD
    提交事务/回滚事务 con.commit() / con.rollback();
    关闭连接 conn.close();
使用Spring的事务管理功能后,我们可以不再写步骤 2 和 4 的代码,而是由Spirng 自动完成

二、Spring 事务的传播属性

常量名
解释
PROPAGATION_REQUIRED 融入当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,也是 Spring 默认的事务的传播
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。新建的事务将和被挂起的事务没有任何关系,是两个独立的事务,外层事务失败回滚之后,不能回滚内层事务执行的结果,内层事务失败抛出异常,外层事务捕获,也可以不处理回滚操作
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED

如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。

PROPAGATION_NOT_SUPPORTED   以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。


三、隔离级别

一般数据库的隔离级别有4个,由低到高依次为Read uncommitted、Read committed、Repeatable read、Serializable,这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题。

 


√: 可能出现    ×: 不会出现

 

  脏读 不可重复读 幻读

说明

Read uncommitted

"读未提交",意思就是即使一个更新语句没有提交,但是别 
的事务可以读到这个改变.这是很不安全的。允许任务读取数据库中未提交的数据更改,也称为脏读。

Read committed ×

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

Repeatable read × × ×

"可以重复读",这是说在同一个事务里面先后执行同一个查询语句的时候,得到的结果是一样的.在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读

MVCC会帮助mysql避免幻读这种情况

Serializable × × ×

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

 

1.查看当前会话隔离级别
select @@global.tx_isolation, @@session.tx_isolation;
2.设置事务的隔离级别为“读未提交”

set session transaction isolation level read uncommitted;

   set global transaction isolation level read uncommitted;

3.设置事务的隔离级别为“读已提交”
set session transaction isolation level read committed;
 set global transaction isolation level read committed;

4、设置事务的隔离级别为“可重复读”

set session transaction isolation level repeatable read;

  set global transaction isolation level repeatable read;

5、设置事务的隔离级别为“序列化”

set session transaction isolation level serializable ;

  set global transaction isolation level serializable ;

 insert into demo value(5,"阳鑫磊",1,100);
5.命令行,开始事务
set autocommit=0 ;设置手动提交
  begin;开启事务

6.提交/回滚

commit/rollback

7.关于 select ... for update ;

当条件为索引时,用的是行锁,无索引时,是表锁.

8.乐观锁

增加版本号控制会避免两个update堵塞相继执行的情况

Read uncommitted

读未提交,顾名思义,就是一个事务可以读取另一个未提交事务的数据。

事例:老板要给程序员发工资,程序员的工资是3.6万/月。但是发工资时老板不小心按错了数字,按成3.9万/月,该钱已经打到程序员的户口,但是事务还没有提交,就在这时,程序员去查看自己这个月的工资,发现比往常多了3千元,以为涨工资了非常高兴。但是老板及时发现了不对,马上回滚差点就提交了的事务,将数字改成3.6万再提交。

分析:实际程序员这个月的工资还是3.6万,但是程序员看到的是3.9万。他看到的是老板还没提交事务时的数据。这就是脏读。

 

Read committed

读提交,顾名思义,就是一个事务要等另一个事务提交后才能读取数据。

事例:程序员拿着信用卡去享受生活(卡里当然是只有3.6万),当他埋单时(程序员事务开启),收费系统事先检测到他的卡里有3.6万,就在这个时候!!程序员的妻子要把钱全部转出充当家用,并提交。当收费系统准备扣款时,再检测卡里的金额,发现已经没钱了(第二次检测金额当然要等待妻子转出金额事务提交完)。程序员就会很郁闷,明明卡里是有钱的…

分析:这就是读提交,若有事务对数据进行更新(UPDATE)操作时,读操作事务要等待这个更新操作事务提交后才能读取数据,可以解决脏读问题。但在这个事例中,出现了一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读。

 

Repeatable read

重复读,就是在开始读取数据(事务开启)时,不再允许修改操作

事例:程序员拿着信用卡去享受生活(卡里当然是只有3.6万),当他埋单时(事务开启,不允许其他事务的UPDATE修改操作),收费系统事先检测到他的卡里有3.6万。这个时候他的妻子不能转出金额了。接下来收费系统就可以扣款了。

分析:重复读可以解决不可重复读问题。写到这里,应该明白的一点就是,不可重复读对应的是修改,即UPDATE操作。但是可能还会有幻读问题。因为幻读问题对应的是插入INSERT操作,而不是UPDATE操作。

 

Serializable 序列化

Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。

 

两条线程        一个线程 一个事务   保存命令 -- 推送  

                      另一个线程 开启新的事务  监听netty,如果没有客户端连接且有这条命令,切换极光推送

           

 

 

1. 数据结构

 

http://libisthanks.blog.163.com/blog/static/23527612320141016111027592/
事务的隔离性实现基于两个基本的数据结构,一个是行记录,一个是read_view。其中前者实现了MVCC,后者在其基础上实行了记录的可见性。
(1)首先来看下innodb的行结构,innodb中每行都有两个隐藏列:DATA_TRX_ID,DATA_ROLL_PTR。其中DATA_TRX_ID表示更新此条记录的最新事务ID,DATA_ROLL_PTR指向此条记录项的undo信息,可以通过这个指针找到之前的版本。对行记录的更新操作可以通过如下示例表示:
原有记录:

id:1

name:divid

age:25

DATA_TRX_ID:1

DATA_ROLL_PTR


事务A执行update table set name = “fxx” where id = 1 ,行记录变更为:

 

事务B执行update table set name = “libis” where id = 1 ,行记录变更为:

 

可见MVCC是基于两个隐藏列和undo log实现的(可以重用undo log,而且不需要专门对undo log进行维护)。

 

喜欢这篇文章?欢迎打赏~~

 

posted @ 2018-08-03 14:13  苍青浪  阅读(291)  评论(0编辑  收藏  举报