|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
5 }8 x: b) W. [$ m) h4 d) n0 KMysql中的锁语法:
! W: q2 {( o/ n2 qLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
6 {6 c6 f; e) y) HUNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
- E. h9 o4 C: A" hWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
& \0 z$ P7 c5 M+ t( p; z; O( d注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :: j& q. c) }, A+ T9 s$ @3 K
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
6 {6 s. X H& m; i测试时,有个文件就行,叫什么名无所谓 总结:
$ z1 C4 Z. c, W+ C项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
0 m4 F, D7 ]0 W6 B9 U9 |) \* W/ S1. 高并发下单时,减库存量时要加锁% [7 M0 ^# Q# p6 k% B
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*/ r, J% U( [& y
- 模拟秒杀活动-- 商品100件
& F. C2 v0 L! Y! K$ d8 [5 ` - CREATE TABLE ta
2 B$ ?# |; A& `0 ~/ m2 l& @) ] - ( g1 x- P/ ]4 w- }9 F% S
- id int comment '模拟100件活动商品的数量'7 ~9 h( ]6 ^9 Y! y9 W. r
- );
7 g2 A# a- t: V+ p- q - INSERT INTO ta VALUES(100); m/ W, x, e* ^0 @$ i
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
! n1 W2 V `% i) w: C& J/ d8 `) [ - */ * @* s# Q% {. F
- % v$ o7 e3 F& O+ j5 a% i
- // 关闭错误报告1 L$ G+ L5 }3 `; q7 R4 n
- error_reporting(0); / U- ~# h8 R i. ^3 z9 t
- : I% ^: h# R9 ` P
- $dbhost = 'localhost:3306'; // mysql服务器主机地址
% z. y1 J+ F' V8 @% D: j - $dbuser = 'root'; // mysql用户名! F8 I& o& o8 h) M" L
- $dbpass = 'root'; // mysql用户名密码
; M# A; W( k3 B/ J2 S; _ - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);1 l, ~' o' y, t
- if(! $conn )
& l5 ?& e9 b" }& Y7 B: G - {) @8 \ e0 U* ^: ^7 d
- die('连接失败: ' . mysqli_error($conn));
9 A3 j. s- ?3 _ - }
! p* }9 I$ d- W$ b1 g/ v - // 设置编码,防止中文乱码8 c2 u1 W. j+ C L, M- L6 c/ k o
- mysqli_query($conn , "set names utf8");; h1 _9 d! Y1 J$ q
- mysqli_select_db( $conn, 'temp' );
, G: n3 u$ a- \& B
& N- Z# H* a8 }# Z4 Y- # mysql 锁
* K& d5 R3 S: w4 z" Y - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
' U$ {7 s# ^* ?6 Q - $rs = mysqli_query($conn , 'SELECT id FROM a');
; p: d8 k2 p6 ^0 X0 O - $id = mysqli_result($rs, 0, 0); ( i3 k2 [5 A% Y+ v5 S8 \% c
- if($id > 0)
( X% I6 ~% K( \9 V+ l# y: ] - { ' J8 c' n* [! X: P" E) `
- --$id; N- v9 V, d* Q. U+ F
- mysqli_query($conn , 'UPDATE a SET id='.$id);
% i6 Z' C* \) J/ y4 g5 T- H - }
1 i4 v" c1 o4 V
! d0 C6 V# Z0 R- h- # mysql 解锁 . G- b' `" B0 t* E# n
- mysqli_query($conn , 'UNLOCK TABLES'); g. }5 s8 F$ m# X8 [. ]# }
- //查询解锁后的id值+ d* j4 I+ E6 t5 T& C+ W* M
- // $res = mysqli_query($conn , 'SELECT id FROM ta');6 U4 v# Z0 j( T# ~
- // while($row = mysqli_fetch_assoc($res))# l* q1 X$ e1 [6 e
- // {: ]3 L( o7 ^# e$ ]
- // $id = $row['id'];1 `# A* a2 i/ F. u9 t6 \: S
- // }* Z' c( E# {$ Z, y+ B! R/ S
- // echo $id;
复制代码
g5 ^/ g6 `) W% @" }, I0 c: Z7 U x0 C/ z
! s+ b# U4 v- o& Y) W
PHP文件锁示例: - /*
' n. K/ S9 ~. y! [4 n: p - 模拟秒杀活动-- 商品100件
4 X' J! x2 p' N8 ?; c0 j - CREATE TABLE ta5 M4 T3 \4 _, \0 m' U& c/ v) T
- (
" b$ O/ r) @: {& o - id int comment '模拟100件活动商品的数量'6 g+ ?" r4 T, w) _: I C; U) [0 T
- );( G3 C S5 X. G2 S3 P
- INSERT INTO ta VALUES(100);
. \/ x/ k! X' p+ o& X- n B - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
3 u$ [$ ^( ]& f, j% h - */
b0 |, u8 a6 A( `- g -
6 y( u! Z8 B: r - // 关闭错误报告8 {! x) }9 y$ H& u3 `
- error_reporting(0);
/ W# W" w+ X0 _! v* g - 3 B! \* X4 x# u8 F' U- L# a
- $dbhost = 'localhost:3306'; // mysql服务器主机地址( N! @* e% W. E7 k, C0 v( b
- $dbuser = 'root'; // mysql用户名3 M0 I" E- P7 W8 A
- $dbpass = 'root'; // mysql用户名密码
- a- |( Y/ \% o# t. }( k* B - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);& }* {) M: W8 e
- if(! $conn )
+ Y0 N/ E- H/ ~ - {
9 v# |' \, I2 @/ o - die('连接失败: ' . mysqli_error($conn));
5 B( ?+ ?; z( t d- } - }
. n, E, N, e& T# ] - // 设置编码,防止中文乱码. |' L3 j; k5 u' {+ A
- mysqli_query($conn , "set names utf8");* M) a$ ^! J: E$ P; v: H
- mysqli_select_db( $conn, 'temp' );
: a% _3 O, ^0 l% Q - 8 X1 l3 [: }8 k# C8 d
- # php中的文件锁
1 d* t6 ]' W# ^' D: ~) ? i) H+ [ - $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 * l$ j2 W' K& G
- flock($fp, LOCK_EX);// 排他锁 ( F/ J6 G9 i! O. H8 h
- - N1 L9 x! t( I7 h
- $retval = mysqli_query($conn ,'SELECT id FROM ta'); 2 r: ~) a3 E/ u7 E# Q
- while($row = mysqli_fetch_assoc($retval))
! z, }) X+ t' m - {& s! b: z% r& i
- $id = $row['id'];
7 s5 i m5 y5 Q - }, J5 p; Q1 q( O; W' h0 b1 @5 v1 M
- + h5 S- v, O9 l d
- if($id > 0) # A C* N. V9 {9 |: l
- {
/ F7 R6 k6 u- ? u3 I6 U - --$id;
1 B/ x% g8 u( Y( h - mysqli_query($conn ,'UPDATE ta SET id='.$id);
/ X2 m: W( W6 v- x+ F/ w - } $ F/ y4 V0 K1 N. l7 ]% Q9 D- Z
- # php的文件锁,释放锁
5 m- P# a7 a/ Y5 e2 T/ j6 | - flock($fp, LOCK_UN); 5 j! {/ @# R1 B3 [' v0 A
- fclose($fp);* x0 j6 F; ]% ~& T
. x7 b$ @! n! \- W- // $res = mysqli_query($conn , 'SELECT id FROM ta');( A' Q, e# q$ B/ U& m/ q
- // while($row = mysqli_fetch_assoc($res))
% ^0 m3 X5 b! P. Y2 R/ L9 w - // {6 X6 E$ R, |2 R
- // $id = $row['id'];
5 {- L9 i9 K1 K/ ?+ d7 O8 W1 k/ j - // }
. @- R& c' b% Z& F c$ B - // echo $id;
复制代码
* A, \1 J3 E& _6 r9 S$ Y+ S1 `- Y8 R+ | z7 T5 F4 Y
抢券活动实例: - public function envelopeSnatching(){' B# B* M8 `0 X. I+ H3 T
- $lingqu = $_POST['type'];0 r& v- \2 z' Z, K, j
- $uid=session('u_id');//用户id
8 ?: ~, c) a. X; X( u- F9 _4 i - if(!$uid){
- J5 K# y- Z0 x" |, p - $data['msg']='您没登录,请先登录!';( x4 K0 g* @5 ~9 t
- }else if(date('Y-m-d') != '2017-12-12'){
( W4 H7 |' j6 `+ d2 P3 c - $data['msg']='不在活动时间内!';
$ Y8 _! _6 M' [& V* D1 e7 I - }else{4 D" F u$ }1 m7 A* _8 e7 R
- $hours=date('H');//当前小时数/ l8 i' }1 k1 ?" C' G
- if($hours > '09' || $hours > '17'){
) k. H: e1 O: d' t0 S
+ m U& y+ h, R3 |6 W- if($lingqu == 1 || $lingqu ==2){//点击10点的5 h+ K6 Z0 R& S3 ~% R# n ^
- if($lingqu == 1){' y8 @1 k% I+ D
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过 ^7 F! H. [2 M' E6 y/ u/ J
- if($hours > '09'){) I7 Q+ @$ J$ G% k$ i/ N1 W6 M
- $num=mt_rand(25,28);//优惠券金额
: u7 f7 K- j9 _ W Z - $id=1;2 o0 L4 m5 o" i
- }; a: g8 \4 p( b% Z+ C8 _4 ?
- }else if($lingqu == 2){& y( U* M3 [% {6 K
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();; V% D. J6 `. E9 x) a5 l) ^+ @
- if($hours > '17'){
7 T# Q. Q7 M* @2 F - $num=mt_rand(50,55);//优惠券金额
; L3 d' Q- ~$ n - $id=2;% ` S) I0 z- C- n
- }# L( o3 J' O- M+ z1 O( n
- }8 b g1 p Z* q% a
- if(!$id){
) y; k" S( V* M3 G9 O - $data['msg']='时间还没到,晚点再来吧。';" f5 p i8 {& H+ M1 m
- }else{
: O2 v/ c% ~- P$ p& _4 Q4 W6 d) Q& l - if($is_lingqu){' `4 k2 x) I- v' E( Z( G5 r5 W4 q5 Y
- $data['msg']='你已经领取过了,留点给别人吧!';
. N0 E A F3 |% [; C l - }else{
7 \- z! b# z2 s6 s, Y - //锁表
7 C/ k3 B% D- w- Y7 s! y - M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');0 D/ D! A2 E1 @. W4 t" r. } Z Q) U
- $active=M('active_num')->where(array('id'=>$id))->find();
3 |; }* z% I' ` S. u7 J( h" a - if($active > 0){4 ?; z* s3 N% M* U! `1 h4 m R
- //开启事务
# }) r, }- z) J8 _# C6 v - M()->execute('start transaction');. N2 {1 i9 r2 Y. M! n& k
- $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
# S9 Q7 i8 Y/ g. t - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
1 l; v3 ~; |+ H1 Y( G/ c - $members_preferential = M('members_preferential'); f. H5 |. t8 o& i5 v0 t& U$ P
- //对应投资金额,
7 o3 L( s+ w% P( a9 v - $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true)); I- K/ C5 v* J8 h5 A* _; K- o
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
& X4 l$ M e: B- k; G - $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间# v, e* p" K1 P4 u! b
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券$ R9 x0 @ g4 s2 X7 k# x4 L
- if($save && $add && $add2){: V7 U6 c" O1 _ g
- //事务提交
3 V5 B: p9 X. u1 t9 ?$ I. w# u - M()->execute('commit');9 V) B/ c& e# G4 q* V
- $data['msg']='恭喜你领取了'.$num.'元优惠券';' i5 b B5 M, E9 N% K b
- }else{
8 h* n# d0 l9 S+ e - //回滚% G3 q; b1 L) e q7 i
- M()->execute('rollback');
" J9 m( [# ]/ C: Z$ z+ J - $data['msg']='未知错误!';
+ A7 N/ i Z1 {# Y% q8 Z - }
$ [* o0 a; L7 {) s0 e7 z* }/ Q - }else{
) T1 h3 _, r: j2 [" r* q7 B - $data['msg']='红包已领完,你来晚了!';
) }, s2 s) l: j( F. i, | - }
! ~5 g: Y4 p( C8 |7 A - M()->execute('UNLOCK TABLES');) N- t5 A/ N( I; T
- }
: f9 E4 l+ u* R5 ] - }) M z } R0 F$ v: k# `
- }else{# N: @+ ]3 g- l# \
- $data['msg']='非法操作!';' [/ D) ], @, N# F: W
- }+ O1 k* B5 M& O* m1 d
- }else{
. K: W$ }1 M" B8 E- Z& I - $data['msg']='还没有到活动时间,请晚点再来哟!!';) N* O- ^. z0 [! f. V
- }
7 j: i% h9 R+ v* Z- K- `6 a( a/ Z - }' y6 v4 x5 S) |
- exit(json_encode($data));
( h. }8 k$ E$ y) H$ {- Q$ A - }
复制代码
/ g- c* {7 D* | r' z- F. g# e7 T' k% B2 S, o
|