|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
$ H D) n# W5 ~; E2 O2 f2 z2 FMysql中的锁语法:; r# z! H$ I$ i" F5 f( b
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
# T2 W. p, e$ ~: c' \7 L5 aUNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表/ A. {3 F2 f# H2 `
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞/ ^1 j6 y: R+ K5 z. z
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :
+ n" z2 r' t- q( d* Z5 u1 a" E文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
7 R) V+ e. J5 T4 R测试时,有个文件就行,叫什么名无所谓 总结:
' n% ~0 P* b, A项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
* |6 ]7 Z9 {# ?- |( ]( X5 y; T; e1 s1. 高并发下单时,减库存量时要加锁4 U+ K; w/ R) o% | T: ^7 v
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*, {8 @: @" j6 l# k& W# T
- 模拟秒杀活动-- 商品100件
3 K- S( l8 |/ }' O - CREATE TABLE ta. H$ ?& A% R% s
- (3 v& J" @2 p0 K, {$ b4 w2 W" j
- id int comment '模拟100件活动商品的数量', ^, [! D6 f0 G0 \
- );
) S6 l/ E# R" X3 F - INSERT INTO ta VALUES(100);) M' K4 r& `. I6 W" M" S, {
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
7 R/ l2 i$ w) m - */
; E, S& T2 c# k8 b. H" H -
$ ]2 {+ W2 Z! A4 {, c, k - // 关闭错误报告) D; q, x0 D/ e/ y
- error_reporting(0); X: M: e; H" @2 [# v" P" d5 T
5 P! Y( M9 F% E( E- [6 T) E1 n9 K- $dbhost = 'localhost:3306'; // mysql服务器主机地址
5 t) E7 n0 i2 G% ] - $dbuser = 'root'; // mysql用户名
7 S8 m# C2 T5 U2 D - $dbpass = 'root'; // mysql用户名密码% ~/ s0 l2 C* P0 @9 |
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
3 a1 o. x2 m1 c3 Y+ o: }" k7 J - if(! $conn )
e3 S8 D' r% S0 Z - {) g( I3 k7 v* G0 \8 ~# |
- die('连接失败: ' . mysqli_error($conn));$ s0 ]8 W6 H% g
- }2 r* a7 h: j- p
- // 设置编码,防止中文乱码4 Y( F- [" e( ^
- mysqli_query($conn , "set names utf8");# i$ N& `0 n" }& m+ Q+ r
- mysqli_select_db( $conn, 'temp' ); : Y' F6 y3 W" k. K7 X, I# a
& `& h1 v0 F `1 d, k6 Y- # mysql 锁 1 l' y" o9 ^5 B$ z
- mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
" w s3 f$ I6 w7 w0 e9 ] - $rs = mysqli_query($conn , 'SELECT id FROM a'); " ?8 i+ X/ M! J2 ?" n5 q
- $id = mysqli_result($rs, 0, 0);
8 G/ L) F! W$ k& k# Z8 Z - if($id > 0)
7 Z/ R* T& a k; r - { 7 b7 g4 j/ l8 ?! f2 Q" O
- --$id;
/ l" E u1 _9 B( X - mysqli_query($conn , 'UPDATE a SET id='.$id);
8 L& f s; L/ @8 } g - }
) W/ p4 n7 B( g
$ J! }- M; M* C2 e! c- # mysql 解锁 & D7 b( Q% Z( }: B
- mysqli_query($conn , 'UNLOCK TABLES');+ f" \7 ]) X3 L0 H
- //查询解锁后的id值
7 C. f% m1 ]: d. w6 U3 } - // $res = mysqli_query($conn , 'SELECT id FROM ta');- |# H4 s) f" l4 _" U5 V6 V! o3 z( U
- // while($row = mysqli_fetch_assoc($res)), z. F0 r) E) K, @7 J# p# a! _5 z
- // {9 Z/ R4 _+ [! ]+ d
- // $id = $row['id'];
' F6 Z7 _ O" _: s, F. \) c - // }
( e: G( F% F+ Q4 H: v. O - // echo $id;
复制代码
7 K8 a ?: m( R! K5 P1 g( E& ? i: x8 b/ [+ S' i' ]
: W3 `+ l' d9 j( J8 G* _PHP文件锁示例: - /*3 l) F5 k* e( X+ a
- 模拟秒杀活动-- 商品100件4 m m- J3 x1 Q) D! e' u3 l
- CREATE TABLE ta% S: S7 l, }0 E, s
- (, z, d8 n# y/ T& `! k3 c0 q
- id int comment '模拟100件活动商品的数量'. }. z( C$ S. S
- );
( h: P' F" e1 ?% ~7 G% C* n - INSERT INTO ta VALUES(100);
3 U+ e/ f9 {- B ^0 f - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件% S$ f8 U! o O' ^9 H2 i
- */
# S& ~- t$ \9 e' `. }3 Z p - ' k- ~! x1 k- H5 j/ r
- // 关闭错误报告7 p# k5 B% N) W) r/ O
- error_reporting(0);
5 T$ x$ z- b; l, m/ f( b4 G [
9 \- V0 ~" I7 D9 [* c- $dbhost = 'localhost:3306'; // mysql服务器主机地址
; }4 l) e: p2 b. z( p - $dbuser = 'root'; // mysql用户名
5 Y7 N1 V$ M% Z. [3 p. f# R - $dbpass = 'root'; // mysql用户名密码8 Z% d" U k# N$ w
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
9 {8 \# I6 Z2 }$ F5 i: o - if(! $conn )
( b! ~0 T) N' @' ]) c* A# m# S - {
" V1 W1 }% o- a - die('连接失败: ' . mysqli_error($conn));
1 G. Z' z& z" f2 z2 e) o' { - }
* r/ V7 Y7 e2 p - // 设置编码,防止中文乱码: ]1 i% v) H# W- q: k( t/ b
- mysqli_query($conn , "set names utf8");
: Z" _+ N2 z* w3 X+ g9 [( O) \5 V - mysqli_select_db( $conn, 'temp' );
, f" j- N9 A8 Y
' }9 k4 T3 s3 q8 n- # php中的文件锁
9 _9 `/ e/ x; k# C2 \! p - $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 7 p [! J/ P" i
- flock($fp, LOCK_EX);// 排他锁
! |; b5 _# G+ f) I# x' e8 s1 Y: @* a
5 h! C+ e3 Q6 _* d% q- $retval = mysqli_query($conn ,'SELECT id FROM ta');
. _! m( e: ^( N- Y; _: O6 y" b - while($row = mysqli_fetch_assoc($retval))
2 I. N5 p9 P4 }2 Z" M3 f - {
* R: z8 i4 F; S* I$ } - $id = $row['id'];
8 J, p( T3 O. i7 s$ \0 j2 D - }+ H \" p# G& J& o
-
( U* \/ j! l( A: f$ `+ l - if($id > 0)
4 b6 R& R& b$ S; X0 \ - { 4 r7 z* |' F- k/ b- B. Q8 Y
- --$id; 0 W" f3 ~! E4 t
- mysqli_query($conn ,'UPDATE ta SET id='.$id);
! r* R: M7 ~8 p& q+ e# m- | - } 4 y, K( m' H+ s; N( k- N: c
- # php的文件锁,释放锁 & E* h' U2 M z3 M1 E
- flock($fp, LOCK_UN);
* O) x$ t. g8 @, M# ] - fclose($fp);# P e2 a# W0 ? }
- ) Z" q+ K% ~; K
- // $res = mysqli_query($conn , 'SELECT id FROM ta');
J/ n# W& m* h ? - // while($row = mysqli_fetch_assoc($res)): ~: Z5 N7 u3 x* t
- // {2 t, B! }$ N5 b% T5 i3 [
- // $id = $row['id'];; W1 u* n- p, M2 q+ i
- // }" a W5 C, x$ O& e+ N
- // echo $id;
复制代码
1 g* q, L$ w8 H* p$ s% o: `2 e) [ S8 P& Q# Z
抢券活动实例: - public function envelopeSnatching(){
/ Z5 u8 S& a1 w' F1 n - $lingqu = $_POST['type'];$ s0 Q, t8 q4 E: ]
- $uid=session('u_id');//用户id
4 S2 I) R" @. D: \ }5 q - if(!$uid){0 Z& `0 L9 a1 j7 O1 N: G2 O
- $data['msg']='您没登录,请先登录!';4 d% l0 B0 W. n8 A# }$ b) k
- }else if(date('Y-m-d') != '2017-12-12'){" b: H' |* ~8 C
- $data['msg']='不在活动时间内!';# _* R4 }& k) T' V
- }else{# Q% B+ d" Z" }+ z
- $hours=date('H');//当前小时数; v4 h3 u: m/ A
- if($hours > '09' || $hours > '17'){
7 x( C P7 Y0 x2 e1 s
* D$ Q e. F! O, A" W2 t" E( {- if($lingqu == 1 || $lingqu ==2){//点击10点的# c+ L7 g0 b7 m% o* j
- if($lingqu == 1){
# u: F( B4 [% C$ s5 Q. U! S - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
% {- E$ a2 z- Y( q - if($hours > '09'){, U, E( \$ }5 R- p6 |
- $num=mt_rand(25,28);//优惠券金额+ X+ C/ V# Z$ @" }
- $id=1;
9 h9 L; e$ R4 U* c - }! k. q3 t& {6 |1 {5 H& O+ {
- }else if($lingqu == 2){( g; a5 B8 {! m7 M g3 N7 ~
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();2 x; P. \" q: G7 Z: H
- if($hours > '17'){
`, x" q$ b6 R. l' w/ q - $num=mt_rand(50,55);//优惠券金额4 O& Z2 Y+ u6 X$ s$ s! \
- $id=2;
& M6 D- d$ z& ?5 @9 h - }
7 y, B( n% q* P - }
$ i2 _! a0 o2 L! Q* Y' y - if(!$id){* _ M K, l2 ?, v4 c* ?
- $data['msg']='时间还没到,晚点再来吧。';' l5 s+ I3 Y' o. e
- }else{
+ L$ }* i2 h. O5 ?! o - if($is_lingqu){
8 X- G( L7 S q8 W4 K8 _ - $data['msg']='你已经领取过了,留点给别人吧!';
1 I- d4 F5 q/ o( f& ~ - }else{( H* `# q2 q7 o; I
- //锁表4 J3 q' q Q0 B; D: b
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
9 B5 B5 R' j/ t$ Y1 ~5 H) b - $active=M('active_num')->where(array('id'=>$id))->find();! n6 l/ n* O% U# n. X( v! ^
- if($active > 0){- w! C, p. n# l
- //开启事务
' {% B" V% h* Q& M$ _) ^ - M()->execute('start transaction');; E! W N6 g7 s! Q9 `' u: R
- $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
- j" Z' f" p& `, p5 G$ e3 s" e+ D - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));# U* ^0 g; o3 U1 r( _; ?
- $members_preferential = M('members_preferential');
. b e* v/ R6 F) {! `. @ - //对应投资金额,
0 Y+ O+ s/ W& t: ?/ f - $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
1 _) H' z! w* m, X: W8 G - $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
7 W$ \$ [7 ^8 Y8 k: ^& P) u9 ? - $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
% k" n1 r( s: {0 m* @- ]) e4 i# ] - $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券9 w+ @4 g, O& S# l. {$ t5 ?3 f1 d
- if($save && $add && $add2){
3 V9 V7 b$ g( E( P - //事务提交
) P2 m+ [7 W- a8 G. k# [! L - M()->execute('commit');0 Z4 U% B) z4 a* J
- $data['msg']='恭喜你领取了'.$num.'元优惠券';
" s2 L. L: c1 `% G - }else{! g1 Y6 b6 q6 H1 o; b% p0 E
- //回滚' E1 O. B7 G5 E' {* K$ _6 T m
- M()->execute('rollback');- G" R9 y" n! y& m. T
- $data['msg']='未知错误!';
2 L$ o; s, H9 ` - }
- y& T! ?, a: q7 k$ M - }else{
; L: O! t! P& L( K - $data['msg']='红包已领完,你来晚了!';4 t% @* h- k& A6 t) c, p6 u. a
- }
9 c4 E- L X8 A! \1 [ - M()->execute('UNLOCK TABLES');$ o, M9 B. k3 @' z- U9 i2 u
- }
/ s) ]9 I/ p: N7 J& [ - }
6 L, ^. c5 u, _2 r6 h+ }* T - }else{" O# C- J9 E( c8 w( v+ d
- $data['msg']='非法操作!';
3 n' a0 M6 P; w t) H" T - }
( F( E; U( ~ U# g5 B( x - }else{
7 w, Q2 Y, ]/ r% | - $data['msg']='还没有到活动时间,请晚点再来哟!!';6 c" B* \5 C; ]7 N% j/ g
- }; g o0 `) F2 g' h9 P. S- g: r
- }% A9 c8 C2 Y. [2 N3 ^
- exit(json_encode($data));* F7 o1 s6 S7 w; @+ n7 g
- }
复制代码
$ n& S4 d7 d6 R8 y$ t( `8 E& A6 l. r4 D w
|