# `MVCC`
```15
~!@// Transaction 1:@!~
  Begin（start_ts = 100）
    < 1, Tom > ~!@->@!~ < 1, Jack >
    < 2, Andy > ~!@->@!~ < 2, Candy > 
  Commit;（commit_ts = 110）

~!@// Transaction 2:@!~
  Begin（start_ts = 115）
    < 1, Jack > ~!@->@!~ < 1, Tim >
    < 4, Tony > ~!@->@!~ < 4, Jerry > 
```

------------------------------------------------------------------------------
In the implementation of distributed transactions, we learned that if the data change is not committed, reading it will return an error. This means that the write operation blocks not only other write operations, but also read operations. While this is not a problem in theory, it can be inefficient in systems with high concurrency. If a particular row of data is being changed within a transaction, the operation on that row of data will become serial, which can decrease performance.

The solution to the problems described above is called multi-version concurrency control (MVCC for short).

In MVCC technology, every time you want to change or delete a certain data object, the database does not delete or modify the existing data object itself in place, but creates a new version of the data object. In this way, simultaneous reading operations can still read the old version of data, and write operations can be performed simultaneously. The benefit of this mode is that it allows reading operations to no longer be blocked; in fact, there is no need for a lock at all.

In the distributed transaction section, we have seen that for data modification or deletion, TiKV actually only performs additional operations (PUT, DELETE), rather than modifying or deleting the original data. So, in TiKV, we have the data for the previous version, so the next question is how to find the right version of the data.

Let's assume a scenario below:

There are currently two transactions, transaction 1 has been committed and its start_ts is 100 and commit_ts is 110; transaction 2 has started but has not been committed, and its start_ts is 105.

Transaction 1 workflow:
```
Begin（start_ts = 100）
< 1, Tom > -> < 1, Jack >
< 2, Andy > -> < 2, Candy > 
Commit;（commit_ts = 110）
```

Transaction 2 workflow:
```
Begin（start_ts = 115）
< 1, Jack > -> < 1, Tim >
< 4, Tony > -> < 4, Jerry >
```

At this point, when TSO is 120, we execute a query to query the values of key = 1, key = 2, and key = 4. According to common sense, if there is no MVCC mechanism, then key = 1 and key = 4 return errors or are blocked because they are in transaction 2, and key = 2 can query results, and value = Candy because transaction 1 is complete.

However, with the MVCC mechanism, we know that a read with a timestamp of 120 can not only read < 2, Candy >, but also < 1, Jack > and < 4, Tony >.