[MySQL] Baseado em MVCC e Read View, analise como os quatro níveis de isolamento de transações refletem seu isolamento em cenários de leitura e gravação.


Os alunos que precisam de servidores em nuvem e outros produtos em nuvem para aprender Linux podem migrar para / --> Tencent Cloud <-- / --> Alibaba Cloud <-- / --> Huawei Cloud <-- / site oficial, servidores em nuvem leves são baixo custo para 112 yuans/ano, e novos usuários podem desfrutar de descontos ultrabaixos em seu primeiro pedido.


 Índice

1. Três cenários de simultaneidade de banco de dados

2. MVCC para cenários de leitura e escrita 

1. 3 (4) registros de campos de coluna ocultos

2. desfazer log (desfazer log)

3. Simule o cenário MVCC

3.1 cenário de atualização

3.2 excluir cenário

3.3inserir

3.4selecionar cena

4. Visualização de leitura

5. A diferença entre RR e RC

5.1 A diferença entre a leitura atual e a leitura do instantâneo no nível RR

Exemplo 1: instantâneo raiz lido antes da modificação jly

Exemplo 2: Leitura instantânea da raiz após modificação jly

5.2 Diferentes métodos de processamento do MySQL para os quatro níveis de isolamento 

3. Escreva a cena


1. Três cenários de simultaneidade de banco de dados

Leitura-leitura: sem problemas e sem necessidade de controle de simultaneidade

Leitura-gravação: Existem problemas de segurança de thread, que podem causar problemas de isolamento de transação e podem encontrar leituras sujas, leituras fantasmas e leituras não repetíveis.

Gravação-gravação: há problemas de segurança de thread e pode haver problemas de perda de atualização, como o primeiro tipo de perda de atualização, o segundo tipo de perda de atualização

2. MVCC para cenários de leitura e escrita 

O Multiversion Concurrency Control (MVCC) é um controle de simultaneidade sem bloqueio usado para resolver conflitos de leitura e gravação .

A transação recebe um ID de transação que cresce em uma direção e uma versão é salva para cada modificação. A versão é associada ao ID da transação. A operação de leitura lê apenas o instantâneo do banco de dados antes do início da transação. Portanto, o MVCC pode resolver os seguintes problemas do banco de dados:

Ao ler e gravar o banco de dados simultaneamente, isso pode ser feito sem bloquear a operação de gravação durante a operação de leitura, e a operação de gravação não precisa bloquear a operação de leitura, o que melhora o desempenho da leitura e gravação simultâneas, e ao mesmo tempo tempo resolve problemas de isolamento de transações, como leituras sujas, leituras fantasmas e leituras não repetíveis, mas não resolve o problema de atualizações perdidas.

1. 3 (4) registros de campos de coluna ocultos

Ao criar uma tabela, o MySQL criará 3 campos de colunas ocultas de registro além das colunas exigidas pelo usuário.

DB_TRX_ID: 6 bytes, esta coluna registra o ID da transação (modificação/inserção) da última modificação de cada linha.

DB_ROLL_PTR: 7 bytes, ponteiro de rollback, apontando para a versão anterior deste registro (entendido simplesmente como apontando para a versão histórica, esses dados geralmente estão no log de desfazer)

DB_ROW_ID: 6 bytes, ID de incremento automático implícito (chave primária oculta), se a tabela de dados não tiver uma chave primária, o InnoDB irá gerar automaticamente um índice clusterizado com DB_ROW_ID

O quarto campo de coluna oculto: Na verdade, existe um sinalizador de campo oculto que identifica se a linha de dados foi excluída.

Por exemplo, ao criar e inserir um dado, a estrutura real da tabela deve ser assim:

nome

idade

DB_TRX_ID

DB_ROLL_PTR

DB_ROW_ID

Zhang San

20

Crie o ID da transação

nulo

1 (chave primária implícita)

2. desfazer log (desfazer log)

O MySQL é executado na memória como um processo daemon. Undo log é um buffer de memória no MySQL para salvar dados de log.

3. Simule o cenário MVCC

3.1 cenário de atualização

Existe um ID de transação 10. Atualize a tabela de informações acima e altere o nome de Zhang San para Li Si:

1. Como deseja modificá-lo, primeiro você deve adicionar um bloqueio de linha ao registro.

2. Antes da modificação, copie os dados redirecionados para o log de desfazer (copie durante a gravação, os dados originais estão na tabela, os dados copiados estão no log de desfazer, assumindo que o endereço dos dados copiados seja 0XAA)

