Mysql 事务与Spring事务

Mysql存储引擎

    mysql的存储引擎包括:MyISAM、InnoDB、BDB、MEMORY、MERGE、EXAMPLE、NDBCluster、ARCHIVE、CSV、BLACKHOLE、FEDERATED等,其中InnoDB和BDB提供事务安全性,其他存储引擎都是非事务安全性。

最常使用的2种存储引擎:

1.在MySQL 5.5之前,当您创建表而未明确指定存储引擎时,MyISAM是默认存储引擎。从版本5.5开始,MySQL使用InnoDB作为默认存储引擎。每个MyISAM在磁盘上存储成三个文件。文件名都和表名相同,扩展名分别是.frm(存储表定义)、.MYD(MYData,存储数据)、.MYI(MYIndex,存储索引)。数据文件和索引文件可以放置在不同的目录,平均分布io,获得更快的速度。

2.InnoDB存储引擎提供了具有提交、回滚和崩溃恢复能力的事务安全。但是对比Myisam的存储引擎,InnoDB写的处理效率差一些并且会占用更多的磁盘空间以保留数据和索。

Mysql事务和Spring事务

    一想到事务就是spring的事务,但是实际上Spring事务本质是对数据库事务的支持,如果数据库不支持事务(例如MySQL的MyISAM引擎不支持事务),则Spring事务也不会生效。

sql实现事务

    在说spring的事务之前,我想让大家回忆下,直接写sql语句是怎么实现事务来着?

//设置为手动提交,或者START TRANSACTION;都能开启事务​​​​
set autocommit=0; select * from t_user where `name`='xxx';update t_user set `password`='666' where `name`='xxx';COMMIT;

可见由三步组成:

  1. 开启事务

  2. 业务sql执行

  3. 提交/回滚事务

我们来看下不用spring的情况下完成事务的实现。

public void doTest(String arg) {      Connection conn = null;        PreparedStatement ps = null;      try {          Class.forName("com.mysql.jdbc.Driver");          conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbcdemo", "root", "123456");          //开启事务          String sql = "set autocommit=0";          ps = conn.prepareStatement(sql);          ps.execute();          sql = "update t_student set name = ?,age = ? where id = ?";          ps = conn.prepareStatement(sql);          ps.setString(1, "小明");          ps.setInt(2, 20);          ps.setInt(3, 2);          ps.executeUpdate();          //提交事务          conn.commit();      } catch (Exception e) {          if (conn != null){              try {                  //回滚事务                  conn.rollback();              } catch (SQLException e1) {                  e1.printStackTrace();              }          }      } finally {          //释放资源      }}

Mysql 事务与Spring事务_第1张图片

mysql默认的事务隔离级别:REPEATABLE-READ(select @@tx_isolation

脏读:一个事务对数据进行了增删改查,但是未提交事务。另一个事物可以读取到未提交的数据,如果第一个事务进行了回滚,那么第二个事务就读到了脏数据。

例子:领导给张三发工资,10000元已打到张三账户,但该事务还未提交,正好这时候张三去查询工资,发现10000元已到账。这时领导发现张三工资算多了5000元,于是回滚了事务,修改了金额后将事务提交。最后张三实际到账的只有5000元。

不可重复读:一次事务发生了两次读操作,两个读操作之间发生了另一个事务对数据修改操作,这时候第一次和第二次读到的数据不一致。不可重复度关注点在数据更新和删除,通过行级锁可以实现可重复读的隔离级别。

例子:张三需要转正1000元,系统读到卡余额有2000元,此时张三老婆正好需要转正2000元,并且在张三提交事务前把2000元转走了,当张三提交转账是系统提示余额不足。

幻读:指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行。

相对于不可重复读,幻读更关注其它事务的新增数据。通过行级锁可以避免不可重复读,但无法解决幻读的问题,想要解决幻读,只能通过Serializable隔离级别来实现。

Spring 声明式注解事务

使用声明式注解事务是比较简单的方式,将事务管理器交予 Spring 管理,在目标类或者目标方法上添加注解 @Transactional 即可同Propagation.REQUIRED

类型 名称 描述
事务传播行为 Propagation REQUIRED 当前如果有事务,Spring就会使用该事务;否则会开始一个新事务;默认选择
SUPPORTS 当前如果有事务,Spring就会使用该事务;否则不会开始一个新事务
MANDATORY 当前如果有事务,Spring就会使用该事务;否则会抛出异常
REQUIRES_NEW Spring总是开始一个新事务。如果当前有事务,则该事务挂起
NOT_SUPPORTED Spring不会执行事务中的代码。代码总是在非事务环境下执行,如果当前有事务,则该事务挂起
NEVER 即使当前有事务,Spring也会在非事务环境下执行。如果当前有事务,则抛出异常
NESTED 如果当前有事务,则在嵌套事务中执行。如果没有,那么执行情况与Transaction- Definition.PROPAGATION_REQUIRED一样
事务的隔离级别 Isolation

DEFAULT

默认隔离级别(多数数据库默认 )
READ_UNCOMMITTED 对应数据库 Read Uncommitted;产生 脏读、不可重复读、幻读
READ_COMMITTED 对应数据库 Read Committed;避免 脏读,产生不可重复读、幻读
READ_COMMITTED 对应数据库 Read Committed;避免 脏读,产生不可重复读、幻读
REPEATABLE_READ 对应数据库 Repeatable Read;避免 脏读、不可重复读,产生 幻读
SERIALIZABLE 对应数据库 Serializable,隔离级别最高

Spring事务失效场景

  1. 访问权限问题

    众所周知,java的访问权限主要有四种:private、default、protected、public,它们的权限从左到右,依次变大。

    但如果我们在开发过程中,把有某些事务方法,定义了错误的访问权限,就会导致事务功能出问题,例如:

  2. 未完,详细请看

你可能感兴趣的:(mysql,spring,mysql,java)