|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码 7 S3 Z- a$ ^" I% j( ?' N
Mysql中的锁语法:) V9 ]% i* ~ F4 I: e* A
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】, p5 H7 a# C9 O& i E$ ^' x4 U
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表" V# l! P; Z0 D! E+ H
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
$ @. A' Y3 _2 n- [7 H注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :
0 Y# c) G9 T2 I' T9 P5 _8 N文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
! t6 J1 Y( q9 ~3 B; q/ _* L: a测试时,有个文件就行,叫什么名无所谓 总结:
* C# L; |) d5 \2 D7 |项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景: K) Q% O9 l# |
1. 高并发下单时,减库存量时要加锁0 V9 I$ z5 S! F4 W
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*
6 X8 h _) D5 H O - 模拟秒杀活动-- 商品100件
4 `+ Y( s d) l1 l/ l2 P8 ~1 S3 m3 B - CREATE TABLE ta1 c. K. ?1 L4 O" g1 Y% Z8 s
- (4 ^; e4 v c! k, _3 S" M. g
- id int comment '模拟100件活动商品的数量'
N" R; @' l0 @$ l - );
- t) d ^' u$ }7 r - INSERT INTO ta VALUES(100);
& L* ]4 d) \& N1 q - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
5 i# T8 D ~) l8 N6 d. ] - */
" e, `$ k: ~" } - Y* ?7 d; ^- i% x$ c4 m" F
- // 关闭错误报告& F9 W _" V) x1 e. z a: l6 X% \
- error_reporting(0); % ^' ]: n2 X- i# h$ h1 F" T, o1 a
- b8 L+ y# Y! `6 @. o; o6 j
- $dbhost = 'localhost:3306'; // mysql服务器主机地址( _$ ^4 L/ i/ g' U- O' i
- $dbuser = 'root'; // mysql用户名 `* P1 c( w" {) D6 k @" f
- $dbpass = 'root'; // mysql用户名密码: K& O2 X( U3 M' `
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
; G2 R, Y7 s, Q# d5 j3 n* {/ R0 m - if(! $conn )( u/ h, ?/ `; L' f
- {5 s' G% _4 K- x1 ]( M% g
- die('连接失败: ' . mysqli_error($conn)); h2 l9 a8 p2 K5 z! @
- }
4 P) _; C1 t/ s) ^9 _1 f - // 设置编码,防止中文乱码2 z1 V: m& G# `8 {0 q6 m
- mysqli_query($conn , "set names utf8");
" o) r0 g* ^1 T4 B" Q% j* J. E& d - mysqli_select_db( $conn, 'temp' ); % [" b7 e( R% m' I- r% i
. X. d- R# ^/ v. R% c4 v5 a0 g- s- # mysql 锁
/ ?- A4 Z! b2 i - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
, p8 ^7 y, ` k - $rs = mysqli_query($conn , 'SELECT id FROM a'); 8 U+ x- d8 v3 ~# o( `- \
- $id = mysqli_result($rs, 0, 0); # o/ k7 S) J) }( d8 @
- if($id > 0)
; m- R3 G/ d" g$ E* V6 V. A - {
N1 ~2 G; ^5 q8 l# k/ r6 a# B - --$id;
* B& Q$ h6 J( X% z; M9 | - mysqli_query($conn , 'UPDATE a SET id='.$id);
$ F a+ Y" S/ \- }/ P" |1 S, w3 N - } 4 Q, x! S( u/ v" ?
- * z) J: v3 p+ C$ A
- # mysql 解锁
& {4 a6 s, J/ z+ d& l# G, c; }& \ - mysqli_query($conn , 'UNLOCK TABLES');0 w: k7 [' d3 f2 T. _
- //查询解锁后的id值
7 j2 k# d: x8 Y) P7 D9 Q - // $res = mysqli_query($conn , 'SELECT id FROM ta');
3 C* D. z4 C% {4 j6 M7 ~: T" ~ - // while($row = mysqli_fetch_assoc($res))' q- `2 L, U2 o" a; m) E
- // {, L' R3 `, W2 S% b
- // $id = $row['id'];
1 |- _2 C8 o( c9 y) e - // }1 ]# k$ K& R' S; t2 k- R0 @
- // echo $id;
复制代码 : D5 O' X' s- p( x
. G7 q- U% @: l' _4 X$ S3 W
* u9 C: T. t. v' ?* q+ d6 CPHP文件锁示例: - /*
; |! c3 V, {1 A - 模拟秒杀活动-- 商品100件5 b2 B* A. J1 ^3 b' `9 s
- CREATE TABLE ta
# |6 c1 `$ D# e3 O) Y6 _ - (
6 E/ q9 H9 X; n$ | - id int comment '模拟100件活动商品的数量'
- J$ J* s2 {' [5 w! b - );
2 {9 i; W1 x) Y9 c - INSERT INTO ta VALUES(100);7 A4 R: `3 z# G4 @3 S. R
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件 h2 w* Q! _: B+ A( ~
- */ : D; o) i5 _0 K- F7 c v: p" }
- 2 ~6 N# r7 a3 s
- // 关闭错误报告2 B6 a( O0 }9 \- ]
- error_reporting(0);
. ^; }9 H* x/ ?7 S* ^& E, s - 8 Q/ B" X7 F. ~/ h: c9 H7 O3 y
- $dbhost = 'localhost:3306'; // mysql服务器主机地址
4 o" W) y, f/ H8 D4 t - $dbuser = 'root'; // mysql用户名
* ?- C, T' J+ _* x: ~$ x$ i - $dbpass = 'root'; // mysql用户名密码7 J' }( D, p* D/ M, Y
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);6 X( F* t7 W. A' G3 }; |; l
- if(! $conn )3 H, d0 L8 T6 l: F$ ~
- {+ J" J5 ^; d4 ?' a+ A
- die('连接失败: ' . mysqli_error($conn));2 C) r, h( \* M; w
- }3 @5 C$ `3 N* O" }) P( E
- // 设置编码,防止中文乱码
0 y9 I5 |* E r: m8 T' q - mysqli_query($conn , "set names utf8");7 ~$ d+ ~3 J* U/ _7 q, h. i: X& U
- mysqli_select_db( $conn, 'temp' ); 4 N% F' ~: t; l) {2 W" L, U
- t3 W0 V# T' m/ R% B& n3 |: t* U
- # php中的文件锁
4 ^+ t% v7 M7 M z - $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 , f! B7 u& U2 Y, D: s
- flock($fp, LOCK_EX);// 排他锁 $ D* q( |3 I/ n, r4 p+ ]# @) Q/ b
- % ?: ^( i, _7 f
- $retval = mysqli_query($conn ,'SELECT id FROM ta');
- k& S0 f) c1 D4 b - while($row = mysqli_fetch_assoc($retval))
& J3 J( `/ Z; q - {& ^7 L, D7 t( v# O
- $id = $row['id'];0 q4 x, F$ c& P, _7 p! s
- }
. ~! A1 Q" k( F5 z4 x - ( i, }, j- n" g z" m! a
- if($id > 0) ! i- q2 A2 p& L& `& Q
- { 7 f6 c+ M8 O, v( y/ f
- --$id;
0 x* ^5 B' s l& q$ K9 \ - mysqli_query($conn ,'UPDATE ta SET id='.$id); 5 l6 B3 I( Y. {; Y- \5 }! s
- } 1 D0 P# Y9 ]7 F2 ?* S
- # php的文件锁,释放锁
! } C$ g. q% d5 `$ _0 y - flock($fp, LOCK_UN); ( a+ F( o2 {, [* y( c
- fclose($fp);; K, |5 \; i! G0 T' F4 Z+ r
- 9 e0 B' S5 S- q9 r6 ]4 i) r2 c/ i
- // $res = mysqli_query($conn , 'SELECT id FROM ta');8 l7 M7 |2 N* ~& s* S
- // while($row = mysqli_fetch_assoc($res))
6 ]! B) C, Q8 l2 D* f7 D# v5 f4 @ - // {
: Q0 K; ?; i: l2 `$ T* y - // $id = $row['id'];% S4 q; o1 a& l1 {
- // }
- ?% J; f2 J6 j - // echo $id;
复制代码 ) D Q$ J; g/ t9 F9 a3 {
1 h5 W$ i- f# a; K6 w: L抢券活动实例: - public function envelopeSnatching(){
. w+ d$ B) C. @+ ~ - $lingqu = $_POST['type'];- ]4 u) I( ]9 g Q8 O6 E+ c
- $uid=session('u_id');//用户id
k" r& z3 v/ [* P( C( t - if(!$uid){
; _: @: h) M: k- M0 k. J - $data['msg']='您没登录,请先登录!';
' B7 {, b; R7 j' T - }else if(date('Y-m-d') != '2017-12-12'){
- c+ X8 u( c$ m. a9 c - $data['msg']='不在活动时间内!';( z3 b9 w0 f3 C; q' T' J
- }else{
2 R6 a4 ?& q; T( L - $hours=date('H');//当前小时数5 ~" J. H! |+ e( [& C3 l
- if($hours > '09' || $hours > '17'){' l) t0 ]/ ]# R d
- - N) b" q) N; s8 [
- if($lingqu == 1 || $lingqu ==2){//点击10点的
# }* Y# ~) ]) K: q - if($lingqu == 1){1 _1 S& |, j1 k/ t# b' X- Q8 I
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
% e, |8 \6 B( u$ C: E/ U% U - if($hours > '09'){
, n) f- w# k7 s+ |+ l4 k& ] - $num=mt_rand(25,28);//优惠券金额
( y0 X. E3 y" h6 h3 g - $id=1;
( b8 D' L2 q7 [; `0 f& b - }% D# e1 Y; W! D! a
- }else if($lingqu == 2){) S6 Z! W* A- u$ D k6 f
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();# u) o6 l% D6 p* v
- if($hours > '17'){9 u/ j( y& r" y4 ?6 @
- $num=mt_rand(50,55);//优惠券金额
5 @$ r8 p" O2 [ V# E. V. | - $id=2;
7 g3 v7 ^7 ], ]: g: @+ r - }, ?: W! l5 T9 @- z0 Y8 q
- }
{5 O4 q t& V0 u" V. d* t - if(!$id){% V9 e: P- P5 Q. A
- $data['msg']='时间还没到,晚点再来吧。';
2 D/ A4 K" O Q7 _$ l, a; } - }else{
* l6 f' b: i, U# p - if($is_lingqu){
/ d. p, ?+ S+ N0 u4 I% ^ - $data['msg']='你已经领取过了,留点给别人吧!';! W7 z; p5 t- I5 x3 n0 d
- }else{
; @0 h/ G3 A& ]8 ~( a - //锁表
2 Q) [& N# \& ~: R d - M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
5 a1 E, i0 f" M0 W6 K2 d - $active=M('active_num')->where(array('id'=>$id))->find();
% ^! g( @" q6 p; v: ^3 b0 e" y - if($active > 0){. `- A) S4 Q2 y* U
- //开启事务
4 t8 a2 r- U& Y# t" J1 A - M()->execute('start transaction');
$ N1 d: p8 j: A - $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
) M, {6 x8 f1 E - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
7 A9 }. c" I! ~ ^7 \8 i; r - $members_preferential = M('members_preferential');
4 ]$ i/ ~: W' T% t |; \. C* ~% p - //对应投资金额,/ T1 q* v. \! ^2 `- @ \; C7 o
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));# A3 f, X) F8 e5 E
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');. P `7 X5 J9 I" n
- $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间) P5 q5 w& K j& Y8 J9 e
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
a2 b0 P' x. x6 C - if($save && $add && $add2){
. W; X3 i0 W1 D+ x2 t& m/ P7 |2 C2 I - //事务提交
; m" y9 q" D5 H3 Y. E# Z - M()->execute('commit');
/ p* |' l3 M0 R: n0 t; t - $data['msg']='恭喜你领取了'.$num.'元优惠券';
# Q' Q! l) c3 z8 _2 L% q* K) m - }else{" _4 p( |' ^0 p* t& A
- //回滚
* `) ^& I# I+ ], m - M()->execute('rollback');
. g4 s f2 w6 h" p ^( ?7 r - $data['msg']='未知错误!';
- D& Z& |/ x F$ R: [ - }
& q V" Q% c" ?; o - }else{
! w5 Q/ Z5 z7 \( G3 N# o- Q' e - $data['msg']='红包已领完,你来晚了!';
) P( j& f, N8 c - }
) \: v9 n$ B% h+ d& J) `+ p - M()->execute('UNLOCK TABLES');% ?& D* B' s, F" P
- }; j' V! N5 f" M# |. {) q. t7 Y- m
- }
9 ~' S- R: G1 ?: G# z9 K+ z - }else{5 ^4 n( B. L: Y/ }
- $data['msg']='非法操作!';
) {8 t- Z S. h1 _3 J7 [, M - }9 x7 {: D# {: o# X
- }else{
) e6 R9 c0 h, T, I# F/ t9 \ - $data['msg']='还没有到活动时间,请晚点再来哟!!';
' B8 u5 u! v* { - }& m# C# y5 N! B& i1 v3 ^- P
- }
) v7 F5 w% H& h; h - exit(json_encode($data));% }! `- p9 ~- `7 z# ]
- }
复制代码 # d W; u" {$ P+ o
, y( w4 }4 _- e5 d. ^" y# V: i( f
|