3. Ao modificar os dados originais, modifique o campo oculto DB_TRX_ID para 10 e o ponteiro de rollback DB_ROLL_PTR para 0XAAAAAAAAA.

4. A transação 10commit é enviada e o bloqueio de linha é liberado.

nome

idade

DB_TRX_ID

DB_ROLL_PTR

DB_ROW_ID

John Doe

20

10

0XAAAAAAAA

1 (chave primária implícita)

Neste momento, há outra transação 11, que precisa atualizar os registros da tabela de informações e alterar a idade da linha de Li Si para 30:

1. Como deseja modificá-lo, primeiro você deve adicionar um bloqueio de linha ao registro.

2. Da mesma forma, copie a linha correspondente na tabela atual para desfazer o log, assumindo o endereço 0XBBBBBBBB

3. Ao modificar os dados originais, modifique o campo oculto DB_TRX_ID para 10 e o ponteiro de rollback DB_ROLL_PTR para 0XAAAAAAAAA.

nome

idade

DB_TRX_ID

DB_ROLL_PTR

DB_ROW_ID

John Doe

30

11

0XBBBBBBBB

1 (chave primária implícita)

Cada versão no log de desfazer é chamada de instantâneo. Além da cadeia de versões, você também pode registrar o SQL reverso para se preparar para a reversão de dados (como excluir dados e o log pode salvar dados de inserção)

3.2 excluir cenário

Excluir dados não significa limpá-los, apenas defina o sinalizador oculto para excluir. Versões também podem ser formadas.

3.3inserir

Inserir é uma inserção. Você só precisa registrar suas instruções de exclusão correspondentes no log de desfazer ao inserir. Ao reverter, você só precisa executar essas instruções de exclusão. Se a transação atual for confirmada, o log de desfazer excluirá os dados de backup. (Pode haver outras transações ainda acessando atualização e exclusão, e os dados de reversão do log de desfazer não serão excluídos imediatamente após a confirmação)

3.4selecionar cena

No nível RR do MySQL, a operação de gravação de uma transação não afeta a operação de leitura de outra transação. Adições, exclusões e modificações são modificações nos dados mais recentes, mas a leitura pode exigir a leitura de versões históricas.

Leitura atual: lê o registro mais recente, que é a leitura atual. Adições, exclusões e modificações são todas chamadas de leitura atual, e selecionar também pode ser leitura atual, como selecionar bloqueio no modo de compartilhamento (bloqueio compartilhado), selecionar para atualização

Leitura do instantâneo: Leia a versão histórica. As leituras de instantâneo não estão bloqueadas.

Quando várias transações são adicionadas, excluídas e modificadas ao mesmo tempo, é a leitura atual e precisa ser bloqueada. Se a seleção também estiver bloqueada, o nível de isolamento é a serialização. Se a seleção for uma leitura de instantâneo, ela não afetará a leitura atual de adições, exclusões e modificações, portanto, nenhum bloqueio é necessário e a execução paralela é altamente eficiente. O nível de isolamento da transação determina se os dados históricos de leitura selecionados são leitura atual ou leitura de instantâneo. (Se a visualização de leitura está atualizada)

Então, como garantir que transações diferentes vejam conteúdos diferentes? A transação que vem primeiro deve ver as modificações feitas pelas transações subsequentes? Read View realiza julgamento de visibilidade.

4. Visualização de leitura

Read View é gerado pelo MySQL quando uma transação realiza a leitura do instantâneo pela primeira vez e registra e mantém o ID da transação atualmente ativa no sistema. Read View é uma classe no código-fonte do MySQL. Ela é essencialmente usada com MVCC para determinar quais snapshots posso ver e quais snapshots não posso ver.

Quando uma transação realiza uma leitura selecionada de instantâneo, o MySQL criará um novo objeto para ela e usará suas condições internas para determinar qual versão dos dados a transação atual pode ver. Os dados visíveis podem ser os dados mais recentes ou os dados mais recentes. Esta linha registra uma determinada versão dos dados no log de desfazer, que é determinada pelo nível de isolamento.

A seguir está uma estrutura simplificada do ReadView:

