|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码 $ X* e" U" Y9 g
Mysql中的锁语法:8 s4 o* R9 H- t1 b2 A& k. j
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】: i! z& v4 [3 O" G, { j! @; i
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
4 R3 z% s h7 a9 l5 yWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
8 d1 J7 S: D- ^2 U% j8 l- M( h注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :
; Y" ?4 f. [3 y: V3 g文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。& _0 o7 U' q( I! v
测试时,有个文件就行,叫什么名无所谓 总结:4 x7 ~9 e& I: Y5 R0 {3 {8 S
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:; p$ N7 n1 s! i- f8 c( n8 T
1. 高并发下单时,减库存量时要加锁
0 M9 }- A1 [2 E ~2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*& U' v& D: @; p$ M7 M! I
- 模拟秒杀活动-- 商品100件9 c+ G7 _4 a: g. B5 U% q
- CREATE TABLE ta
2 L F! K/ V' e* |9 D3 e% o - (
. z. t& e3 _# s, L+ W( m - id int comment '模拟100件活动商品的数量'
: W& ~8 P* p% j5 T - );
8 L: S! [& d' Y' P r7 i - INSERT INTO ta VALUES(100);
5 Y7 I% u, w: U! r - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
6 `" {3 N7 ^. v* J0 V5 m1 F- ?' _ - */ " o/ k* l' v ]1 G: C. b: X. @
- " ?" @4 {+ \: e2 a4 I; X
- // 关闭错误报告
+ y" A" o( |7 K - error_reporting(0);
1 f# D* q/ [+ ^5 `6 \1 [ - 3 u9 y4 |7 w: T5 b
- $dbhost = 'localhost:3306'; // mysql服务器主机地址* K: q0 i- e/ [5 a" J
- $dbuser = 'root'; // mysql用户名/ ~) [$ Y8 B( M
- $dbpass = 'root'; // mysql用户名密码! L% t! g) s( K6 @6 H6 w
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);; D3 l" l6 b! L& H2 `# l, A. g- @
- if(! $conn )
) y. x' x9 n. b9 n' q& S# ] - {/ e! B r2 a5 \0 ?
- die('连接失败: ' . mysqli_error($conn));
9 `. e' h; n# m6 R% N - }3 g; j' e& e; |, f8 X0 x
- // 设置编码,防止中文乱码: V: ` f% a$ M+ v+ b% S. _
- mysqli_query($conn , "set names utf8");
4 c9 o3 z8 W. ~ - mysqli_select_db( $conn, 'temp' ); 4 {9 v% P& m- a1 J$ [; B) u
$ j5 S! e0 G# T- # mysql 锁
9 }' Z X- d0 K" ^5 I - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
7 B5 R# W( Y5 K9 [& R; ` - $rs = mysqli_query($conn , 'SELECT id FROM a');
: g4 b; J/ e) L - $id = mysqli_result($rs, 0, 0);
/ K# H8 j6 F& W$ B0 v, x* s1 R3 j& o - if($id > 0) 8 ?: `8 [9 o; w! W [( L( z
- { " J+ G6 K C% U1 @3 a
- --$id; / J9 p7 ~, Z3 \1 U& @) ^1 Z
- mysqli_query($conn , 'UPDATE a SET id='.$id);
" N5 x9 J* P& k3 H/ O - } ' H) }7 p. F( y# W7 Y1 l5 Z) W) T
- 2 S7 N7 {% G5 p; p- J
- # mysql 解锁
: G3 z& m) A9 X' `4 T# g - mysqli_query($conn , 'UNLOCK TABLES'); U. a( Z0 N8 ^6 H+ _" e
- //查询解锁后的id值/ Y4 z6 `2 E" H& ^# [% B
- // $res = mysqli_query($conn , 'SELECT id FROM ta');
8 `" Z5 b i( r0 v - // while($row = mysqli_fetch_assoc($res))- _; C' ?4 m! E- |. s( Q$ z9 B7 G
- // {+ j& z. h9 s/ I
- // $id = $row['id'];
8 {/ f1 h5 W/ y/ M3 G J - // }
: I, V4 M$ l7 J! J - // echo $id;
复制代码
5 |$ i/ Y0 P5 m9 C+ ]
8 K7 z& Y' ^1 N% n" V, N. j& h
* I- w# s) L( h9 h2 T ~PHP文件锁示例: - /*
+ ~9 y2 E. T. z, j - 模拟秒杀活动-- 商品100件
$ S8 G% g2 V% X5 T _2 t - CREATE TABLE ta! C7 z+ X9 M8 |' v3 w( L0 l
- (" ?# @8 K" n. D( {
- id int comment '模拟100件活动商品的数量'
+ V5 u$ b" S0 f - );7 P; a+ o, w7 c2 |. k4 X# D; z: M
- INSERT INTO ta VALUES(100);; \% V4 u8 W% n6 y0 p' b, z
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件- a1 t( O8 H/ H8 j
- */
- @# {5 ]" }3 T. F6 m' w: b -
0 A0 Z# w, a4 h; T, C - // 关闭错误报告0 b* e+ c. p' L b" N2 g* ~2 W
- error_reporting(0);
8 J4 k( q1 x( Z3 N7 ?
6 C A, D2 N3 [+ m' ~- $dbhost = 'localhost:3306'; // mysql服务器主机地址6 B! b; H; R; d8 x1 ?6 s. W; j0 [: d
- $dbuser = 'root'; // mysql用户名
/ V; a" a( ]4 [( s5 ? - $dbpass = 'root'; // mysql用户名密码6 C# H* y N" e
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);1 W! l6 p8 A e8 z+ @; d
- if(! $conn )# W+ q( B* R! \3 N2 }2 g
- {
9 }, i* ~* ^0 u" @3 [' `3 j - die('连接失败: ' . mysqli_error($conn));
" a: {% e/ |, o, H2 y) O9 O4 ^( c' ?% S - }2 B7 ?& [& m1 m- {8 R+ X6 _$ @: |
- // 设置编码,防止中文乱码" e D8 `+ V: W8 p
- mysqli_query($conn , "set names utf8");: v' ]+ I5 l0 K2 K9 i [/ Z; Z
- mysqli_select_db( $conn, 'temp' ); . R; ~2 Z1 v5 i& O8 J* o
- 9 U0 ?" [. u7 O) u0 F( a5 p# g
- # php中的文件锁 1 L, i1 s8 ^) u$ o( E
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
/ ~3 T+ F k- R+ h - flock($fp, LOCK_EX);// 排他锁
: q/ y* L. ]* I' j5 q7 h6 e
: V4 Z; z& [; b0 ~4 K% t- $retval = mysqli_query($conn ,'SELECT id FROM ta'); + I! [0 a ~( I& `2 ]
- while($row = mysqli_fetch_assoc($retval))* \4 r, A3 [" @- P m& d* s
- {" }+ c/ o- [% O* [; A
- $id = $row['id'];% V5 L" [3 L5 G1 \
- }6 w% E' q* V s6 F; ~$ s* _
- , P" M' Y6 T% ^% O: I+ N1 g3 e. t
- if($id > 0)
, a% H: q; g/ f; K - {
_( d& x% b2 C& q; ? - --$id; 7 u/ q( J5 n$ @/ M V
- mysqli_query($conn ,'UPDATE ta SET id='.$id); 7 b5 k5 L+ [; e4 q6 v* U: X/ {
- }
9 ?' O. R! X8 ~2 I# N5 ^ - # php的文件锁,释放锁
0 E) i0 }* r* V1 _( t! [ - flock($fp, LOCK_UN); : c- D9 l4 z+ c, Q$ U5 t
- fclose($fp);
% Q' A8 i( w* x: a - + L3 g$ G; h, B/ [ [) c4 f, n- w
- // $res = mysqli_query($conn , 'SELECT id FROM ta');
5 k1 v+ }. Y9 f - // while($row = mysqli_fetch_assoc($res)). k/ E7 }' n1 _& A2 o( ~
- // {- l5 {0 `3 p9 c% e0 J s: w p
- // $id = $row['id'];
- x2 y1 P/ t; N } U: o' U1 K - // }
1 f4 V/ q0 ~! f: @! O: F - // echo $id;
复制代码 6 ~' w1 V7 M" X! N8 j
* L$ H J# u# H- P* P0 O; p抢券活动实例: - public function envelopeSnatching(){
# C9 x% D& p- f/ N - $lingqu = $_POST['type'];
7 p/ I$ a: u2 @5 @8 [, B! c - $uid=session('u_id');//用户id
. M% \2 C$ o5 b3 k) i: {! A* q - if(!$uid){
% \/ h+ K# {; q! m1 P5 H - $data['msg']='您没登录,请先登录!';
# K) D+ Q2 f3 w- R4 A1 j - }else if(date('Y-m-d') != '2017-12-12'){# {; f) G7 G- \
- $data['msg']='不在活动时间内!';
% ^8 l; @: s2 u. U+ S - }else{
- y5 R& F6 [( `8 M+ K/ A - $hours=date('H');//当前小时数
5 n3 v0 G' ]# h- { - if($hours > '09' || $hours > '17'){- K1 M1 B, W* C4 K' p' ?
- ; O" J- F# f) n. m; `1 M
- if($lingqu == 1 || $lingqu ==2){//点击10点的
& q3 S8 b; X" J! ]/ F J6 B: F - if($lingqu == 1){3 w0 b/ U! `* |2 B# h. P8 J6 r
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过& d, m; U- ~3 Q' \0 E
- if($hours > '09'){ F/ K" i) h( ^$ t
- $num=mt_rand(25,28);//优惠券金额
2 ~0 ~& S" E' D6 R% U - $id=1;2 |) ^, w; E* h5 K
- }5 _3 _% t% |- Y r- v
- }else if($lingqu == 2){2 ?" d0 _3 q' N) o& i* ]
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
0 {9 j3 A& v/ E1 ~8 { - if($hours > '17'){ c5 M1 w: b8 K3 }, [1 J; m
- $num=mt_rand(50,55);//优惠券金额
! G% X0 l# F8 }/ y8 ?. H - $id=2;1 a% q" k' a X# p9 P
- }1 F" J% U# v( \; d
- }
9 A! a% y# A/ u+ `, d4 p - if(!$id){
|) i2 }4 w1 w `7 K; O - $data['msg']='时间还没到,晚点再来吧。';
. ?" G: |' l5 _ - }else{# I5 Y; w0 f0 H5 A
- if($is_lingqu){! v7 Y, v. c( |1 u& D4 i* R$ r$ i
- $data['msg']='你已经领取过了,留点给别人吧!';6 @/ |6 `1 Q+ P4 S9 w
- }else{5 d+ M, i% u% E. V7 u
- //锁表" z s O {1 n9 e
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
# Z. o9 d+ q6 T5 a" a - $active=M('active_num')->where(array('id'=>$id))->find();
7 t9 }7 |( h. i& {/ j) i; A5 } - if($active > 0){; B# a5 M2 w4 i! X4 O8 X& z, [
- //开启事务0 p0 S# M) K1 ~
- M()->execute('start transaction');
9 e1 o/ i' c& `9 t - $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
5 U! \+ {) D; d1 R - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
. B" |0 B2 v/ e9 @ - $members_preferential = M('members_preferential');, t# S8 y+ X9 ~; W- s5 u. |
- //对应投资金额,7 _0 C$ L8 r& [" V
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));, d Z$ |" d! A
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');4 k5 U. C8 o5 L$ M( J
- $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间% B0 f0 u8 v$ j- h2 k
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券- I" q* f, y- d
- if($save && $add && $add2){
' i4 j% x" o/ C5 { - //事务提交
: D: d7 K9 U8 c1 I7 u - M()->execute('commit');
8 W: h% ^# y" O) R) I* H+ ^ - $data['msg']='恭喜你领取了'.$num.'元优惠券';3 V8 r O! K* N; ]
- }else{
" q- ~* l- V) r! z) c P - //回滚: |5 H6 Y3 b0 w- o7 l* \
- M()->execute('rollback');9 p: X+ G9 ^5 l; X5 [1 k. n
- $data['msg']='未知错误!';0 q8 e3 \3 U0 o) @* I, z& n' h8 d
- }
) z7 j" }7 e6 r' F1 [ n& G9 I/ R+ { - }else{
+ @' u/ [( `5 I! _ - $data['msg']='红包已领完,你来晚了!';# `$ m+ y- `5 l. C9 c+ M
- }
- ^ i/ z Y/ m. X9 n9 k, d$ v - M()->execute('UNLOCK TABLES');3 x4 O, z$ j& d; `) x$ n' [+ }
- }$ c) r: q7 t- ^9 H
- }2 ~: r6 m' ]8 d( a
- }else{
( |& i8 S5 R# v - $data['msg']='非法操作!';% P/ A2 h, N+ {
- }
4 D/ E4 N% m9 b; D" S8 l5 { - }else{
; @. O4 _" p5 ]* B" W( B% x! s1 t; C - $data['msg']='还没有到活动时间,请晚点再来哟!!';
: I5 k# R+ P' u% L' x) t - }( k8 e. H0 L; ?+ E
- }
0 |3 m. m. b5 h3 b$ l - exit(json_encode($data));
8 Y M3 s+ _6 w - }
复制代码 ' |3 T* W9 D ^/ V& h% @
W8 O8 v4 X+ J4 K9 W7 z
|