Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

Masalah Lost Update dalam Transaksi Serentak

Masalah pembaruan yang hilang terjadi ketika 2 transaksi bersamaan mencoba membaca dan memperbarui data yang sama. Mari kita pahami ini dengan bantuan sebuah contoh.

Misalkan kita memiliki tabel bernama "Produk" yang menyimpan id, nama, dan ItemsinStock untuk suatu produk.

Ini digunakan sebagai bagian dari sistem online yang menampilkan jumlah item dalam stok untuk produk tertentu dan karenanya perlu diperbarui setiap kali penjualan produk tersebut dilakukan.

Tabelnya terlihat seperti ini:

Id

Nama

ItemsinStock

1

Laptop

12

Sekarang pertimbangkan skenario di mana pengguna datang dan memulai proses pembelian laptop. Ini akan memulai transaksi. Sebut saja transaksi ini, transaksi 1.

Pada saat yang sama pengguna lain masuk ke sistem dan memulai transaksi, sebut saja transaksi ini 2. Perhatikan gambar berikut.

Transaksi 1 membaca item dalam stok untuk laptop yaitu 12. Beberapa saat kemudian transaksi 2 membaca nilai ItemsinStock untuk laptop yang masih akan menjadi 12 saat ini. Transaksi 2 kemudian menjual tiga laptop, sesaat sebelum transaksi 1 menjual 2 item.

Transaksi 2 kemudian akan menyelesaikan eksekusinya terlebih dahulu dan memperbarui ItemsinStock ke 9 karena telah menjual tiga dari 12 laptop. Transaksi 1 melakukan sendiri. Sejak transaksi 1 menjual dua item, itemsinStock diperbarui menjadi 10.

Ini salah, angka yang benar adalah 12-3-2 =7

Contoh Kerja Masalah Pembaruan yang Hilang

Mari kita lihat masalah pembaruan yang hilang dalam tindakan di SQL Server. Seperti biasa, pertama, kita akan membuat tabel dan menambahkan beberapa data dummy ke dalamnya.

Seperti biasa, pastikan Anda telah dicadangkan dengan benar sebelum bermain dengan kode baru. Jika Anda tidak yakin, lihat artikel ini tentang pencadangan SQL Server.

Jalankan skrip berikut di server database Anda.

<span style="font-size: 14px;">CREATE DATABASE pos;

USE pos;

CREATE TABLE products
(
	Id INT PRIMARY KEY,
	Name VARCHAR(50) NOT NULL,
	ItemsinStock INT NOT NULL

)

INSERT into products

VALUES 
(1, 'Laptop', 12),
(2, 'Iphon', 15),
(3, 'Tablets', 10)</span>

Sekarang, buka dua contoh studio manajemen server SQL secara berdampingan. Kami akan menjalankan satu transaksi di setiap kasus ini.

Tambahkan skrip berikut ke instance pertama SSMS.

<span style="font-size: 14px;">USE pos;

-- Transaction 1

BEGIN TRAN

DECLARE @ItemsInStock INT

SELECT @ItemsInStock = ItemsInStock
FROM products WHERE Id = 1

WaitFor Delay '00:00:12'
SET @ItemsInStock = @ItemsInStock - 2

UPDATE products SET ItemsinStock = @ItemsInStock
WHERE Id = 1

Print @ItemsInStock
Commit Transaction</span>

Ini adalah skrip untuk transaksi 1. Di sini kita memulai transaksi dan mendeklarasikan variabel tipe integer “@ItemsInStock”. Nilai variabel ini diatur ke nilai kolom ItemsinStock untuk catatan dengan Id 1 dari tabel produk. Kemudian ditambahkan delay 12 detik agar transaksi 2 dapat menyelesaikan eksekusinya sebelum transaksi 1. Setelah delay, nilai variabel @ItemsInStock dikurangi 2 yang menandakan penjualan 2 produk.

Terakhir, nilai kolom ItemsinStock untuk catatan dengan Id 1 diperbarui dengan nilai variabel @ItemsInStock. Kami kemudian mencetak nilai variabel @ItemsInStock di layar dan melakukan transaksi.

Pada SSMS instance kedua, kita tambahkan script untuk transaksi 2 yaitu sebagai berikut:

<span style="font-size: 14px;">USE pos;

-- Transaction 2

BEGIN TRAN

DECLARE @ItemsInStock INT

SELECT @ItemsInStock = ItemsInStock
FROM products WHERE Id = 1

WaitFor Delay '00:00:3'
SET @ItemsInStock = @ItemsInStock - 3

UPDATE products SET ItemsinStock = @ItemsInStock
WHERE Id = 1