class ReadView {
    // 省略...
    private:
    /** 高水位,大于等于这个ID的事务均不可见*/
    trx_id_t m_low_limit_id
    /** 低水位:小于这个ID的事务均可见 */
    trx_id_t m_up_limit_id;
    /** 创建该 Read View 的事务ID*/
    trx_id_t m_creator_trx_id;
    /** 创建视图时的活跃事务id列表*/
    ids_t m_ids;//ids_t集合类型 
    /** 配合purge,标识该视图不需要小于m_low_limit_no的UNDO LOG,
    * 如果其他视图也不需要,则可以删除小于m_low_limit_no的UNDO LOG*/
    trx_id_t m_low_limit_no;
    /** 标记视图是否被关闭*/
    bool m_closed;
    // 省略...
};
m_ids; //一张列表,用来维护Read View生成时刻,系统正活跃的事务ID
up_limit_id; //记录m_ids列表中事务ID最小的ID
low_limit_id; //ReadView生成时刻系统尚未分配的下一个事务ID,也就是目前已出现过的事务ID的最大值+1
creator_trx_id //创建该ReadView的事务ID

Então, quais dados podem ser lidos pelas transações e quais dados não podem ser vistos pelas transações? Veja abaixo:

Para resumir: por exemplo, sou um júnior. Posso ver os dados de procura de emprego dos alunos do último ano que entraram na escola antes de mim, mas os idosos não podem ver os dados de procura de emprego dos meus que entraram na escola mais tarde. Da mesma forma, ao tirar um instantâneo, posso ver:

Transações enviadas:

1. creator_trx_id (o ID da transação que criou o instantâneo) == DB_TRX_ID (o ID da transação que modificou pela última vez a linha no log de desfazer)

2. DB_TRX_ID (o ID da transação da linha que foi modificada pela última vez no log de desfazer) <up_limit_id (o ID com o menor ID de transação na lista m_ids que forma o instantâneo)

Transações em m_ids (IDs de transações ativas) quando o snapshot foi criado:

1. Os IDs de transação no instantâneo não são necessariamente consecutivos. O intervalo de IDs de transação no instantâneo é up_limit_id<=ID<low_limit_id. Se DB_TRX_ID (o ID da transação da modificação mais recente na linha no log de desfazer) estiver neste intervalo, mas não houver tal ID na lista m_ids da tabela de instantâneo, significa que a transação foi confirmada e pode ser visto no instantâneo atual. Se a lista m_ids tiver Este ID indica que a transação com este ID no instantâneo atual ainda está ativa e não pode ser vista.

Não consigo ver:

Novidades após a criação do snapshot:

1. DB_TRX_ID (o ID da transação da última linha modificada no log de desfazer) >= low_limit_id (o próximo ID que não foi atribuído pelo sistema quando o instantâneo é gerado)

Se for constatado que a versão atual não deve ser visualizada, o próximo passo é percorrer a próxima versão até que as condições sejam atendidas.

nome

idade

DB_TRX_ID

DB_ROLL_PTR

DB_ROW_ID

Zhang San

28

Crie o ID da transação

nulo

1 (chave primária implícita)

A cadeia de versões no log de desfazer neste momento:

Quando a transação 2 executa a leitura do instantâneo na linha alterada, ela percorre os instantâneos no log de desfazer para determinar qual versão do instantâneo devo ler ao ler o instantâneo da linha desta vez.

5. A diferença entre RR e RC

5.1 A diferença entre a leitura atual e a leitura do instantâneo no nível RR

Preparação:

--将全局隔离级别设置为可重复读(需重启)
mysql> set global transaction isolation level REPEATABLE READ;
Query OK, 0 rows affected (0.00 sec)
--创建一张表
mysql> create table if not exists account(
    -> id int primary key,
    -> age int not null,
    -> name varchar(20) not null
    -> )ENGINE=InnoDB DEFAULT CHARSET=UTF8;
Query OK, 0 rows affected (0.26 sec)
--插入一条数据
mysql> insert into account values (1,18,'张三');
Query OK, 1 row affected (0.04 sec)
Exemplo 1: instantâneo raiz lido antes da modificação jly

Usuário: jly

--1、启动事务
mysql> begin;
Query OK, 0 rows affected (0.01 sec)
--2、进行快照读
mysql> select* from account;
+----+-----+--------+
| id | age | name   |
+----+-----+--------+
|  1 |  18 | 张三   |
+----+-----+--------+
1 row in set (0.00 sec)
--3、更新数据,修改id为1的字段的年龄为20
mysql> update account set age=20 where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
--4、对事务进行提交
mysql> commit;
Query OK, 0 rows affected (0.04 sec)

Usuário: raiz

