日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

ci mysql高并发_高并发访问mysql时的问题(一):库存超减

發布時間:2023/12/4 数据库 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ci mysql高并发_高并发访问mysql时的问题(一):库存超减 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

標簽:

如果在對某行記錄的更新時不采取任何防范措施,在多線程訪問時,就容易出現庫存為負數的錯誤.

以下用php、mysql,apache ab工具舉例說明:

mysql表結構

CREATE TABLE`yxt_test_concurrence` (

`id`int(11) NOT NULLAUTO_INCREMENT,

`value`int(11) NOT NULL COMMENT ‘庫存‘,PRIMARY KEY(`id`)

) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT=‘庫存表‘;

CREATE TABLE`yxt_test_pv` (

`id`int(10) unsigned NOT NULLAUTO_INCREMENT,

`val`int(255) DEFAULT NULL COMMENT ‘該線程讀取到的庫存數量‘,PRIMARY KEY(`id`)

) ENGINE=MyISAM AUTO_INCREMENT=351 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT=‘訪問記錄表,每次訪問都增加一條記錄,并記錄此次訪問時的庫存數‘;

在庫存表中存入模擬庫存500個.

在此,為方便,php采用TP框架:

public functiontc(){$this->tc = M("test_concurrence");//模擬商品的剩余數量

$this->pv = M("test_pv");//模擬訪問次數

$res=$this->tc->field(‘value‘)->find(1);//查到的剩余數量

$value=$res[‘value‘];if($value>0){//如果大于0,則進行下面的邏輯

$this->pv->data(array(‘val‘=>$value))->add();//這個是用來記錄訪問的次數,并記錄此次訪問時的庫存數

M()->execute("UPDATE `yxt_test_concurrence` SET `value`=`value` - 1 WHERE `id` = 1");//商品數量減1}

}

使用ab工具模擬并發訪問:

C:\Users\chenhui>ab -c 50 -n 500 http://study.com/course/Course/tc/

This is ApacheBench, Version 2.3Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/

Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking studyyxtcmf.com (be patient)

Completed 100 requests

Completed 200 requests

Completed 300 requests

Completed 400 requests

Completed 500 requests

Finished 500 requests

Server Software: Apache/2.4.9

Server Hostname: studyyxtcmf.com

Server Port: 80

Document Path: /course/Course/tc/

Document Length: 25786 bytes

Concurrency Level: 50

Time taken for tests: 60.035 seconds

Complete requests: 500

Failed requests: 450

(Connect: 0, Receive: 0, Length: 450, Exceptions: 0)

Total transferred: 12973630 bytes

HTML transferred: 12785130 bytes

Requests per second: 8.33 [#/sec] (mean)

Time per request: 6003.543 [ms] (mean)

Time per request: 120.071 [ms] (mean, across all concurrent requests)

Transfer rate: 211.03 [Kbytes/sec] received

Connection Times (ms)

min mean[+/-sd] median max

Connect: 0 1 2.1 1 34

Processing: 781 5915 1578.6 5996 12272

Waiting: 765 5901 1581.8 5983 12261

Total: 783 5916 1578.4 5997 12272

Percentage of the requests served within a certain time (ms)

50% 5997

66% 6385

75% 6707

80% 6850

90% 7387

95% 8402

98% 9734

99% 10300

100% 12272 (longest request)

查看數據庫記錄:

SELECT * fromyxt_test_pv;--截取一段記錄(左邊是第幾次訪問,右側是當次訪問看到的庫存)

| 338 | 164 |

| 339 | 164 |

| 340 | 163 |

| 341 | 162 |

| 342 | 162 |

| 343 | 162 |

| 344 | 162 |

| 345 | 157 |

| 346 | 156 |

| 347 | 156 |

| 348 | 153 |

| 349 | 155 |

| 350 | 151 |

可以發現在341-343次讀取的庫存數量是一樣的,在庫存還很多的情況時,并不會出現問題:因為程序中減庫存的邏輯,是當前庫存量減去1.但是庫存不多的時候,就很可能出現問題,比如庫存只有一個了,而此時有多個線程查詢到此時還有一個庫存,因為1>0滿足條件,所以庫存減1,多個線程都對當前庫存減1,最后就多減了庫存,出現負數,這是不允許的.

所以一定要采取措施.

我認為,總的原則是:對于某一個時刻的庫存,只允許一個會話去修改.要滿足此條件.有兩種選擇:

1.對于某一個時刻的庫存,只允許一個會話去讀取(鎖機制).待鎖被釋放后,其他會話才可以讀取庫存.

2.對于某一個時刻的庫存,設定版本(即增加一個版本字段,用于比較.我對版本的理解是刻個記號),更新庫存時要判斷版本是否發生變化,若沒發生變化,則更新庫存的同時,更新版本號.若更新庫存時發現版本發生變化了,那一定是有別的線程早已對庫存修改,此情況下就放棄修改.

選擇1.使用mysql的鎖機制.(悲觀鎖)

public functiontc(){$this->tc = M("test_concurrence");//模擬商品的剩余數量

$this->pv = M("test_pv");//模擬訪問次數

//對表加鎖,注意,如果加鎖過程中要操作多個表,要對這幾個表都加鎖,否則會報錯

//mysql> lock table yxt_test_concurrence read;--只鎖了一張表

//Query OK, 0 rows affected (0.00 sec)

//mysql> SELECT * from yxt_test_pv;--讀取沒有被鎖的表

//ERROR 1100 (HY000): Table ‘yxt_test_pv‘ was not locked with LOCK TABLES--報錯,提示查詢的表沒有被鎖住

M()->execute("lock tables yxt_test_concurrence write,yxt_test_pv write;");$res=$this->tc->field(‘value‘)->find(1);//查到的剩余數量

$value=$res[‘value‘];if($value>0){//如果大于0,則進行下面的邏輯

$this->pv->data(array(‘val‘=>$value))->add();//這個是用來記錄訪問的次數

M()->execute("UPDATE `yxt_test_concurrence` SET `value`=`value` - 1 WHERE `id` = 1");//商品數量減1

}//解鎖

M()->execute("unlock tables");

}

采用鎖機制,可以嚴格控制庫存數量的變化,但是采用鎖會增加數據庫的開銷.

選擇2.版本控制(樂觀鎖)

樂觀鎖,是假定事務之間是互不干擾的,事務在訪問數據的時候,并不會獲取鎖,但是,在提交前,每個事務都要確保其他事務并沒有修改他讀取到的數據.如果在更新數據時發現其他事務已經修改了數據,則回滾提交.樂觀鎖經常用于"低爭用數據結構"的場景中.當沖突特別少的時候,事務可以在完成時,不需要管理鎖的開銷及等待其他事務釋放鎖,這可以帶來更高的吞吐率.但是,如果對于數據的爭用特別頻繁,重新開啟一個新事務的開銷會明顯影響性能.

通常認為,其他并發控制方法,在此情況下會有更好的表現,然而,基于悲觀鎖的方法,會導致較差的性能.因為即使死鎖可以避免,"鎖"仍會極大的影響并發性能.(我想應該是因為會話被阻塞,從而導致只能串行訪問數據庫)

以上定義摘自wiki:https://en.wikipedia.org/wiki/Optimistic_concurrency_control

這種情況下,如果并發訪問,則修改失敗的幾率會較高,

舉例:在熱銷產品場景下則容易出現購買失敗的情況.這對用戶的體驗是不好的.因為這意味著又要重新嘗試一次.

小結:應該采取哪一種鎖,應根據實際場景來權衡利弊,如果更新的很頻繁,那應該使用悲觀鎖.此刻需要考慮的問題是:如何解決并發問題.如果很少更新,則使用樂觀鎖更為方便省事.

標簽:

總結

以上是生活随笔為你收集整理的ci mysql高并发_高并发访问mysql时的问题(一):库存超减的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。