# Mvcc

+ 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 > 
```
------------------------------------------------------------
From the implement of distributed transaction, we understand that if a row of data is in the process of being transacted (uncommitted), then reading it will return an error. In other words, writes block not only writes, but also read. Although there is no problem in theory, for highly concurrent systems, if a row of data is in a transaction, the operation on that row of data will immediately become serial, which is very inefficient.

The solution method the above problem is called Multi-Version Concurrency Control (hereinafter referred to as MVCC). Databases like Oracle, MySQL, PostgreSQ, etc. also use this method. Let's take a look at how TiKV uses MVCC.

In MVCC technology, whenever you want to change or delete a 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, so that concurrent read operations can still read the old version of the data, and write operations can be performed at the same time. The advantage of this mode is that reads are no longer blocked, and in fact locks are not needed at all. 

In the distributed transaction section, we have seen that for data modify or deletion, TiKV actually only performs append operations (PUT, DELETE), instead of modify or deleting the original data. So, in TiKV we have previous versions of data, and the next question is how to find the right version data.

Let's assume a scenario:
There are currently 2 transactions, transaction 1 has been committed, its start_ts is 100, and its commit_ts is 110; transaction 2 has started, but has not been committed, and its start_ts is 105.

Transaction 1:
```
Begin（start_ts = 100）
 < 1，Tom > -> < 1，Jack >
< 2，Andy > -> < 2, Candy > 
Commit;（commit_ts = 110）
```
transaction 2:
```
Begin（start_ts = 105）
 < 1，Jack > -> < 1，Tim >
< 4，Tony > -> < 4, Jerry > 
```

At this point, when the STO is 120, we start 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 an error or are blocked because they are in transaction 2, and key = 2 can query the result, value = Candy, because transaction 1 has completed.

However, if there is an MVCC mechanism, we know that when the STO is 120, we can read not only the read < 2, Candy >, but also the < 1，Jack > and < 4，Tony >, because transaction 1 is not committed, we can read the value before the commit.