--当上方用户执行完第一步时,root同时启动事务
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
--当上方用户执行完第二步时,root同时进行快照读,读取的结果一样
mysql> select* from account;
+----+-----+--------+
| id | age | name   |
+----+-----+--------+
|  1 |  18 | 张三   |
+----+-----+--------+
1 row in set (0.01 sec)
--当上方用户执行完第三步时,root进行快照读,发现年龄的修改并没有被读到
mysql> select* from account;
+----+-----+--------+
| id | age | name   |
+----+-----+--------+
|  1 |  18 | 张三   |
+----+-----+--------+
1 row in set (0.00 sec)
--当上方用户执行完第四步提交事务时,root再次进行快照读,发现年龄的修改还是没有被读到
mysql> select* from account;
+----+-----+--------+
| id | age | name   |
+----+-----+--------+
|  1 |  18 | 张三   |
+----+-----+--------+
1 row in set (0.00 sec)
--但是此时root使用当前读,使能够读到年龄的修改的
mysql> select* from account lock in share mode;
+----+-----+--------+
| id | age | name   |
+----+-----+--------+
|  1 |  20 | 张三   |
+----+-----+--------+
1 row in set (0.01 sec)
Exemplo 2: Leitura instantânea da raiz após modificação jly

Usuário: jly

--1、启动事务
mysql> begin;
Query OK, 0 rows affected (0.01 sec)
--2、进行快照读
mysql> select* from account;
+----+-----+--------+
| id | age | name   |
+----+-----+--------+
|  1 |  20 | 张三   |
+----+-----+--------+
1 row in set (0.00 sec)
--3、更新数据,修改id为1的字段的年龄为30
mysql> update account set age=30 where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
--4、提交事务
mysql> commit;
Query OK, 0 rows affected (0.03 sec)

Usuário: raiz

--1、同时启动事务
mysql> begin;
Query OK, 0 rows affected (0.01 sec)
--当上方用户执行完第四步提交事务时,root进行快照读,发现读到的数据是被修改过的
mysql> select* from account;
+----+-----+--------+
| id | age | name   |
+----+-----+--------+
|  1 |  30 | 张三   |
+----+-----+--------+
1 row in set (0.00 sec)

Através do Exemplo 1, podemos descobrir que: antes de jly ser enviado, o root select lê os dados antes da modificação;

Através do Exemplo 2, podemos descobrir que após a seleção da raiz ser enviada por jly, os dados modificados são lidos.

Isso ocorre porque quando uma transação é lida, o MySQL irá gerar um objeto de visualização de leitura. Como mencionado no capítulo que apresenta a visualização de leitura acima, a visualização de leitura é essencialmente uma classe usada para determinar quais instantâneos posso ver e quais instantâneos não posso ver. .

O momento de geração da visualização de leitura é diferente, o que afetará a visibilidade das transações.

5.2 Diferentes métodos de processamento do MySQL para os quatro níveis de isolamento 

A diferença no tempo de geração da Visualização de Leitura resulta em diferentes resultados de leitura de instantâneo sob diferentes níveis de isolamento de RC e RR:

Leitura repetível: A primeira leitura de instantâneo de um registro por uma transação no nível RR criará um instantâneo e um objeto Read View para registrar outras transações ativas no sistema atual; quando a leitura do instantâneo for chamada novamente mais tarde, o mesmo Read View ainda será usado, desde que a transação atual use a leitura do instantâneo antes de outras transações confirmarem as atualizações, as leituras subsequentes do instantâneo usarão a mesma visualização de leitura, portanto, as modificações subsequentes não serão visíveis; ou seja, no nível RR, quando a leitura do instantâneo gerar uma leitura View, a Visualização de Leitura registrará os instantâneos de todas as outras transações ativas neste momento, e as modificações dessas transações serão invisíveis para a transação atual. Somente modificações feitas por transações criadas antes da Visualização de Leitura podem ser vistas.

Confirmação de leitura: Em uma transação no nível RC, cada leitura de instantâneo gerará um novo instantâneo e uma visualização de leitura. É por isso que podemos ver as atualizações de outras transações no nível RC. É precisamente quando o RC lê um instantâneo que uma Visualização de Leitura é formada, então o RC tem um problema de leitura não repetível.

Leitura não confirmada: leitura atual. Não há isolamento.

Serialização: atualmente lendo, enquanto a adição, exclusão e modificação estão bloqueadas, a seleção também está bloqueada.

3. Escreva a cena

Entenda-o diretamente como a leitura atual.

Acho que você gosta

Origin blog.csdn.net/gfdxx/article/details/131524580
Recomendado
Clasificación