|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
% D" e! D: D1 b- qMysql中的锁语法:
4 ~7 x1 [$ s: h3 @8 {0 B4 VLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】7 V" M7 V( K: r) L! H0 c. H
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
* }- o9 ^, ]: e! C& xWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
. B$ R9 M7 v$ j. M) J注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :$ M6 [9 z* j1 q4 u/ P
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
2 A" n' G; d$ b3 Q% e5 j# x测试时,有个文件就行,叫什么名无所谓 总结:
. f4 e, w& t; f项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
8 c, i# Z) n0 d2 m3 K1. 高并发下单时,减库存量时要加锁
, m1 d& G# g6 J( M/ p: [4 q2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*& k- T, Q( }8 O
- 模拟秒杀活动-- 商品100件
# x4 J: n' g0 y; t: P7 p, D - CREATE TABLE ta, b5 t9 v" H* x9 h' y! Z
- (( O3 |# q$ g: a$ I c, m
- id int comment '模拟100件活动商品的数量'
. P* E# x+ H0 |$ U% D$ r, X/ a W - );5 \; u7 A- V- P* u6 z
- INSERT INTO ta VALUES(100);9 t* H7 u5 P. _. ]) z
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
! A; v2 n* ~/ L8 ^% t# f% M - */
) e0 A a5 @9 d% M+ j - ! t. l( Q' k0 H8 n/ n
- // 关闭错误报告. [; B5 \0 `3 ~: i) ^4 a3 h
- error_reporting(0); & Z0 [2 \ c* {
$ P h( Z0 F/ \( i, }2 ~- $dbhost = 'localhost:3306'; // mysql服务器主机地址8 s" [( K3 {) w# v4 J2 g
- $dbuser = 'root'; // mysql用户名
: m) d: q9 E" k5 {- {: ~ - $dbpass = 'root'; // mysql用户名密码
+ Z. z o5 ?2 b% }$ P0 V - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
* K/ N. ]5 @+ A" [' p$ a - if(! $conn )
# K- E8 a+ R! v( [2 T& p- S - {8 d3 [$ K/ O* ^" T9 U
- die('连接失败: ' . mysqli_error($conn));
! z2 t2 B* M. t* ~& o! c! a - }
7 O$ f& H! C1 K8 @: g6 B - // 设置编码,防止中文乱码
, @, K6 s% D" D - mysqli_query($conn , "set names utf8");
% h6 X" L' O5 d% T" k - mysqli_select_db( $conn, 'temp' ); 0 V. F/ ]$ y l K" r2 j
- + z0 ]9 c/ R( ]' R* P
- # mysql 锁 " V, S( p2 N3 o/ E4 s: P. E
- mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
1 j6 |. z* D; {! S- Q H9 d - $rs = mysqli_query($conn , 'SELECT id FROM a');
" V6 u7 Y. X; M1 s0 x - $id = mysqli_result($rs, 0, 0); ( ?$ o, A) Y4 H4 R" c! Z) d3 w
- if($id > 0) 0 b4 ~5 }3 j! j o$ R: g- O
- {
! A7 ^' z: {# a$ d2 { - --$id; / r/ u, ]; `- X
- mysqli_query($conn , 'UPDATE a SET id='.$id); 7 z8 W. m6 _4 p, `
- }
( z6 Y" y. s6 ^7 F* [' U - - i q( i% f0 o; `1 y( i" Z, S- h
- # mysql 解锁 0 }9 V1 O1 i$ B. ]8 ?
- mysqli_query($conn , 'UNLOCK TABLES');' a1 T, c3 h4 ?/ q
- //查询解锁后的id值# b7 F/ g$ @: ^8 y
- // $res = mysqli_query($conn , 'SELECT id FROM ta');) U; \3 [- W: R2 a o3 }/ k0 P
- // while($row = mysqli_fetch_assoc($res))
5 j4 O* Z" c$ Z- m# c: ?7 v - // {
* U& j& k' p3 `; w6 x T - // $id = $row['id'];! O" ] Z0 g" K2 n
- // }
x" t' N3 x4 Z' j( t - // echo $id;
复制代码
% V* d. y$ q" V. b" H+ f" k" G+ x2 f
, r6 y2 X7 E2 U' V8 f7 ]" P# Z$ \
PHP文件锁示例: - /*
" D% I( j3 {$ v0 e2 q" [6 y' P - 模拟秒杀活动-- 商品100件
" _$ m8 O& [! C. c! z - CREATE TABLE ta. h* Q5 u$ @# Z' a
- (
+ m7 W7 Y/ z. P1 K" h - id int comment '模拟100件活动商品的数量': p3 z" V; _: q& q! Y
- );8 R" V. W. [% q! ^
- INSERT INTO ta VALUES(100);
' x& d% n% S- D8 J) F2 Q - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件" g8 H) v: y! u4 k. [' U" ^6 }
- */
I# X9 Y( t' U" O* Y - $ O! m7 V* i# Q4 b
- // 关闭错误报告
1 G! o0 ?: u4 s0 Q' q - error_reporting(0); 6 W3 ^6 o: q, u. ]9 D- s
5 E8 K- h0 L' e1 q7 p9 t. {- $dbhost = 'localhost:3306'; // mysql服务器主机地址* e* V( B/ A4 {% G: Z9 U& D
- $dbuser = 'root'; // mysql用户名2 l/ M9 t' e# b. P1 j
- $dbpass = 'root'; // mysql用户名密码
0 o4 Q( b) |! _& ]5 k; U - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
% g& z+ V/ g1 ~( N( R - if(! $conn )
# j, t0 A3 s( o# c0 O - {$ u+ y* b5 f% o; j, A7 {5 r+ {2 j
- die('连接失败: ' . mysqli_error($conn));7 x* u8 O; P2 ]. _9 d) {
- }& x& V; }# r% w1 ?6 r
- // 设置编码,防止中文乱码
, Z S L3 H3 l$ t - mysqli_query($conn , "set names utf8");; E* G$ A5 ?* g! o5 @- B# O, b9 b1 M
- mysqli_select_db( $conn, 'temp' ); 9 S {3 a" s7 ~ a8 r
- `* u$ T( |/ V% P8 S
- # php中的文件锁 2 v7 [( l7 s1 D0 H) `! K) I1 {
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
6 p9 U5 o$ M4 ~, c - flock($fp, LOCK_EX);// 排他锁
4 U+ F5 k# I P% t& A* x3 h
: z! h1 z8 V5 V& [ H$ R8 K- $retval = mysqli_query($conn ,'SELECT id FROM ta'); - O1 U. F1 a! E# R: N8 G0 ] t& w8 u
- while($row = mysqli_fetch_assoc($retval))
3 \* ^9 t* _: }* X9 [ - { u+ O5 U- v7 \' f- f. g( c0 n
- $id = $row['id'];
' p I* m: t- u% H4 `- ?, b9 q5 U - }
* ^7 t- z, r3 Y4 C -
9 G/ I) N& b3 i5 q3 b+ m - if($id > 0)
+ Z. ]4 }/ {1 n% |# \; D: k0 }- E - {
+ L1 @/ |- ?+ p1 G; d6 Q! w2 r - --$id;
, V- q1 o7 _0 q4 A7 c4 V - mysqli_query($conn ,'UPDATE ta SET id='.$id); 2 P5 J0 {- K# a) w. I9 @* ^
- }
$ X/ U$ X0 c1 D& U+ [2 t - # php的文件锁,释放锁
3 h% @& E% E' C2 K, v P: n& I - flock($fp, LOCK_UN); + y5 N5 v0 R- d
- fclose($fp);
7 H1 Y% n7 L6 O& _ - 0 N: X* T5 h6 N
- // $res = mysqli_query($conn , 'SELECT id FROM ta');4 ~& z+ u* G" }. M' ^5 N
- // while($row = mysqli_fetch_assoc($res)). p. E8 [2 }( ~/ x' W1 ]2 R
- // {
+ q# Y% T, l i7 _6 h0 I - // $id = $row['id'];
( \$ E* W1 w" I$ T7 D - // }8 ?+ o( x+ U& L9 _4 l
- // echo $id;
复制代码
u7 |% l- M5 w: W, m) T6 f6 S: i1 r. k9 j! l6 h/ Y. @* r
抢券活动实例: - public function envelopeSnatching(){
4 U* C) {- k3 z - $lingqu = $_POST['type'];, n5 u3 j) N- N7 r& i
- $uid=session('u_id');//用户id2 s2 c; e4 O& h
- if(!$uid){
- \. O9 h4 B4 Z% A9 B/ Y - $data['msg']='您没登录,请先登录!';- |* O; v! ]1 t4 x
- }else if(date('Y-m-d') != '2017-12-12'){; K" e; q T2 c6 x" X
- $data['msg']='不在活动时间内!';
& L. Y/ S2 m J% W! @ - }else{" B z0 ^. i$ k7 o% v% d# w
- $hours=date('H');//当前小时数
. Y, w: G/ `+ G9 s% t+ L - if($hours > '09' || $hours > '17'){
( h0 M) D7 g0 B
. Y" l' v" `. y A0 b5 P! f- if($lingqu == 1 || $lingqu ==2){//点击10点的7 t: B$ q2 m6 w% Q+ Y" ~+ D$ H u
- if($lingqu == 1){6 c' D ?6 k) n, M, L/ T# R8 _7 [
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
3 i6 \$ V. k. b- p* ~; r- Q - if($hours > '09'){
: z3 k, g; _- j8 T - $num=mt_rand(25,28);//优惠券金额( z& S; f$ |; F7 [5 U7 `
- $id=1;
/ H" Z; Q' ?. w& q) U7 P - }: e7 e7 z, ~# X: h% Z6 x
- }else if($lingqu == 2){% H! a+ p! X- X5 G8 i
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
5 P6 ~. o8 r) _0 W* T# S: B- q - if($hours > '17'){. L4 S w/ C8 J6 x8 `4 o7 C% x
- $num=mt_rand(50,55);//优惠券金额 a. {. M* N; H5 w. P: l: G
- $id=2;
% p7 V6 P. S- ~+ d - }
; [/ N- J" ^2 O - }
8 m- Q0 S( {3 w - if(!$id){, F1 p0 g- R2 t9 g
- $data['msg']='时间还没到,晚点再来吧。';2 \9 Z7 s8 L) T4 a' P& B
- }else{0 E: }3 J& @' }! T+ [; [: V5 r
- if($is_lingqu){
- y& R5 n" t; S& ^7 l7 H - $data['msg']='你已经领取过了,留点给别人吧!';# g7 Q( Z' N; ]: X3 V
- }else{
3 K7 w- T0 v8 M9 N% B& E/ h0 F! E$ ?6 S - //锁表
! E2 d1 D8 X. h( s: V) r+ d8 K - M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');$ X; C' W" n/ M: F# @' ^
- $active=M('active_num')->where(array('id'=>$id))->find();$ B6 Z9 H/ z. h( Q
- if($active > 0){# j% ^3 A( a8 t, w7 k9 ?
- //开启事务
7 t, i p% N+ d h4 u; D: n - M()->execute('start transaction');0 H( N {& b& _$ H$ Z
- $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
- b: Q1 i# z5 Y2 I - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));# z. d# O2 r: N+ }
- $members_preferential = M('members_preferential');
+ h7 k/ Q6 k) |: J8 ~$ q - //对应投资金额,+ z+ h' d. V, f8 s: x
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
# q; E: m5 M% _: l# O5 W4 z - $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
" q: V& y3 _# w - $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
9 \3 E$ y9 F }9 ^5 r7 {7 r - $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券( Y G, n% T/ |/ G* F* @
- if($save && $add && $add2){
+ J4 u/ `+ `+ n# T5 u7 ]6 `$ E - //事务提交
1 j! m: v! R2 a* A( [ f - M()->execute('commit');
. G6 [/ R6 K* g$ _4 g2 b' Z - $data['msg']='恭喜你领取了'.$num.'元优惠券';9 D7 @+ x, P- k# C9 R, L
- }else{2 I# {( |6 p( i4 ]. j5 ?3 }
- //回滚
! }# {3 {- H% g' J8 Y, }# { - M()->execute('rollback');
- o* p# n) c; y - $data['msg']='未知错误!';
$ I7 S) b, Z) q$ G% B$ R - }
! G8 F2 M8 }% U3 W0 I+ G. O - }else{
. P5 h% \5 ?1 @0 q - $data['msg']='红包已领完,你来晚了!'; s5 g; _9 l1 c5 {) Y; f
- }
- r- T: _) d' P! T: Q* C - M()->execute('UNLOCK TABLES');* k9 }' b" K# L, |# {
- }
( W, A: w9 m- J5 ~ - }7 c: ^. Z& G5 ~4 a- }2 K5 |: @. i# I
- }else{
% q' F7 Z' l$ C1 n - $data['msg']='非法操作!';3 _* S3 S3 Z* Y" q
- } e" O/ K1 k7 z3 W2 a( `
- }else{
9 W e* J) P8 [9 f - $data['msg']='还没有到活动时间,请晚点再来哟!!';! t6 a8 }+ I O* ~. r: y8 M6 b1 b
- }: L7 ] l9 _1 r3 _
- } @, \3 G# s' o1 y3 a5 M7 E
- exit(json_encode($data));6 ^$ K' J. ?1 D' P- d x0 @
- }
复制代码
' X5 n# S3 x8 ~8 z1 e: m4 b5 D! i- V5 z% B; V
|