notas de fondo de MySQL (17) - bloqueo bloqueo optimista y pesimista

1. ¿Qué es el bloqueo optimista, pesimista de bloqueo

  1. medios de bloqueo optimista que cuando se leen los datos, el valor por defecto no se cree que este hilo para modificar los datos (en la clase atómica de Java Atómica está diseñado, como CAS), pero sólo cuando se presente ante el juez para determinar si, en línea con las expectativas o no la necesidad de girar y leer de nuevo.Adecuado para la lectura y escritura de un menor número de ocasiones.
  2. medios de bloqueo pesimista de que cuando se leen los datos creo que debe haber otros hilos modifican datos, añadido directamente mutex, hasta su procesamiento completo de los datos después de la liberación de la cerradura (Java es pesimista en bloqueo sincronizado),Adecuado para escribir una vez leído muchas menos ocasiones.

Los dos .MySQL bloqueo optimista y pesimista de bloqueo

  1. DDL
CREATE TABLE goods (
  id int(20) NOT NULL AUTO_INCREMENT,
  name varchar(100) DEFAULT NULL,
  stock int(20) DEFAULT NULL,
  PRIMARY KEY (id),
  UNIQUE KEY idx_name (name) USING BTREE
) ENGINE=InnoDB 
  1. DML
INSERT INTO goods VALUES (1, "MacBookPro2015", 1000);
INSERT INTO goods VALUES (2, "MacBookPro2016", 1000);
INSERT INTO goods VALUES (3, "MacBookPro2017", 1000);
INSERT INTO goods VALUES (4, "MacBookPro2018", 1000);
INSERT INTO goods VALUES (5, "MacBookPro2019", 1000);

1. bloqueo pesimista

1. mutex actualización -por

En primer lugar hay que decir es mutex, palabras clave Sincronizar similares a Java, a su uso

select ... for update

Lo cual, mutex mutex línea después de la investigación de la fila está bloqueada sólo cuando la rosca de bloqueo ha presentado la transacción, se suspenderán, otros hilos antes de que esto no pase for updateo lock in share modevaya a adquirir el bloqueo, seguridad de los datos está asegurada bajo un estricto concurrencia para un gran rendimiento de los requisitos de seguridad de la situación, pero reducirá en gran medida la concurrencia. Así, mutex más convertirse en un bloqueo de escritura.

  1. 1 hilo
mysql> begin; // 0.开启事务
mysql> select * from goods where id = 1 for update; // 1.使用互斥锁
+----+----------------+-------+
| id | name           | stock |
+----+----------------+-------+
|  1 | MacBookPro2015 |  1000 |
+----+----------------+-------+
1 row in set (0.00 sec)

mysql> update goods set stock = stock - 1 where id = 1; // 2.减少库存
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit; // 4.提交事务
Query OK, 0 rows affected (0.01 sec)
  1. rosca 2
mysql> select * from goods where id = 1; // 3.不获取互斥锁进行查询,查询出来的结果是错的
+----+----------------+-------+
| id | name           | stock |
+----+----------------+-------+
|  1 | MacBookPro2015 |  1000 |
+----+----------------+-------+
1 row in set (0.00 sec)

mysql> select * from goods where id = 1 for update; // 3.使用互斥锁查询,获取不到互斥锁,阻塞
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> select * from goods where id = 1 lock in share mode;// 3.使用共享锁查询,获取不到共享锁,阻塞
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> select * from goods where id = 1 for update; // 5.在线程1提交事务释放互斥锁后可使用互斥锁查询
+----+----------------+-------+
| id | name           | stock |
+----+----------------+-------+
|  1 | MacBookPro2015 |   999 |
+----+----------------+-------+

Otros casos, como actualizar, eliminar, etc., son el mismo, después de usar un mutex, solamente esperar a su lanzamiento antes de que puedan llegar a y ejecutar

2. Compartido -lock bloqueo en modo compartido

uso:

select...lock in share mode

También pertenece a un bloqueo pesimista bloqueo compartido, pero es diferente de bloqueo de exclusión mutua que:Antes de bloquear la fila no se ha modificado, otros hilos también se pueden utilizar para obtener el bloqueo compartido y leer los datos, pero no pueden ser modificados; después de bloquear la fila es modificado, otro hilo no puede adquirir el bloqueo compartido para leer los datos, Compartir actualizado para bloquear mutex. Por lo tanto, un bloqueo compartido también se conoce como un bloqueo de lectura.

  1. 1 hilo
mysql> begin;    // 0.开启事务
Query OK, 0 rows affected (0.00 sec)

