|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
' C" N- \' @( K J+ [* gMysql中的锁语法:: |% _( j. H1 d
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
3 z3 b" J* Y1 a9 k$ P) b( S3 S c/ L5 }UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表+ |( x/ q7 j: d
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞& g# X5 L1 ?8 W9 @0 T3 Y( G
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :
8 u5 {7 W6 B9 G# p文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
' x7 Q Z# R; N1 r- W测试时,有个文件就行,叫什么名无所谓 总结:# ?" |+ G, e Y
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:: ~9 `$ A% Q1 n7 R" t$ ^2 J
1. 高并发下单时,减库存量时要加锁' S; S6 H9 E+ C5 x& X& D" Z: \, _) C1 \
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*
: H {' B/ r, h8 c! j - 模拟秒杀活动-- 商品100件( M9 ^4 ?, U3 M8 e+ c! z
- CREATE TABLE ta
! u/ Q) F, C& k4 K5 y - (
' X/ N' Y- o: d' K# n0 [ - id int comment '模拟100件活动商品的数量'2 b# G) M1 x7 _ t5 T- {
- );
5 u& z/ Q E/ s( ~. g5 _0 a - INSERT INTO ta VALUES(100);7 U o/ x+ _% E& ]1 O
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件- v3 m8 ^& m2 ~3 ]1 Z2 ]2 E" i
- */ 6 E" [9 t. q% E5 U
-
% g% \8 I% u# A! | - // 关闭错误报告/ z8 y* M! E# v2 @
- error_reporting(0);
0 g0 i. _( R" |( B. q) I* i - \, u# A5 L. q: k: o( {
- $dbhost = 'localhost:3306'; // mysql服务器主机地址
& w/ y, W2 @& Y& o9 K - $dbuser = 'root'; // mysql用户名
9 s0 K! w: Z6 N% I - $dbpass = 'root'; // mysql用户名密码) ?/ D: c- |, F8 o$ Z
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
! h; i _9 Z; M5 ~( ~9 b - if(! $conn )
0 X5 i! n1 @; P$ Z4 x - {/ Q. A7 \/ w2 [1 E
- die('连接失败: ' . mysqli_error($conn));; r( V7 Z6 e8 E2 G
- }
1 Q- V8 }% K+ n3 b# e - // 设置编码,防止中文乱码; x* r0 G4 v h
- mysqli_query($conn , "set names utf8");
8 Q( \% p( |1 Z! u6 F' |/ }5 H - mysqli_select_db( $conn, 'temp' );
9 m! J3 F: C0 w8 K. b - , ?* }% B C& h5 G# b
- # mysql 锁
% J% F5 P) e- G0 H1 N f& U - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
8 A) k& w. M7 w7 Q+ X2 t; n - $rs = mysqli_query($conn , 'SELECT id FROM a'); 9 w3 }& F% C7 p, f1 w+ K
- $id = mysqli_result($rs, 0, 0); 7 L5 s6 _6 N* V
- if($id > 0)
& N, Q: ~8 i+ D0 U3 \ - {
+ i! t% y! y# D+ t/ C - --$id; - s5 D, O# l, T8 Y
- mysqli_query($conn , 'UPDATE a SET id='.$id); 1 W, [' t- ?3 {$ U: J6 F ~
- } }5 n" _+ s& D
8 \: f+ N$ G- @7 x- # mysql 解锁
( m4 ~" j( j: i" q/ ~. f% y - mysqli_query($conn , 'UNLOCK TABLES');
" K7 Q9 e! r% d' H* D - //查询解锁后的id值. Z9 [' O7 D. x, R) E
- // $res = mysqli_query($conn , 'SELECT id FROM ta');1 _" l" O) g. o' R) Q. O6 D
- // while($row = mysqli_fetch_assoc($res))$ L) h; U8 a, k9 S( r8 \
- // {% v" _. N7 W; @1 @9 i/ I- f; `
- // $id = $row['id'];7 N8 j9 B- B: j! T5 T1 t: {
- // }
# `* m1 |6 `+ Z/ S, \0 g# a6 B - // echo $id;
复制代码 6 W( O' u5 m _6 T8 ~6 M
+ k2 k( x0 M. O/ s4 M1 k1 e8 R) S& S3 P2 [% i J1 h# j; |
PHP文件锁示例: - /*
8 r, y/ s% S2 _* M( a" f/ ?. N - 模拟秒杀活动-- 商品100件
) P. X- E; x. ` - CREATE TABLE ta6 [5 @- f8 s0 n4 ]* ]7 I
- (
' A: @& @! k- R+ W5 d/ M - id int comment '模拟100件活动商品的数量', T; W( ]8 ~4 P/ ? j' s
- );! o3 B" i2 D* t6 z3 | F% d, S
- INSERT INTO ta VALUES(100);
! b8 d# T3 ]* e3 p/ j2 z6 b6 V - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件$ u# ]5 V1 Y- B. y
- */
A: W# G* A' A" H8 Y1 R9 G -
" u9 [. k% e6 |2 \- }& ]. ^% k - // 关闭错误报告
7 V A& j% C `# s( S - error_reporting(0); , I$ W: G& |8 F+ l' L
- 4 T$ b+ Q0 L0 g( i
- $dbhost = 'localhost:3306'; // mysql服务器主机地址
" g& y' R m6 ]* X4 y - $dbuser = 'root'; // mysql用户名
! Y0 s" _/ s2 y: F) _ ]6 d+ z) u - $dbpass = 'root'; // mysql用户名密码7 V& N2 Z- N# H- H- u5 K8 V* s
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
6 g2 B1 g" A0 e - if(! $conn )
% ~' C# `" \8 k* f1 D, g" B - { L) S% J( Q( o2 l9 @5 b7 ^+ h
- die('连接失败: ' . mysqli_error($conn));
2 n0 J( M; h7 U3 e) R8 p! A - }
% o: m- }3 H/ K3 J/ Z - // 设置编码,防止中文乱码; q# ^3 D/ ^: M; ~ Z% P% j( z8 p/ U
- mysqli_query($conn , "set names utf8");8 b4 Y4 U3 l2 F' A$ r
- mysqli_select_db( $conn, 'temp' ); 8 F5 t( [( ^! G& O
; {8 ~- s; Q: A, M' r- # php中的文件锁 2 e4 P( {3 |6 g0 G9 I* N) Y: J Y
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
* Y. }5 a b# L' G! Z - flock($fp, LOCK_EX);// 排他锁 $ q0 P! L; F* r/ L) A
$ V: ]% z g/ i0 k- $retval = mysqli_query($conn ,'SELECT id FROM ta');
' i( k+ o* t3 V3 j# `! V# S - while($row = mysqli_fetch_assoc($retval))2 b3 H0 I- L Y# \
- {
7 g, I Y4 N" {1 K* w1 @* u - $id = $row['id'];% X' k$ S g: F( G
- }
) |1 r+ ^$ y4 h+ Q - 9 z, n6 B. Q) q/ W4 }( ^* G
- if($id > 0)
: W! h( M4 i' ^1 k! h# x7 ]6 _ - { 1 o4 n0 C' m. s, f9 I* o n0 W
- --$id; ! N2 C; _; _1 U; ?- c0 c5 f
- mysqli_query($conn ,'UPDATE ta SET id='.$id);
3 j) m! D1 I/ D% `; F( x1 l6 h - }
* q$ W3 q' t* x: _1 z - # php的文件锁,释放锁 ; i2 p. b a& s2 J& W: T1 w
- flock($fp, LOCK_UN);
" o f0 [' R% H' k: r - fclose($fp);3 e: }& a j9 ^; V, Z$ O
- ) H; P5 W. k$ C) R1 o: d s4 F9 r
- // $res = mysqli_query($conn , 'SELECT id FROM ta');4 A9 G- ?5 h" Z5 S; F7 j8 p+ Q
- // while($row = mysqli_fetch_assoc($res))2 _2 L0 y, W4 Z$ m1 B7 ?' c$ T0 n
- // {3 i6 q4 E0 O/ k* I& C
- // $id = $row['id'];
6 X+ l( @7 @4 C0 e2 }+ j) c - // }
4 ^9 S( @. Y0 m) W - // echo $id;
复制代码 - Y7 E+ u6 c3 S" A/ q1 `% \
0 T p. P, a2 \( ^4 \抢券活动实例: - public function envelopeSnatching(){; V5 W2 ^7 ?& K/ I- s
- $lingqu = $_POST['type'];
& i+ ~6 r) p- h/ o& M6 X6 j) ~ - $uid=session('u_id');//用户id4 ~/ |# ?9 Z6 T7 L1 L
- if(!$uid){
( {4 O: q! t7 g6 a! z' G# B( s) l& K - $data['msg']='您没登录,请先登录!';; k% ?- s$ a' N6 G
- }else if(date('Y-m-d') != '2017-12-12'){
( R2 [) u1 U+ K8 q! i - $data['msg']='不在活动时间内!';
7 v' \1 ^# L5 e! D6 \7 z - }else{! G$ o3 [ g- W# Z x0 C
- $hours=date('H');//当前小时数
1 W) ~& f- f& D5 i; ~ - if($hours > '09' || $hours > '17'){
7 P6 r' k0 _& u- A. U
! `1 f* L1 R) ]- if($lingqu == 1 || $lingqu ==2){//点击10点的
' M9 }6 K2 n1 @7 z5 L: v* t( ? - if($lingqu == 1){* ^; O' \/ [! p+ q
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过0 t X6 N; @5 Z8 W6 R# N [8 ]
- if($hours > '09'){" i+ o' ?( |! n
- $num=mt_rand(25,28);//优惠券金额
) \6 H% Y7 Q7 k7 x8 u - $id=1;5 h: @5 s* G4 T. K
- }4 D9 p0 m% }* @/ M
- }else if($lingqu == 2){1 e6 F: y- D3 P8 \) J
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
5 x: I+ z- l) M c& c - if($hours > '17'){% m1 g; ?5 R& q' ~$ H; p$ j
- $num=mt_rand(50,55);//优惠券金额
) l5 g: n! z4 U* N - $id=2;
, l: \$ Z, H$ u5 O/ A' v% U% H - }% _: f7 \' \( \6 V. v
- }# k% i g$ A8 l3 H9 [0 d- B
- if(!$id){
* e( d/ C( v0 M8 [& `, ^ - $data['msg']='时间还没到,晚点再来吧。';1 Q# ~8 I: V& R W8 Y! Q4 H% n+ c& p
- }else{
! k$ o6 m! A1 n3 E8 o1 o - if($is_lingqu){
1 G( F7 Q8 e& G% M) I3 c9 i: N6 x - $data['msg']='你已经领取过了,留点给别人吧!';
- R u% e9 D: ]! _6 x! T4 |2 ` - }else{
% n+ }$ F: `4 e, A - //锁表
1 R0 G0 N. q) X1 r - M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
/ z' n$ v# N9 v% `, j6 { - $active=M('active_num')->where(array('id'=>$id))->find();7 y: c5 C1 u! s# R4 i; V
- if($active > 0){3 S, a9 F0 N; g4 W/ S% m
- //开启事务
, a4 G6 `* F6 c$ |8 ]) b! F - M()->execute('start transaction');
& n2 H) X* z' l - $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
% d/ m2 s0 e9 e1 c7 U/ ?5 ] - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
+ @7 k& T* R' y2 B - $members_preferential = M('members_preferential');
z$ s: Y) H K: J# i - //对应投资金额,
# R5 U9 R9 p6 w5 r6 i- \ - $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));0 _. [% P# W3 E, K
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');' i" }8 p, s2 m; s
- $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间1 i% o$ w* K/ Q5 k+ f- j! k+ @
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券+ T* K3 x; c" A& j
- if($save && $add && $add2){/ p+ B0 {$ N G8 ?5 x- T, [+ W# }, C- b s
- //事务提交
( v- z) s7 J! R& A5 t - M()->execute('commit');1 O4 n+ b; F! [1 T% N
- $data['msg']='恭喜你领取了'.$num.'元优惠券';
" f* M: X/ f+ P4 M1 W4 Z% G! U - }else{
& g% A- d# Q! K, L- M7 o" ? u; x2 c/ a9 ] - //回滚# T; W: \- M: z- r
- M()->execute('rollback');
$ ~# a* U& l; [. u3 v7 L& ]' j- c - $data['msg']='未知错误!';
a0 }) k+ b9 E- D9 Z0 ~ - }0 n, l6 L" g% H" u
- }else{
/ q( e0 m3 Y/ { Q- c8 \5 D - $data['msg']='红包已领完,你来晚了!';
4 p/ s) i j4 ^2 J9 l- i - }5 a6 w4 W5 g$ U; L$ X9 L& W' F G$ f
- M()->execute('UNLOCK TABLES');
) }4 ~0 t: {$ u5 R) y( q( \& X - }9 [' B! \1 Z5 J
- }# ?* B0 w; C: I6 ]! w
- }else{
' \" x5 p; M9 o7 f( B. \2 L8 b1 ^ - $data['msg']='非法操作!';
9 {; e" O. u4 Q* ?$ ^# K0 R. I1 f3 ` - }# Y7 q& Q+ K' m5 c: Z
- }else{7 F: F6 i1 N( Q( c- r3 ~- V
- $data['msg']='还没有到活动时间,请晚点再来哟!!';
# ^) x3 ^5 K* @% B' s- o/ F# N, U! b - }
3 {& c) s. v* H R! B - }
* R1 Y, j' o, F - exit(json_encode($data));
$ L6 o* ]+ `- [ - }
复制代码 , | d. b9 N3 N; M3 }
' f' y; c, k3 @3 x0 `8 q
|