Print @ItemsInStock
Commit Transaction</span>

Script untuk transaksi 2 mirip dengan transaksi 1. Namun, di sini pada transaksi 2, penundaan hanya selama tiga detik dan penurunan nilai variabel @ItemsInStock adalah tiga, karena penjualan tiga item.

Sekarang, jalankan transaksi 1 dan kemudian transaksi 2. Anda akan melihat transaksi 2 menyelesaikan eksekusinya terlebih dahulu. Dan nilai yang dicetak untuk variabel @ItemsInStock akan menjadi 9. Setelah beberapa waktu, transaksi 1 juga akan menyelesaikan eksekusinya dan nilai yang dicetak untuk variabel @ItemsInStock akan menjadi 10.

Kedua nilai ini salah, nilai sebenarnya untuk kolom ItemsInStock untuk produk dengan Id 1 seharusnya 7.

CATATAN:

Penting untuk dicatat di sini bahwa masalah pembaruan yang hilang hanya terjadi dengan tingkat isolasi transaksi baca yang dikomit dan baca yang tidak dikomit. Dengan semua tingkat isolasi transaksi lainnya, masalah ini tidak terjadi.

Baca Tingkat Isolasi Transaksi Berulang

Mari perbarui tingkat isolasi untuk kedua transaksi agar dapat dibaca berulang dan lihat apakah masalah pembaruan yang hilang terjadi. Namun sebelum itu, jalankan pernyataan berikut untuk memperbarui nilai ItemsInStock kembali ke 12.

Update products SET ItemsinStock = 12

Script Untuk Transaksi 1

<span style="font-size: 14px;">USE pos;

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
-- Transaction 1

BEGIN TRAN
DECLARE @ItemsInStock INT

SELECT @ItemsInStock = ItemsInStock
FROM products WHERE Id = 1

WaitFor Delay '00:00:12'
SET @ItemsInStock = @ItemsInStock - 2

UPDATE products SET ItemsinStock = @ItemsInStock
WHERE Id = 1

Print @ItemsInStock
Commit Transaction</span>

Script Untuk Transaksi 2

<span style="font-size: 14px;">USE pos;

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
-- Transaction 2

BEGIN TRAN
DECLARE @ItemsInStock INT

SELECT @ItemsInStock = ItemsInStock
FROM products WHERE Id = 1

WaitFor Delay '00:00:3'
SET @ItemsInStock = @ItemsInStock - 3

UPDATE products SET ItemsinStock = @ItemsInStock
WHERE Id = 1

Print @ItemsInStock
Commit Transaction</span>

Di sini, di kedua transaksi, kami telah menetapkan tingkat isolasi ke pembacaan berulang.

Sekarang jalankan transaksi 1 dan segera jalankan transaksi 2. Tidak seperti kasus sebelumnya, transaksi 2 harus menunggu transaksi 1 untuk melakukan sendiri. Setelah itu terjadi error berikut untuk transaksi 2 :

Msg 1205, Level 13, State 51, Line 15

Transaksi (Process ID 55) menemui jalan buntu pada sumber daya kunci dengan proses lain dan telah dipilih sebagai korban kebuntuan. Jalankan kembali transaksi.

Kesalahan ini terjadi karena pembacaan berulang mengunci sumber daya yang sedang dibaca atau diperbarui oleh transaksi 1 dan itu membuat kebuntuan pada transaksi lain yang mencoba mengakses sumber daya yang sama.

Kesalahan mengatakan bahwa transaksi 2 memiliki kebuntuan pada sumber daya dengan proses lain dan bahwa transaksi ini telah diblokir oleh kebuntuan. Ini berarti bahwa transaksi lain diberikan akses ke sumber daya sementara transaksi ini diblokir dan tidak diberikan akses ke sumber daya.

Ia juga mengatakan untuk menjalankan kembali transaksi karena sumber dayanya gratis sekarang. Sekarang, jika Anda menjalankan transaksi 2 lagi, Anda akan melihat nilai stok barang yang benar yaitu 7. Ini karena transaksi 1 telah mengurangi nilai IteminStock sebesar 2, transaksi 2 selanjutnya mengurangi ini dengan 3, oleh karena itu 12 – (2+ 3) =7.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Opsi Penyesuaian Kinerja Database Azure SQL

  2. Menggabungkan File Data dengan Statistica, Bagian 2

  3. Bagaimana Rencana Paralel Memulai – Bagian 3

  4. Kesalahan menggunakan koneksi OLAP:Penyedia MSOLAP tidak terdaftar di mesin lokal...

  5. Unggah Dokumen ke Azure Data Lake dan Ekspor Data menggunakan SSIS