mysql> select * from goods where id = 1 lock in share mode; // 1.获取共享锁
+----+----------------+-------+
| id | name           | stock |
+----+----------------+-------+
|  1 | MacBookPro2015 |   999 |
+----+----------------+-------+
1 row in set (0.00 sec)

mysql> update goods set stock = stock - 1 where id = 1;  // 3.更新库存
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec) // 5.提交事务
  1. rosca 2
mysql> select * from goods where id = 1; // 2. 普通查询,不加锁,可以查询
+----+----------------+-------+
| id | name           | stock |
+----+----------------+-------+
|  1 | MacBookPro2015 |   999 |
+----+----------------+-------+
1 row in set (0.00 sec)

mysql> select * from goods where id = 1 for update; // 2.无法获取互斥锁
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> select * from goods where id = 1 lock in share mode; // 2. 可以获取共享锁进行查询
+----+----------------+-------+
| id | name           | stock |
+----+----------------+-------+
|  1 | MacBookPro2015 |   999 |
+----+----------------+-------+
1 row in set (0.00 sec)

mysql> update goods set stock = stock - 1 where id = 2; // 2.无法获取共享锁进行修改
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted

mysql> select * from goods where id = 1 lock in share mode; // 4.无法获取共享锁,无法查询,因为线程1已经修改了库存,此时升级为互斥锁
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> select * from goods where id = 1 lock in share mode; // 6.线程1释放共享锁,线程2获取共享锁
+----+----------------+-------+
| id | name           | stock |
+----+----------------+-------+
|  1 | MacBookPro2015 |   998 |
+----+----------------+-------+
1 row in set (2.30 sec)
3.Update, insertar, eliminar bloqueo de registro automático

Lo anterior dos casos son los casos de los comandos SQL, bloqueo manual, en INNODB, update, insert, deleteestas tres afirmaciones es la exclusión mutua predeterminada, si está utilizando update...for updateo update...lock in share modese error:

mysql> update goods set stock = stock - 1 for update;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'for update' at line 1
mysql> update goods set stock = stock - 1 lock in share mode;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'lock in share mode' at line 1

Prueba simple:

  1. 1 hilo
mysql> begin;
Query OK, 0 rows affected (0.01 sec)

mysql> update goods set stock = stock - 1 where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
  1. rosca 2
mysql> select * from goods where id = 1 for update;
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted
mysql> select * from goods where id = 1 lock in share mode;
^C^C -- query aborted
ERROR 1317 (70100): Query execution was interrupted

2. Bloqueo optimista - control de versiones

Para aplicar el bloqueo optimista en MySQL, por lo general mediante la adición de un campo de número de versión de fila para lograr, cuando operamos, primero revisar el número de versión de los datos, cuando terminamos la modificación de los datos, y luego determinar la actualización de la versión de nuevo número de versión a inconsistencias evitar. Para modificar con éxito el número mínimo de la versión de los datos. Si el número de versión es diferente de descrito anteriormente se modifica, la operación anterior se repite para, (En InnoDB también utilizar este mecanismo para resolver el problema de las circunstancias RR de lectura fantasma, ser llamado Multi Versión MVCC control de concurrencia). Golang utilizar la siguiente implementación sencilla de la lógica de bloqueo optimista.

mysql> alter table goods add version int(20)  not null default 0;//添加版本号字段
type Goods struct {
	Id int `gorm:"column:id"`
	Name string `gorm:"column:name"`
	Stock int `gorm:"column:stock"`
	Version int `gorm:"column:version"`
}

func main() {
	db := getDb()
	var good Goods
	db.Raw("select * from goods where id = 1").Scan(&good)
	fmt.Println(good)
	for good.Id != 0 && good.Stock > 0 {
		// 获取到版本号
		version := good.Version
		// 减库存并增加版本号,以当前版本号为条件之一
		exec := db.Exec("update goods set stock = stock - 1, version = ? where id = 1 and version = ?", version+1, version)
		if exec.RowsAffected != 0 {
			fmt.Println("更新成功")
			break
		}
		fmt.Println("更新失败,重试")
	}
	db.Raw("select * from goods where id = 1").Scan(&good)
	fmt.Println(good)
}

resultados:

{1 MacBookPro2015 997 3}
更新成功
{1 MacBookPro2015 996 4}
Publicados 309 artículos originales · ganado elogios 205 · Vistas de 300.000 +

Supongo que te gusta

Origin blog.csdn.net/pbrlovejava/article/details/103862808
Recomendado
Clasificación