模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
j }. i' Z$ R' i- \6 NMysql中的锁语法:4 X) b# G. U' l! K s" L% T9 @
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】! ^& K% ~4 y) ^
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表9 ^' w9 V) I5 ~4 ~ u+ D
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
$ K5 J* S/ |* R注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :1 e% o! H h- t, Q, r( ?
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。$ c" s. o9 c! l! W8 q
测试时,有个文件就行,叫什么名无所谓 总结:
$ r- J3 c; v' [1 d4 p* Z" Q项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
; f$ ^8 W0 l! k0 d7 W1. 高并发下单时,减库存量时要加锁
: P/ ?( Q" L3 p, F5 t2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*
# Q. i2 _: w& q6 {9 u9 }- { - 模拟秒杀活动-- 商品100件
! _% a# p* g4 }) A+ g1 W - CREATE TABLE ta+ I+ D8 }( Z' t/ g
- (
, e5 B* K( s# b7 g - id int comment '模拟100件活动商品的数量' W l+ ~! k- W9 R/ {: ^
- );
0 `+ M1 U" t1 Q7 U4 ?+ s9 |! v - INSERT INTO ta VALUES(100);; m6 |6 c+ b( X- Z$ |$ t
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件$ M5 c3 U# G. D# P4 J( r
- */ ' p7 r- X6 r3 G( h% i1 U
- % E6 x9 ^( Y2 V% W: U
- // 关闭错误报告! M2 d. i" a2 J7 j+ i
- error_reporting(0); 7 k( l; E- V5 Q% }( o2 }7 L, b6 O) q
: f+ s$ B o, s; n9 P- $dbhost = 'localhost:3306'; // mysql服务器主机地址- R+ v2 A$ ~0 }' m
- $dbuser = 'root'; // mysql用户名
8 _% B( H9 P% I - $dbpass = 'root'; // mysql用户名密码
% X: p) Q2 e2 t1 }) L1 u - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);# d( [8 L. k5 B: K; H) U
- if(! $conn )( z5 w Q" ]' L# j( x6 a
- {
& Z- W3 w% g* M/ M: q5 M - die('连接失败: ' . mysqli_error($conn));
- Y" j) W/ @+ U8 F% k - }8 V6 L- R# m5 s) ?
- // 设置编码,防止中文乱码
7 _+ H; ]+ T) b0 e" ~8 c6 S - mysqli_query($conn , "set names utf8");
+ y+ E3 A4 m* V# Y+ R5 c' n, v5 ` - mysqli_select_db( $conn, 'temp' ); $ ~3 ~0 V. g9 L
5 H" D& z: V V8 Z- # mysql 锁 4 }% N5 s" ~1 P2 k. x, g
- mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
+ j4 l0 p/ b& A& F8 \9 K6 M4 U: e - $rs = mysqli_query($conn , 'SELECT id FROM a');
* d0 m5 K4 h- Z - $id = mysqli_result($rs, 0, 0); - R! A' Q' T y. ~: C
- if($id > 0) 9 X+ u; g( ^& i- h- @
- { 2 H3 Z" H7 r! t
- --$id; 2 U" W) v b( Y! t/ Q. }1 K4 Z
- mysqli_query($conn , 'UPDATE a SET id='.$id); 7 W4 P+ A+ M" Q1 n
- }
( V8 z( _# l- a: u5 T4 k& K
( R4 m" w& ~: X- # mysql 解锁
- f- \: Q: Z7 l - mysqli_query($conn , 'UNLOCK TABLES');( x% K, {. h) R: e3 }
- //查询解锁后的id值6 U8 ?: \) L" i- V7 }) w) e
- // $res = mysqli_query($conn , 'SELECT id FROM ta');
/ v& n$ W0 a) G% ? - // while($row = mysqli_fetch_assoc($res))
: r7 D$ ^9 s4 D. W" ]/ O - // {
7 A7 f% g X2 B0 L) \; { - // $id = $row['id'];
) p6 ]( V4 b( h' `2 h - // }
3 |) E1 G j# S7 L0 T" @ - // echo $id;
复制代码 6 S* k9 z! n" Z/ {1 w9 c/ @" Z: s
- |, y" s+ O4 |( z& c* q1 N+ Y+ ?9 ^/ j+ @# h
PHP文件锁示例: - /*
$ t7 F6 c. y" R# R3 W( K0 ~- O - 模拟秒杀活动-- 商品100件
1 t( j! O# f" J% ~ - CREATE TABLE ta
9 x6 _% v8 k; t! B5 ~: d - (
! m$ f# a! e! B2 {! N5 ~/ w - id int comment '模拟100件活动商品的数量'
/ @( X! P) G! U( o7 J9 F) _: ~ - );
7 Z4 j1 Z Z+ V1 |2 S - INSERT INTO ta VALUES(100);" p! O3 R$ J" m7 @% T+ G8 ~
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件* u4 s+ p/ H' o+ `; I0 }/ p: B5 R' F! S
- */
( I a. X4 F% U; B# b -
6 j4 ]& s7 o- t5 u! F# V - // 关闭错误报告
: I% U. S: A+ R: l - error_reporting(0);
- g( y7 A! z* R& Y, N
a; W, z3 Q5 H1 g" N% x! a- $dbhost = 'localhost:3306'; // mysql服务器主机地址- \. a% s3 G% \4 Q2 r
- $dbuser = 'root'; // mysql用户名) z( |1 H# w# ~
- $dbpass = 'root'; // mysql用户名密码# a' { X0 H! k! U- }5 E1 u
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
5 u4 [4 c) y: x) L( z, A - if(! $conn )
) n9 h9 D W/ N ^$ s# S/ p - {
* O% K2 x; T. I7 v9 } - die('连接失败: ' . mysqli_error($conn));, ]+ E+ F s& X" i
- }
* @) Y0 b" x# w3 q. g) l - // 设置编码,防止中文乱码
. N- i$ A. n* g( I - mysqli_query($conn , "set names utf8");
6 a* S3 ]; T: V7 @* k8 C: ? - mysqli_select_db( $conn, 'temp' );
3 V1 n: L6 c; H8 R
# F1 R" O# f0 [2 F* b- # php中的文件锁
C) ?( C! c1 s. ^$ f - $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
% U2 Q: F5 | {% ^ - flock($fp, LOCK_EX);// 排他锁 9 h; [( R$ M' F4 G' x
- ' H' B2 W/ Z1 l
- $retval = mysqli_query($conn ,'SELECT id FROM ta');
- ?8 s, S. A7 _$ a# I4 y - while($row = mysqli_fetch_assoc($retval))! g9 t! |8 Z8 q' \% X6 X& I. D
- {1 B: O0 l" @9 S. W# E) T0 x
- $id = $row['id'];
" z( G2 r5 U4 A u - }2 p' q) C1 e7 ]9 E, t, r
-
/ K, ~. c2 L# L0 m2 J - if($id > 0)
6 [7 Y8 A' ^- C2 \ - { 5 o: y5 J5 I4 u& x- S+ U3 A! Q( y1 {
- --$id; / c& p; ~1 x% K) W
- mysqli_query($conn ,'UPDATE ta SET id='.$id);
+ u" u; ~2 f4 o# t2 |- v - } ' o& J0 D; m, K9 h
- # php的文件锁,释放锁 ! M$ U% G5 N. p1 Z, J
- flock($fp, LOCK_UN);
6 X: ?: s2 y( p - fclose($fp);* |. }6 q- ~( X* G9 R( ~/ R2 w* H
- 2 K& L' t3 ^0 D* c3 w i: @
- // $res = mysqli_query($conn , 'SELECT id FROM ta');
& c w5 G8 O! @6 J - // while($row = mysqli_fetch_assoc($res))
\4 j, t: ^9 b - // {
6 r; X9 ^1 S9 a9 O) b - // $id = $row['id'];
T" @/ s4 w( B' b7 [% K - // }" l9 x. V: \. l% C6 d
- // echo $id;
复制代码 - ^9 h, e5 A( |' |/ q* U
: q' d/ K$ I; {+ v& I7 D4 c
抢券活动实例: - public function envelopeSnatching(){
* ^# w7 B" P4 H2 k' o4 J- } - $lingqu = $_POST['type'];
; }4 Q) T7 S! M; ~ - $uid=session('u_id');//用户id
) f* O( u2 \$ R3 e# e - if(!$uid){
4 g% K5 d3 L: T+ f8 Q - $data['msg']='您没登录,请先登录!';1 G! `* A8 ?# q
- }else if(date('Y-m-d') != '2017-12-12'){
/ U2 i7 ?- a7 v& d: B& C - $data['msg']='不在活动时间内!';# {! M ]( {% ~* |# q8 G0 s
- }else{6 m6 D2 j! n$ y: i- d$ y5 B2 E+ A
- $hours=date('H');//当前小时数6 D" r7 W: r3 k: {- y) x
- if($hours > '09' || $hours > '17'){5 R9 h6 V, i1 G7 I8 X( ~: d& g
5 C8 O! K( h: L& v. e" D- if($lingqu == 1 || $lingqu ==2){//点击10点的, \7 P. C, h) B; a/ H
- if($lingqu == 1){
: U4 q9 _' |/ k" T/ \ - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过: I& p+ G/ g) |% C, O$ ^
- if($hours > '09'){6 k! u" K( p/ M* `
- $num=mt_rand(25,28);//优惠券金额
5 K: e/ f( I; ~: J - $id=1; F& L- O0 w# D" _# t: Z3 t! z3 O
- } M7 q# M" G: J) N2 ~
- }else if($lingqu == 2){
' h0 p4 T% O/ Z; d - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();2 e9 b/ R' E' [9 u3 q. |7 t7 w
- if($hours > '17'){
0 Y" l7 v4 s1 p3 l3 T! S - $num=mt_rand(50,55);//优惠券金额
' i# a$ M( ~/ ~- p: r& j - $id=2;
# J8 H1 T" O; O6 t9 ~ - }9 p, {- l/ @( A5 j
- }+ p, [# N. s3 H1 K
- if(!$id){# t" E, r1 k9 \% m: J
- $data['msg']='时间还没到,晚点再来吧。';# N$ k4 L( {$ A* {0 w
- }else{. h! h- v4 [, M1 ]! x
- if($is_lingqu){
5 ~: E( u! k9 K& w$ ?2 i# c; M - $data['msg']='你已经领取过了,留点给别人吧!'; v4 W3 I% Z5 w( P: _' @
- }else{
- G! m# |" M4 E - //锁表
3 Y0 \6 s; A* p' f; Z - M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
7 e1 D; d2 e ^0 a: j3 l - $active=M('active_num')->where(array('id'=>$id))->find();; a; S$ O u- P' ^
- if($active > 0){
- h/ z" S5 v/ m+ N8 i9 ?2 X) @3 z - //开启事务
1 ]$ d) Q7 l L# \ - M()->execute('start transaction');
' k; F, _6 ?3 p7 A" b. H - $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));5 D7 _4 ], D, O" q/ }+ r
- $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));6 q' Q2 ? Y( Q/ s& t, m/ c
- $members_preferential = M('members_preferential');
' x: M& v4 ~0 b) f5 u* Q - //对应投资金额,) B% `6 ?( m& _* S( q% Y1 A
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));5 K: A5 l/ v% Z/ t' L* C% N
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
. _- M$ `/ F! R; K1 n; ?3 O - $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间/ K0 w0 Y/ I! G$ {$ D" t
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
6 A* U5 ~* m% ~" P5 T, G! U# ] - if($save && $add && $add2){9 a! R! I k' d& a
- //事务提交
3 w# N0 L& D2 {6 \0 d. o/ w - M()->execute('commit');
! \9 W4 r+ `8 o; _" o4 l5 ] - $data['msg']='恭喜你领取了'.$num.'元优惠券';
7 N: P) c9 q$ q - }else{6 h; D0 ~, t* _( o( D
- //回滚" B! \: J) X2 Q0 L( n* H J' [
- M()->execute('rollback');$ F* s' k; \, Q, W8 X
- $data['msg']='未知错误!';
* _/ [# u0 u0 O3 n, n- S% V- c - }
9 ^ x+ ]1 s6 a+ U - }else{" U: p8 y3 g, }
- $data['msg']='红包已领完,你来晚了!';
; `( F$ S) h3 {; g - }9 W8 Z' y) m7 h
- M()->execute('UNLOCK TABLES');
( S+ v; K! y( x7 C0 D q, ^ - }4 m, N' P. c. f: g6 j+ t( L
- }. y/ @' C( _: ]5 X3 l' k
- }else{
* A2 K4 z5 g; K" w) E: v& ]. S - $data['msg']='非法操作!';7 u8 |& j1 N2 c4 `- Y
- }6 Q2 g1 X9 j4 d+ Z% |/ @) H
- }else{$ f( j" V0 Q& y- J4 z
- $data['msg']='还没有到活动时间,请晚点再来哟!!';. h$ N* ~) i' L# ]2 S
- }
) |$ y2 j; D2 n5 y9 i - }
: t9 G: H9 f2 G, C5 V/ Q, E2 ^ - exit(json_encode($data));4 e1 R8 k. ], V% g8 P
- }
复制代码 * `0 i6 M8 H( N$ m S5 X. w
- l! I' x' y7 D3 B
|