|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码 ' Q) U* f, T, T; a6 A- e! V) X
Mysql中的锁语法:
- e e' x- b7 U" i( T% F" ULOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
$ K9 a5 \* ~3 ~' C% G4 A6 CUNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表6 p$ U* \# t. ~; A. N
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞: k. m9 F! c5 @: C; Z
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :
* w! W4 h4 S @8 b文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。& x4 c5 _" K2 \; h+ h6 _
测试时,有个文件就行,叫什么名无所谓 总结:- P3 L" P' v$ e! E% f2 G9 B- M
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:1 z I: j2 w! s e0 V+ t2 k
1. 高并发下单时,减库存量时要加锁+ U v! { K# W' c9 v# `
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*; p/ @; C' R* M6 f% O* x8 L' j: k
- 模拟秒杀活动-- 商品100件4 c; x' i, x6 E' m$ ^
- CREATE TABLE ta
9 `- w! o! _% {& `. u, |& z - (
! W( h2 p' G, g8 Y9 e - id int comment '模拟100件活动商品的数量'
4 _; L! B! G% { - );
7 q, p6 i: O" x: X) b# Z, B - INSERT INTO ta VALUES(100);
+ a/ \6 r; \# h - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
, q4 x% c6 Q U$ L - */ % U8 E3 n1 y7 f$ ?. b- O" f `
- 6 @* y2 k$ ~: E
- // 关闭错误报告' n2 ~$ v2 S8 E [
- error_reporting(0);
) M0 J; f' m$ C- ?1 F! d9 I
6 C. Y( l+ ~0 p- $dbhost = 'localhost:3306'; // mysql服务器主机地址
6 Y4 u8 y5 o. p& F+ @) q - $dbuser = 'root'; // mysql用户名: Z: S$ |9 i8 E5 M" N
- $dbpass = 'root'; // mysql用户名密码; ?+ a! R( l- e$ O( H
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
& n( b; n. O! k; j8 U - if(! $conn )
% e# ?0 a! E; W3 k9 Z - {7 j9 L$ ~% [2 r0 v& b
- die('连接失败: ' . mysqli_error($conn));
* |: |% E) J1 F - }% [) K& U v6 L" L2 D4 O/ P
- // 设置编码,防止中文乱码
* \6 D N0 ]8 c, p$ ~: @$ ~+ @3 }3 B - mysqli_query($conn , "set names utf8");
4 d" \1 D% @' P, S7 I - mysqli_select_db( $conn, 'temp' );
5 J ~6 S" \% y: o% x' Q - 1 q8 ?/ x; n3 ~, u
- # mysql 锁
5 i4 G- [& n+ B9 {. K - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
2 A6 u) N7 @4 x0 C* n: u$ U - $rs = mysqli_query($conn , 'SELECT id FROM a'); 2 J9 J9 M0 V5 g# T3 b* h g- e
- $id = mysqli_result($rs, 0, 0);
( X% D. @" r$ m) E; { - if($id > 0) & a+ x% a5 O+ C9 p, y
- { # f' n3 Z. F9 y2 Z- ~, X) v
- --$id; - j9 y' e! @' L# H
- mysqli_query($conn , 'UPDATE a SET id='.$id);
: d9 X# ~4 U2 j$ u; p - }
7 R$ f- ?2 k& Q2 \$ I - ( B/ ]0 K$ |% \% Y7 L
- # mysql 解锁
$ q0 i5 m- C' F, K - mysqli_query($conn , 'UNLOCK TABLES');
; p: X C) J! ^. m$ }3 s - //查询解锁后的id值
: {5 m& O z7 Y) A! L - // $res = mysqli_query($conn , 'SELECT id FROM ta');
7 _2 |9 Z/ F$ c% |7 I6 O2 {: B6 m - // while($row = mysqli_fetch_assoc($res)). z; n. I9 [) n# [) _# B" Y+ f
- // {
. l& v1 s/ W* ]; x - // $id = $row['id'];& X1 n. i, H0 H% j4 r" Z
- // }* o' @. a; i v
- // echo $id;
复制代码
# o4 m! z- y1 n* a/ d& K
* }1 [- k, o6 e8 W/ n9 q$ Z' P' P% ~
PHP文件锁示例: - /*/ V/ u8 O1 Q. k1 A7 k0 _3 x8 M# P
- 模拟秒杀活动-- 商品100件8 v, l5 e% S% }9 w( ?- ~. K
- CREATE TABLE ta0 p# ~2 n! t. V% s
- (
/ O, [3 y! N$ R& S' Z5 [. V9 { - id int comment '模拟100件活动商品的数量'. g0 U4 z# A6 x
- );0 F7 |0 D5 U8 n5 K
- INSERT INTO ta VALUES(100);
+ b. p5 \; J3 s' P- x - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
! k. l! |$ A) T# P y2 V - */
0 F, M: D7 n. O! Q( J5 f - 4 Y2 [4 z5 _$ i
- // 关闭错误报告5 `8 R( C3 ^; @% z- \
- error_reporting(0); # L) Q9 @" i, x/ X% t; | n- c9 j7 z U
- - s" b, i2 d- J/ a
- $dbhost = 'localhost:3306'; // mysql服务器主机地址# D3 R+ l4 X5 t6 R( O$ g/ O
- $dbuser = 'root'; // mysql用户名* [' ^4 j1 E9 L" I7 Z
- $dbpass = 'root'; // mysql用户名密码; w' E0 K+ D2 n2 u1 N( B
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);) R* l4 y' o! d/ _) j
- if(! $conn )
! m1 g3 A4 H( R+ c) x H* v - {
$ I8 v0 W; W- j1 T - die('连接失败: ' . mysqli_error($conn));
* E+ |$ {2 H/ ~ - }; `6 e* }7 w# I- q
- // 设置编码,防止中文乱码
1 Z7 [ \5 u5 m; V5 E4 G4 P7 H' _ - mysqli_query($conn , "set names utf8");
+ s6 d3 ]- ?( H7 Z% z - mysqli_select_db( $conn, 'temp' );
2 L2 c; G T' J6 V( Q" Z# i, { - 6 u/ z- K3 j% d5 U3 w- e
- # php中的文件锁 6 _, }( j! S: d: [" x. C
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 & _5 ~/ l* T4 x4 ~$ K
- flock($fp, LOCK_EX);// 排他锁
! s: \/ J' _% t \: P/ S( Y N
: Z5 v' P& H4 O8 u4 _. Z- $retval = mysqli_query($conn ,'SELECT id FROM ta'); * K& \* p+ l# }0 g! p, h
- while($row = mysqli_fetch_assoc($retval))
( G9 [/ E9 K3 x! \7 V; A - {
3 k- g7 ?( s/ e; ?( q+ l - $id = $row['id'];' q! |# f: c/ y$ R' G
- }
6 F% O; }3 h. H" q7 p. W - " b. H1 H u; N6 o( {4 D
- if($id > 0)
0 m% `% t1 }3 Z p- \# v - { / k5 x; |- v/ N9 Y! d8 g! ?
- --$id; 1 Q, l! c5 g) j9 V+ k
- mysqli_query($conn ,'UPDATE ta SET id='.$id); / D' W! E# S' Z+ H
- } / _1 t1 m9 N/ r% L/ r5 z. c
- # php的文件锁,释放锁
7 W% g, h2 m6 H& X6 Z$ V0 c - flock($fp, LOCK_UN);
7 r2 \5 e+ `* }$ B3 N( H- i - fclose($fp);' x* e( y: S: A- Q8 ?" S2 P1 E
6 T! z: Y; p; h- // $res = mysqli_query($conn , 'SELECT id FROM ta');
6 y5 |+ s5 c( \6 t+ q, b L - // while($row = mysqli_fetch_assoc($res))4 A' g5 ?# u" ]% x4 d8 S$ d Q
- // {1 s9 Y7 h4 a& s! p& X2 T' r
- // $id = $row['id'];
7 ?% c6 C$ J/ B+ N2 ~ - // }3 S7 e+ Y1 _) ]4 [9 F9 Z
- // echo $id;
复制代码
1 F" ? h/ q6 Q `% `! R$ g d, d U: ~. w2 _+ F& E
抢券活动实例: - public function envelopeSnatching(){$ b2 J- M% n ~/ V, }5 [: f
- $lingqu = $_POST['type'];
3 J" W1 ?$ w6 R' h i! @% P* t - $uid=session('u_id');//用户id( n2 a' M! @% O
- if(!$uid){
# V3 x1 N# j- s% o; m% F - $data['msg']='您没登录,请先登录!';6 K7 Q; V/ s) b6 Y- z6 J5 ?
- }else if(date('Y-m-d') != '2017-12-12'){2 W' a; D2 z) Z0 h* r
- $data['msg']='不在活动时间内!';
- N9 y6 `! Q5 q3 b* M - }else{) I$ X3 g- f. v' ^
- $hours=date('H');//当前小时数
3 ~* y, Y8 |% v8 I8 i - if($hours > '09' || $hours > '17'){) g( w6 q- L& l- k
! f* y+ L# v2 \2 p( U1 ]- if($lingqu == 1 || $lingqu ==2){//点击10点的* B" v- `; Q* M# S6 { Y
- if($lingqu == 1){
) R/ C1 Q, o" _% T, U - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
$ `& D7 K' J* r7 D - if($hours > '09'){: J& i' R8 ?9 Q, D" h' l. S( V
- $num=mt_rand(25,28);//优惠券金额
$ c9 {6 ?5 a; S - $id=1;5 K' c3 {8 _8 b) u% C/ O
- }
) v+ ~" b0 P+ }9 F3 w - }else if($lingqu == 2){: G& F# s0 I9 l7 _3 d8 _
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
* ~5 I+ }$ [7 }6 I: u) M' | - if($hours > '17'){
! O9 p# X5 F4 Y# R" u5 y5 K - $num=mt_rand(50,55);//优惠券金额, \* X( ?- H' f+ v$ g% ^9 \5 E! }6 x
- $id=2;6 `& Y: x- ~- P9 L' s
- }5 N) E/ E8 M% X9 C- i+ L
- }- m0 Q& ?( H P: V* V
- if(!$id){ j) u+ E3 ~* ~' x" P
- $data['msg']='时间还没到,晚点再来吧。';
- u2 K% b2 S) e3 f' F* K - }else{( D4 i0 V( ^# F' J/ `5 W' b
- if($is_lingqu){0 r( W7 H4 B6 j! y
- $data['msg']='你已经领取过了,留点给别人吧!';
* l; a* p2 C5 N L2 g# H' {6 d& f - }else{
" D' X/ h0 N p5 V8 P - //锁表
: A! s1 Q0 C8 D- d3 t% C' V - M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');0 y) k& w* m/ k# U1 E0 Z: K+ {
- $active=M('active_num')->where(array('id'=>$id))->find();! i- f7 @- j& k! Y' n5 {
- if($active > 0){
7 S: D+ E6 q1 m2 C4 b: T( n3 m - //开启事务
2 O" i, C: z6 ]7 [1 P - M()->execute('start transaction');, K; [( T; m1 {# f
- $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));% V- j. w& F9 ~8 L# G( d
- $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));! q8 H j, K0 i
- $members_preferential = M('members_preferential');4 d+ t! i; t' n7 c
- //对应投资金额,
+ d& _+ @; ?* U5 V - $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
/ T# ~, ~2 v9 G ^8 ]' C - $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
0 L3 z, Z, W. N7 C9 m: s+ A - $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间! D% `2 \, M; D I! `
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券5 O' {- u$ U0 W' H# A7 D
- if($save && $add && $add2){
. V5 [: i# \0 h. c - //事务提交2 n9 E. e: x, c8 M/ _
- M()->execute('commit');; `; T# x: J' u
- $data['msg']='恭喜你领取了'.$num.'元优惠券';
5 X& x* N4 E N) H$ _3 Q+ t - }else{+ M3 y5 S: M' E: C2 }4 o
- //回滚
$ Q2 `. b4 Q8 x! N% f! @. y. M% o - M()->execute('rollback');4 V8 e; p5 x% D/ _' k& N7 d
- $data['msg']='未知错误!';. d" N, z' v- @1 ~# k
- }( ^0 D( c. d/ J
- }else{& w9 p: L% C' X$ o( h8 A
- $data['msg']='红包已领完,你来晚了!';! E( i( e0 i. }& t
- }
: m# `6 p/ K; D# V - M()->execute('UNLOCK TABLES');' ^+ Q" q1 f& Z
- }/ X) ~2 _& T& c! _; m2 N
- }
- d N8 @( f9 v Z - }else{' \! X2 @: K4 w! ^( M# S' T
- $data['msg']='非法操作!';, z0 l3 c$ F. X4 b+ x
- }
5 W8 P2 m7 L0 v7 f2 Y0 b - }else{
' p$ |8 ]- Z& D( f3 J' N - $data['msg']='还没有到活动时间,请晚点再来哟!!';# c% `! o9 c/ {8 |# P% u" v# Q
- }
# J1 r" W( X. @$ [! C( o) _ - }
. C0 J# y; K& n# I - exit(json_encode($data));) s4 Q4 y! h2 d! r. I( K4 L
- }
复制代码
7 _5 A. x( o3 v4 f- A
& Y2 P8 }" Z2 H8 h& o: e1 ? |