|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码 " w3 \% m; V% ~( Y5 l, C
Mysql中的锁语法:, D7 v5 F, p) ~2 k6 g, V; z
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】1 F, v9 C5 \& K/ P3 H- U6 W" J
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表: r' ^/ D0 ?; J+ b
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞+ }. r( [! n7 F* b
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :2 N/ }- p) h% x! z1 ]6 F8 ?
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
- k6 D1 R# W4 {8 J# z测试时,有个文件就行,叫什么名无所谓 总结:
' t4 N R8 ?8 u9 r项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:3 J2 i8 p- y: l0 g, J7 q4 g
1. 高并发下单时,减库存量时要加锁8 R9 D/ Y! c/ k2 Q2 I* u6 p d
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*
6 o4 V5 ]* E# Z) U1 r - 模拟秒杀活动-- 商品100件
8 E# B# N5 ]; S - CREATE TABLE ta6 s9 |" z' O, @
- (
: e! s& t& M; p; Z4 C s( _/ U& Q9 p - id int comment '模拟100件活动商品的数量'! W4 u, J m$ X0 a8 M1 v, E
- );
/ T/ k* ^! m( o# `# o - INSERT INTO ta VALUES(100);
$ H1 h. b8 x( K% P8 t2 @, [ - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
6 z9 Y/ A* |' X3 f - */
8 X1 m+ U, W& q" o1 A# }4 t; @ -
0 u8 @# {4 P6 `1 a0 O6 Y - // 关闭错误报告" @* C/ r: X9 G$ p0 O D0 L% I
- error_reporting(0);
, w: R" d1 ^0 l - ! q& P% c4 h, A7 k" Z& d
- $dbhost = 'localhost:3306'; // mysql服务器主机地址$ X9 z* G3 X, g
- $dbuser = 'root'; // mysql用户名9 u( C+ Y& ]+ z& g' s) N
- $dbpass = 'root'; // mysql用户名密码
: P! Y7 t5 C5 [6 } - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
* u9 J8 v- K3 I" }4 h: W. p: l- z - if(! $conn )
: ?! m4 H" `- J, V/ S9 ?# j - {
2 I O$ d: \: K" k! v5 Z" T - die('连接失败: ' . mysqli_error($conn));
, w3 U2 Z; U2 M: q( L2 Z0 k7 a6 M0 R - }
* q1 f1 a1 u; G' P - // 设置编码,防止中文乱码* j6 p; A1 a) t
- mysqli_query($conn , "set names utf8");
2 a( @0 ]( \1 l* C8 v6 y# Q+ u+ i - mysqli_select_db( $conn, 'temp' );
0 k P, W. x, O9 O' a. |
4 W2 M* d* o8 G% ~1 t7 r+ z: P- # mysql 锁
3 i) J! ]. ^/ e# S O, n - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 # o$ n5 h& a" V+ T/ a$ E1 }3 b4 U2 }
- $rs = mysqli_query($conn , 'SELECT id FROM a'); & @6 @+ i3 o, d8 s
- $id = mysqli_result($rs, 0, 0);
. P' }9 C0 a* Y8 G% `) j; S6 p - if($id > 0)
$ W- i( d% { \- b- }+ | - {
: y4 p. u: W1 t- H9 ~: @4 L - --$id;
4 i4 u1 h- G8 s! M4 l. K - mysqli_query($conn , 'UPDATE a SET id='.$id); 5 N# T5 v' k/ ~2 D1 z# Q8 I
- }
2 ]8 `$ z' o% x- G% U# t5 l
% S6 a) W, w! P& X2 X- # mysql 解锁 ) R5 g# I3 n$ p; f% W
- mysqli_query($conn , 'UNLOCK TABLES');% ~; i+ f' [- {0 S I& b4 F
- //查询解锁后的id值8 p4 S$ e, w' f6 b Z
- // $res = mysqli_query($conn , 'SELECT id FROM ta');
. @7 t" v7 P3 u! j - // while($row = mysqli_fetch_assoc($res))
/ b4 c' x) p+ L6 C' | - // {2 [) I0 N4 @8 N m# ?
- // $id = $row['id'];% v$ Q& H7 e) s2 e* r/ {
- // }
0 z% d+ g3 U2 V- u) i- ? - // echo $id;
复制代码 ) d5 x/ U1 m7 l: D/ M
% }3 ?( l4 b; z6 i+ ~5 |1 Z
9 U* J7 Z, K, O, P# L6 [: `PHP文件锁示例: - /*2 f. F8 S" N- \1 n
- 模拟秒杀活动-- 商品100件
8 j. v7 d7 I, p; l' R0 W; G/ ~ - CREATE TABLE ta1 R$ A( i! k6 q" z6 v
- (5 t/ S# b, Q3 v) ~* c
- id int comment '模拟100件活动商品的数量'" u: o" V1 e0 w' C: y( e- n6 \, [6 J
- );
' k- O U& B( u8 G3 _* L - INSERT INTO ta VALUES(100);* Y- ^* F8 j. O- G
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件0 [/ g( d. F" o
- */ % _8 a, e8 c* ]7 r
- 4 s+ H' Q `0 m$ ]: E
- // 关闭错误报告2 B* J: O( K9 s8 L
- error_reporting(0); 4 G% h. w+ R, B, G* Y
- + R9 m8 G4 U7 [! [
- $dbhost = 'localhost:3306'; // mysql服务器主机地址
, d# t( a! _3 y, L0 }* A8 ` p$ ` - $dbuser = 'root'; // mysql用户名5 I# j6 J t& J$ L5 O. V6 |$ Q
- $dbpass = 'root'; // mysql用户名密码 i% g% {3 ]5 H8 D
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
& j: q6 M0 @5 ?& P - if(! $conn )
- O* e/ T$ I' _ - {; _* m% T" ]# O4 v8 ^
- die('连接失败: ' . mysqli_error($conn));. Z9 X/ O* o7 z6 v& q
- }& `9 V4 C- D2 Z, i4 d* T9 F
- // 设置编码,防止中文乱码
+ o; Q' h* {9 V8 ^5 m' v! Z7 E - mysqli_query($conn , "set names utf8");8 U# D: `8 ]& k1 P3 e
- mysqli_select_db( $conn, 'temp' ); 4 B1 U E! v9 H
- - d5 \5 q7 m3 F/ S
- # php中的文件锁
9 P2 J. \+ k8 M# u - $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
J6 q, {9 @' [( m1 a& w1 ^! f - flock($fp, LOCK_EX);// 排他锁 4 h5 z- B9 O' L, ^ }! U: _% n
- A# ?6 g2 G5 p E
- $retval = mysqli_query($conn ,'SELECT id FROM ta'); , }6 Y5 p: A$ ~8 A# J& i
- while($row = mysqli_fetch_assoc($retval))
% m5 D8 c1 @+ b+ i - {6 L; C% ]$ W, u& a! B/ H
- $id = $row['id'];: _5 y0 t* u% P6 J7 a% w& W
- }6 y8 Q4 O& L4 |/ A7 q2 ]8 X6 M
-
/ j* x# [$ s* d; t$ Z, W( K - if($id > 0) 9 \3 N; r, E3 y$ w4 f! T" l" u
- {
0 @! ^- ^$ F* a6 v - --$id;
( B: L0 j/ M' T) p7 N - mysqli_query($conn ,'UPDATE ta SET id='.$id); * F, T0 A; U4 ?- H
- }
% b) F4 K1 T. b, C4 x9 q - # php的文件锁,释放锁
" F$ q A: i9 k- H( g% }2 o1 ` - flock($fp, LOCK_UN); / w3 y' @/ t- W U/ c8 K7 `
- fclose($fp);
+ B- L |8 v& ]' G- ^4 y5 u* U
7 N& x' i! ~4 A4 d- E! K c- y% A$ d- // $res = mysqli_query($conn , 'SELECT id FROM ta');" r0 w" `: t/ X& x, j0 d2 t7 D; U8 h
- // while($row = mysqli_fetch_assoc($res))
) W# x/ T1 w1 q9 y0 C. D - // {) [) v# U. \% `0 q$ G! w: ]
- // $id = $row['id'];
$ {$ t4 f6 w3 q - // }" W7 `! W- I) P8 b2 j5 O
- // echo $id;
复制代码
6 Z9 O) P$ m- G0 `4 B. @9 l4 A; p) l* D( U
抢券活动实例: - public function envelopeSnatching(){
" W5 C7 s1 ^. N& ]3 w2 s8 x$ c - $lingqu = $_POST['type'];
8 L# h4 O( g! Z. c, F/ b - $uid=session('u_id');//用户id5 o# B$ f$ Q {* O$ t
- if(!$uid){6 M1 W, h! }8 V
- $data['msg']='您没登录,请先登录!';
2 Y3 E1 |0 h: _# O8 p9 N* E# y - }else if(date('Y-m-d') != '2017-12-12'){! t" _ R* E0 M! A
- $data['msg']='不在活动时间内!';
' X5 a6 S. K4 M4 a+ {1 G& k - }else{
; y& T; {) E2 k+ r9 Q1 X - $hours=date('H');//当前小时数
5 z X; M: R# J2 k! L - if($hours > '09' || $hours > '17'){/ ~# p6 l4 ^& V5 O( t
; T2 {. G& _6 i0 ` ~9 X2 T; M- Z- if($lingqu == 1 || $lingqu ==2){//点击10点的
; |- i1 v G s - if($lingqu == 1){
5 X0 U8 u, W* B0 U i - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
" c8 Z4 @* H: E7 @! s - if($hours > '09'){' u* d4 q d; z/ q! {
- $num=mt_rand(25,28);//优惠券金额. ^5 F) V! x8 S' ]4 o7 O
- $id=1;: c; S) B' @2 ]& U* O% t! E$ O
- }( Y# e; Y/ h) {4 B; J
- }else if($lingqu == 2){/ o1 j/ D% T( Y# L2 N9 U
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();2 _' f7 f8 N- n. f& E
- if($hours > '17'){
0 R% A- ^9 _! j# e) M# K: w - $num=mt_rand(50,55);//优惠券金额
/ \1 P5 L7 R# ^! S - $id=2;
' ?9 m% \2 S* q4 u. n* u - }
3 a! G1 w2 ~+ g* T, |. b+ B2 E - }4 `6 ~; o% s9 M# p( ]* z' J
- if(!$id){
1 q( M) u0 j- r; G - $data['msg']='时间还没到,晚点再来吧。';. p; F: }* Q: B
- }else{
7 p5 j; K$ Y; E: _ - if($is_lingqu){3 n; l2 W+ w/ U' q2 E1 k
- $data['msg']='你已经领取过了,留点给别人吧!';
5 E0 d% M5 S2 F. a( K9 r3 g - }else{
0 a) a" I* L- ^1 l7 [- d6 k8 F z2 B- \' Y - //锁表
) ^( E$ u! E% ~) ~ - M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');, j/ B6 X! U% k* E$ L% t1 `
- $active=M('active_num')->where(array('id'=>$id))->find();4 c8 k5 Z. f9 }+ t* m+ b% {: C* R
- if($active > 0){% x" Q& ~; d) t* l6 C
- //开启事务
j( e# Q* L B6 ]# g3 Q - M()->execute('start transaction');6 K9 t5 _* O0 x7 U' }; H, E
- $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
+ n: i# K1 N, b0 g - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
~1 o9 q) L( i" c - $members_preferential = M('members_preferential');
5 U# Y3 R4 `- T8 W - //对应投资金额,
, k! G; c- E9 T% m! T) T7 P- g. v- Y - $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));* c- G2 e: ^# T5 G& A: L, `
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');6 g" o, c. g4 f. K' p' }
- $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
m5 H" r9 |/ V, C6 W+ x! {" x9 G0 r - $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券# |; d2 T d ]4 D
- if($save && $add && $add2){
! `2 b$ }- N- C3 f$ ]% g - //事务提交1 q' C4 r4 Q% N. J
- M()->execute('commit');! W# S/ G$ [ U% |
- $data['msg']='恭喜你领取了'.$num.'元优惠券';- R5 q/ ?- B2 D. U- @
- }else{) m; i: ?6 ?! o. E: o2 P
- //回滚
" P& s: R2 L3 e! V, l - M()->execute('rollback');
1 k1 p L: H( } - $data['msg']='未知错误!';6 E, n0 z0 k. K! U/ F8 v
- }
! N9 z& e( B, m4 N5 r# o, d/ y - }else{
7 ~8 d; J+ Z, ?" h) ?5 h2 h1 |' U - $data['msg']='红包已领完,你来晚了!'; G) w7 m' {7 l1 S
- }
S0 \& s h8 ~* }9 ? - M()->execute('UNLOCK TABLES');& K( j1 j$ @. {$ {' \
- }8 x' m* i5 D4 P
- } V0 k" I5 t2 f
- }else{ w( v( U4 Q3 |# Z m
- $data['msg']='非法操作!';
$ g" _/ |5 `4 N/ z: Z7 t - }
+ v8 q2 C$ p$ G! l! k - }else{5 b; B. v# [ T, z8 M
- $data['msg']='还没有到活动时间,请晚点再来哟!!';- |: J. P v( ^' w' D5 i! ~, |
- }2 f$ Y: ~; a3 l" v3 a6 e
- }
3 B7 ~$ V! \$ G: T) c Z8 a6 u - exit(json_encode($data));% D! X0 S% s* `$ P4 l2 a
- }
复制代码
% Q1 V: j* k2 u4 q' [' P; h
1 y' Y8 r6 `5 m/ b8 } |