模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
5 D6 n7 B- @) y1 N% |8 o) MMysql中的锁语法:
5 x; E4 ~! s9 n& W v" R4 OLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
5 v9 p( X5 Z. N7 h' K& G0 |0 QUNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表- }2 F7 I+ ?9 e& V/ k4 S
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
; f+ V9 P6 u7 P& e9 X注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :
% [' [2 z Z8 |/ h文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。* y% x2 E0 \ t* Q" E3 O5 p/ [
测试时,有个文件就行,叫什么名无所谓 总结:
* a, ^- k- Z7 L: R项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
7 P" S5 U" J. s2 p! h! z1. 高并发下单时,减库存量时要加锁9 o% T& ]+ n' n% b j
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*0 v. X# v: ?6 ~) D- B9 M
- 模拟秒杀活动-- 商品100件
8 [" v- s E/ I' [8 r - CREATE TABLE ta! }" q" F3 B& f+ g3 k! |" n! \
- (
: |' u& T0 w/ g* V4 ~) ^$ _! Z/ [ - id int comment '模拟100件活动商品的数量'
3 C: {. c- f: ]$ }, A - );
! H" R& c, ]$ U! x - INSERT INTO ta VALUES(100);
+ H! X5 F6 H V$ f: ~9 W E - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件. s! d5 V& h* @3 @# i
- */
& u' s5 t2 w; T- e6 O - 3 i5 D* C/ t! V7 }/ ~% L8 D. g
- // 关闭错误报告" t, W; C0 m1 z6 ]3 s* j
- error_reporting(0); 7 p1 x0 X& _5 x) Q: q. Y4 b
- # u$ ?9 Y$ a1 l9 M3 V& \
- $dbhost = 'localhost:3306'; // mysql服务器主机地址
# I$ }; _& U: i# W. ` - $dbuser = 'root'; // mysql用户名2 X; c, W) g+ z
- $dbpass = 'root'; // mysql用户名密码2 i- ?. R( F( }1 h* A
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
G! p3 z9 r3 O2 a - if(! $conn )# R$ z+ ~. ]0 s6 G. w5 r8 V
- {
/ _" b6 K" s" r ]+ S+ A - die('连接失败: ' . mysqli_error($conn));
& v$ L/ ~7 W( e - }9 G8 r7 Z) C2 L0 L# M }
- // 设置编码,防止中文乱码
6 W3 w1 L% L) {& A3 N4 \ - mysqli_query($conn , "set names utf8");" V: G5 {; R1 V5 F4 ]. J7 V7 m
- mysqli_select_db( $conn, 'temp' ); 0 k) L5 Q8 o& c N
: `5 K# Q. d0 B9 C) L- # mysql 锁
& A, g/ k+ ^# s' n; d - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
4 P. n+ i1 x' H" X1 F+ ]1 g$ a - $rs = mysqli_query($conn , 'SELECT id FROM a'); # I8 V8 S" I8 l
- $id = mysqli_result($rs, 0, 0); ! W" M" R! q: X' X
- if($id > 0) * ^( P. ~1 P5 p0 w2 D
- { # |( M+ y+ R. u) a; Q( o
- --$id;
4 D% y. t6 F/ x - mysqli_query($conn , 'UPDATE a SET id='.$id); $ d% K+ \. {: N3 \4 g/ N9 O
- } 7 E% P6 H+ Y6 m* {
7 u; u- b+ I1 j0 ]$ U$ f4 P5 u- # mysql 解锁
2 R( m4 \6 n& W- p - mysqli_query($conn , 'UNLOCK TABLES');
; V! H/ K- Q0 p* } - //查询解锁后的id值
- \) b& h3 S5 T6 ?7 { - // $res = mysqli_query($conn , 'SELECT id FROM ta');2 p& U, h+ j/ ], b5 `5 s
- // while($row = mysqli_fetch_assoc($res))- Z/ x V9 a7 p# y0 s) i
- // {
6 s, l" {' i1 @8 Z: b - // $id = $row['id'];# J/ M' s" r$ X c/ u
- // }+ W9 x o1 @. ?' S
- // echo $id;
复制代码
# J4 [) ~5 c; s! {# L2 J c3 ?
8 q( ~$ ]8 E' H5 V8 {) Z$ t' p" H1 J5 K3 n; z% j s
PHP文件锁示例: - /*9 t! L) o8 y2 O5 I
- 模拟秒杀活动-- 商品100件+ G1 H( p0 |" G" n: }/ z4 t
- CREATE TABLE ta
; f; Y$ _" ]/ `7 M4 f% }) d2 T - (1 {, Z0 L; `4 ?; l3 d
- id int comment '模拟100件活动商品的数量': @& p5 v9 s& H
- );
3 q4 X* i: v! g* J# j# o - INSERT INTO ta VALUES(100);
5 m8 L# P7 s( V4 ?) x; X' \ - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件1 l* u3 @0 U4 n; h- \
- */ 6 O9 o/ ~ k5 t$ K% p# ^( L0 a
-
( G* ~1 P+ L& u$ L' b2 ^ - // 关闭错误报告1 R* ~* d- u+ r$ {6 f+ g
- error_reporting(0);
6 C+ _; B/ }! V% \+ P
2 V# D, a" R( w$ G- $dbhost = 'localhost:3306'; // mysql服务器主机地址6 c$ I2 |" m& K; u
- $dbuser = 'root'; // mysql用户名4 y8 p: R1 Y- _7 s! h2 ~
- $dbpass = 'root'; // mysql用户名密码- W* C. @# @4 S$ s! @+ W& o5 `; k
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
& X/ b) m5 O8 I( m. n6 F/ p2 } - if(! $conn ); Q* W1 E8 ` f1 `0 P5 A
- {
$ H) e1 ^9 `. Z - die('连接失败: ' . mysqli_error($conn));( h, \* Z) U3 x& l& R' J/ H
- }
4 n6 B+ F8 }' ?1 Q - // 设置编码,防止中文乱码! D# l0 m0 E/ y; d
- mysqli_query($conn , "set names utf8");- I6 I: a/ l1 z& Y# G$ [% r$ A2 Y
- mysqli_select_db( $conn, 'temp' );
/ z7 A3 G9 Y9 y, L3 V
' {4 Y* b4 y) a9 X- # php中的文件锁
1 c; U4 {0 c! V% [+ Z - $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 , u" `" S* g: ^$ {
- flock($fp, LOCK_EX);// 排他锁
7 Q; \. ^. j0 h2 t: A3 a - $ b: b3 A% i- v! \
- $retval = mysqli_query($conn ,'SELECT id FROM ta');
+ V8 }, X4 Q* ~7 k5 E% t2 W - while($row = mysqli_fetch_assoc($retval))
$ v' d$ [, S. K5 K - {
! s0 P1 |$ D- ^ - $id = $row['id'];2 _. T% \. M, z/ }" g7 x: |! E/ w
- }
, W( Z$ r, P- y( Z# j -
( X7 \! _+ D8 C+ [7 X - if($id > 0) ) ?: J6 @6 A9 ?& v6 r: y
- { ; a3 _7 w" [) ^3 N
- --$id;
1 I1 b; Z: |# r7 t0 Z0 A, ]& Y - mysqli_query($conn ,'UPDATE ta SET id='.$id);
3 N: O, I# n: \! Q - }
& {5 ^& c+ ~# v8 O( A) {; s( Y - # php的文件锁,释放锁 . X" z" r/ ]2 ^: j6 n2 h9 ^0 h# X; g
- flock($fp, LOCK_UN); 2 ?" Z" j2 [; k& @+ X" a
- fclose($fp);, Z6 i D; U4 W0 z) M- b5 Y/ V, A8 j
7 N) C8 z$ ^, [; m- // $res = mysqli_query($conn , 'SELECT id FROM ta');
6 `9 D/ K: F) d - // while($row = mysqli_fetch_assoc($res)); G0 s5 ^6 a& T5 V. O- ?" u. a8 U
- // {
0 E9 {1 e9 J/ C3 g# o) x4 K' x: F - // $id = $row['id'];
7 d7 u9 Q+ D" ~) U - // }6 X) D: ]7 ?2 J4 h
- // echo $id;
复制代码 2 e& m& U/ y8 l
) p7 A& J9 o9 c2 {8 n1 V/ ?
抢券活动实例: - public function envelopeSnatching(){# P V. [8 j, y( D
- $lingqu = $_POST['type'];0 q# y+ P3 B8 S$ M
- $uid=session('u_id');//用户id
2 A7 A! J* j! F. g$ ^ - if(!$uid){# @# b/ f$ l& b+ `6 L5 ]
- $data['msg']='您没登录,请先登录!';
( B/ v; v. K% ?; M: i1 _ - }else if(date('Y-m-d') != '2017-12-12'){
6 T9 M, {4 c: L1 @1 U - $data['msg']='不在活动时间内!';6 q0 R4 P: k5 O( R, M) r/ u
- }else{. X. U) T5 S9 a9 E4 N
- $hours=date('H');//当前小时数6 F9 U) Y- r* }/ b9 c: Y2 @
- if($hours > '09' || $hours > '17'){
5 w2 ?. c6 A6 e+ E
/ A( m( B. q+ d9 z$ P- if($lingqu == 1 || $lingqu ==2){//点击10点的$ X5 x1 O: E0 e
- if($lingqu == 1){
( A8 p+ ^6 K! } - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过0 i3 O5 d R6 v$ Q
- if($hours > '09'){
% G" |: \' u2 X1 H% L - $num=mt_rand(25,28);//优惠券金额& X1 I8 a7 r* `
- $id=1;( w: U" S% m# W
- }
* P6 |& Z7 ?4 _, V; K* } - }else if($lingqu == 2){
+ S' ^1 x+ E6 B( } - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();% K, q, c5 E0 E1 v
- if($hours > '17'){9 ^8 N0 {" y9 D; k+ S* Z" a
- $num=mt_rand(50,55);//优惠券金额
2 _' R% l; V. z+ S. G" U8 N - $id=2;
+ E9 Q# ~# u! W/ ^' S. f7 X - }
4 }! S7 }2 j' Q0 \6 t* T - }) c$ |5 ^- ~6 G6 y8 x. r
- if(!$id){3 D" n% L: {8 {2 E( R
- $data['msg']='时间还没到,晚点再来吧。';% H- A( l2 u$ Y+ a, v* u9 h
- }else{7 ?( N- d, D/ d1 j& J. H+ |! @) |
- if($is_lingqu){
* p7 t& a& b: e, k( p - $data['msg']='你已经领取过了,留点给别人吧!';: X$ M! K3 b! G7 j5 t
- }else{
( o' W9 f2 i9 c) o) u3 [ - //锁表
% G+ o/ c+ P. X; u! r4 S - M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');7 F. h% X; n" j+ {
- $active=M('active_num')->where(array('id'=>$id))->find();9 x2 K9 C6 A$ X7 o, G, Z
- if($active > 0){0 b* w5 r4 _( ]) c4 m, G$ Y- a
- //开启事务
% {: }# H! m' B0 j; `. |/ X$ Z - M()->execute('start transaction');! _: D) z5 M5 K, |
- $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
" ^" F' \9 Q; K2 y% |4 l3 ^ - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));: w6 j2 `. r P- K- m7 A1 G
- $members_preferential = M('members_preferential');
% i7 A( ?/ }7 D1 o. _& ` - //对应投资金额,
3 X- z' ]7 I! H, b- g - $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
Z; Q _- k3 K% `; r- P. q2 l. z - $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');% a1 `" X; M" v ? ^; S0 T x
- $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
8 ~# w, X0 g, g0 H) z9 S$ A8 ] - $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
( q) j/ Z# s4 n; G: ?; y+ D - if($save && $add && $add2){5 _' w' G$ v" H2 E: f
- //事务提交7 G( V5 A4 a) c
- M()->execute('commit');4 v2 z+ L. p, P( l# v. F
- $data['msg']='恭喜你领取了'.$num.'元优惠券'; e6 t( I) G) k4 m4 u$ o
- }else{
/ j8 h6 I& |1 r. k+ X' F - //回滚
" \* `! d. `+ F5 E8 Q - M()->execute('rollback');% ~ A! r1 Y3 o
- $data['msg']='未知错误!';
+ k$ Y4 d! o0 N7 T/ F! i0 t+ ^! B - }
6 @6 H, m5 E6 [( L, l2 f - }else{
$ v3 `5 W( R4 V4 E - $data['msg']='红包已领完,你来晚了!';
$ K. y0 N9 T8 }. I' k0 x - }& X: Q: E7 D- z1 z
- M()->execute('UNLOCK TABLES');
/ R; b7 ~* f3 o6 ~3 m - }; u; @( t3 S1 `$ R
- }
) t+ x; }5 Q: T) k8 t3 I0 v R# m0 s - }else{
: [3 k; Q- N, r% h - $data['msg']='非法操作!';
U; I: N: @: p - }
- B. \% f9 q: s/ F - }else{
- p6 ]# W# [& u; O2 N - $data['msg']='还没有到活动时间,请晚点再来哟!!';
: H A7 r) G. n& B0 h - }
3 O* [/ _- o; g' Y+ i - }
* X6 I* U3 G- j( I4 }- r - exit(json_encode($data));' O3 Z, P. z$ h
- }
复制代码 1 g9 G& |; X# e& L
/ h8 F9 Y9 a* o; \ J
|