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 {
          //释放资源
      }
}

spring和MySQL事务区别 mysql事务和spring事务_存储引擎

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事务失效场景

访问权限问题

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

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