Rc mysql mvcc_浅谈mysql mvcc

以下为个人理解,如有错误,还望指正!!

mysql的大多数事务型存储引擎实现的都不是简单的行级锁,基于提升并发性能的考虑,他们一般都同时实现了多版本并发控制,可以认为MVCC是行级锁的一个变种,但是它在很多情况下避免了加锁操作,因此开销更低,虽然实现机制有所不同,但大都实现了非阻塞的读操作,写操作也只锁定必要的行。

MVCC的实现是通过保存数据在某个时间点的快照来实现的,也就是说,不管需要执行多长时间,只要事务开始时间相同,每个事务看到的数据都是一致的,事务开始的时间不同时,每个事务对同一张表,同一时刻看到的数据可能是不一样的(因为不同的时间点可能数据就已经产生了不同的快照版本,而每个事务在默认的RR隔离级别下只能看到事务开始时的数据快照)。说道不同的存储引擎的MVCC实现是不同的,典型的有乐观并发控制和悲观并发控制,下面简单说明MVCC是如何工作的:

innodb的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的,这两个列,一个保存了行的创建时间,一个保存了行的过期时间(或删除时间),当然,存储的并不是实际的时间值,而是系统版本号(system version number),每开始一个新的事务,系统版本号都会自动递增,事务开始时刻的系统版本号作为事务的版本号,用来和查询到的每行记录的版本号进行比较,下面看repeatable read隔离级别下,MVCC具体是如何操作的:

select:

innodb会根据以下两个条件检查每行的记录

A:innodb只查找版本早于当前事务版本的数据行(也就是,行的系统版本号小于或等于事务的系统版本号),这样可以确保事务读取的行,要么是在事务开始之前已经存在,要么是事务自身插入或修改的数据。

B:行的删除版本要么未定义,要么大于当前事务版本号,这可以确保事务读取到的行,在事务开始之前未被删除(即,这样做的目的是为了事务不会读取到被真正删除的行,删除版本号小于当前事务版本号的表示操作删除记录的事务已经提交--数据已经被删除,删除版本号大于当前事务版本号的表示这个事务是在当前事务之后开始的--当前事务开始时这些记录是还存在的,根据事务的隔离性,一致性要求,之后开始的事务操作的记录并提交,对当前事务不可见,所以还需要当前事务能够查询这些记录--只能够查询,不能够修改和删除)。

只有满足以上两个条件的才可以返回作为查询结果。

insert:

innodb为新插入的每一行保存当前系统版本号作为行版本号

delete:

innodb为删除的每一行保存当前系统版本号作为行删除标识

update:

innodb为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识

保存这两个额外的系统版本号,使大多数读操作都可以不用加锁,这样设计使得读数据操作很简单,性能很好,并且也能保证只会读取到符合标准的行,不足之处是每行记录都需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作。

MVCC只在repeatable-read和read-committed两个隔离级别下才工作,其他两个隔离级别都和MVCC不兼容,因为read uncommitted总是读取最新的数据行,而不是符合当前事务版本的数据行,而serializeble则会对所有读取的行都加锁。

另外要注意:MVCC在RR和RC隔离级别下的区别,在RR隔离级别下,一个事务只能读取到事务开始的那个时刻的数据快照,即,别的事务修改并提交的数据在自身没有提交之前一般读取不到(加for update语句的select除外,因为这个语句要对数据加X锁必须读取最新的数据快照),在RC隔离级别下,事务总是读取数据行的最新快照,即会产生不可重复读的问题。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MVCC(Multi-Version Concurrency Control)是MySQL InnoDB存储引擎的一种并发控制机制,可以提高数据库的并发性能。下面是Java实现MVCC的大致思路: 1. 在Java中实现MVCC需要使用到数据库连接池,可以使用开源的c3p0或Druid连接池。 2. 在InnoDB存储引擎中,每行数据都有一个隐藏的6字节的事务ID(即版本号),表示该行数据的版本号。在Java中,可以使用一个类来表示这个版本号,比如: ```java public class TxnId { private int trxId; // 事务ID private int rollPointer; // 回滚指针 // 省略get、set方法 } ``` 3. 当一个事务开始时,需要从连接池中获取一个数据库连接,并设置该连接的事务隔离级别为可重复读(Repeatable Read)。在Java中,可以使用JDBC来设置事务隔离级别。 ```java try { Connection conn = pool.getConnection(); conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ); conn.setAutoCommit(false); // 执行一些SQL语句 conn.commit(); } catch (Exception e) { // 异常处理 } ``` 4. 当从数据库中读取数据时,需要读取该数据的最新版本。如果该数据的版本号比当前事务的版本号旧,说明该数据已经被其他事务修改过了,当前事务不能读取该数据。在Java中,可以使用SELECT ... FOR UPDATE语句来实现这个功能。 ```java try { Connection conn = pool.getConnection(); conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ); conn.setAutoCommit(false); String sql = "SELECT * FROM table WHERE id = ? FOR UPDATE"; PreparedStatement ps = conn.prepareStatement(sql); ps.setInt(1, id); ResultSet rs = ps.executeQuery(); if (rs.next()) { // 读取数据 } conn.commit(); } catch (Exception e) { // 异常处理 } ``` 5. 当向数据库中插入、更新、删除数据时,需要生成一个新的版本号,并将该版本号保存到数据中。在Java中,可以使用UPDATE ... SET语句来实现这个功能,例如: ```java try { Connection conn = pool.getConnection(); conn.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ); conn.setAutoCommit(false); int newTrxId = getNextTrxId(); String sql = "UPDATE table SET value = ?, trx_id = ? WHERE id = ?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, value); ps.setInt(2, newTrxId); ps.setInt(3, id); int rows = ps.executeUpdate(); if (rows == 1) { // 更新成功 } conn.commit(); } catch (Exception e) { // 异常处理 } ``` 6. 当事务提交时,需要将该事务的版本号保存到事务ID列表中。在Java中,可以使用一个列表来保存事务ID,例如: ```java public class TxnIdList { private List<TxnId> txnIds = new ArrayList<>(); // 添加事务ID public void addTxnId(TxnId txnId) { txnIds.add(txnId); } // 删除事务ID public void removeTxnId(TxnId txnId) { txnIds.remove(txnId); } // 判断事务是否已提交 public boolean isCommitted(TxnId txnId) { for (TxnId id : txnIds) { if (id.getTrxId() == txnId.getTrxId() && id.getRollPointer() != txnId.getRollPointer()) { return true; } } return false; } } ``` 7. 当事务回滚时,需要根据回滚指针来回滚数据。在Java中,可以使用ROLLBACK语句来回滚事务,例如: ```java try { Connection conn = pool.getConnection(); conn.rollback(); } catch (Exception e) { // 异常处理 } ``` 这样,就可以在Java中实现MVCC机制了。当然,这里只是一个简单的示例,实际上还有很多细节需要考虑,比如事务的隔离级别、事务的提交和回滚、事务ID的生成等等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值