|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
8 g. D5 P6 S% _2 bMysql中的锁语法:
$ C! Y0 M& {6 l/ L" X8 xLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
' b2 \) {& J2 Q8 vUNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表1 ~: a6 Z8 R: O8 x
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
. r& L b3 Y( P$ d3 u注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :
z# F+ ?+ v, B+ b% E- |$ t文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
% A0 R5 x' `- }$ r+ ?测试时,有个文件就行,叫什么名无所谓 总结:4 D% w$ l `/ O: w, E
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:. L$ W P8 M! i/ C6 j; B
1. 高并发下单时,减库存量时要加锁! T$ s2 ~9 T) G+ X- k4 A* g
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*& `# q- o3 S( }3 [8 X1 T" _
- 模拟秒杀活动-- 商品100件
k% r6 @. o- H - CREATE TABLE ta
9 D0 r& M# r; b5 |- q+ W - (% i X& O2 w1 w- Y+ Y! t; P @" b
- id int comment '模拟100件活动商品的数量'$ } T; ?0 X# J
- );
; K! R: T6 ~' `0 u - INSERT INTO ta VALUES(100);
! k( ?, h6 {! } - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件! n- J* n B' G# W
- */ # S, ]: O8 N; m2 z
- 3 a: n) Y+ r& H: r2 c5 h @
- // 关闭错误报告( b( s' o2 t% t/ s- j- M/ i
- error_reporting(0); ( G# `3 J9 o+ |9 g9 C
- ! J$ K' J$ | m! S- t
- $dbhost = 'localhost:3306'; // mysql服务器主机地址
0 A! F \+ `4 ^8 e* \ v. N2 \" m: f - $dbuser = 'root'; // mysql用户名
: l) }: H- K' F - $dbpass = 'root'; // mysql用户名密码
) D! W+ b1 [% ~ - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);( c0 X7 b! |5 g0 Y4 S2 ^
- if(! $conn )4 @, j v& i0 f9 e$ l- ^
- {; j7 d9 Q5 k# J7 w7 T) S
- die('连接失败: ' . mysqli_error($conn));
* y$ R3 w4 Q& k# W+ x( ? - } d6 @6 B& Y) P) J3 t7 T
- // 设置编码,防止中文乱码
) w$ l9 Z6 \5 r* F" f+ P - mysqli_query($conn , "set names utf8");
+ q! [3 ^4 q, ~$ z - mysqli_select_db( $conn, 'temp' );
6 o9 {0 Z) a7 Y: ^( f. F& K- A
, l7 @3 B7 e+ Z; q* x R- # mysql 锁 , k( D9 r; _. B" x2 y- T: O
- mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 " e( [' B( H' D- K3 T3 ~* p
- $rs = mysqli_query($conn , 'SELECT id FROM a'); 0 ]& `8 Y" z" O( q
- $id = mysqli_result($rs, 0, 0); ' X5 S; p) A* w7 e/ G R
- if($id > 0) % t* k% r- j7 j& ^/ i9 H7 N) ]
- {
4 h3 ~9 O0 e3 V) Q5 N9 ~ - --$id; 5 L5 ^* I$ x6 S1 ~) l4 F, m/ v
- mysqli_query($conn , 'UPDATE a SET id='.$id);
& _; u/ R7 w; \% T( o7 g - } / B3 d$ p8 t4 r: w
- ' O R; b: f( h0 C8 e( m6 K' M
- # mysql 解锁 ( w# U' N8 c4 [0 ^ L1 `
- mysqli_query($conn , 'UNLOCK TABLES');0 X, v) t. P$ t/ Z. U
- //查询解锁后的id值
1 k% G1 Z2 v) i G+ B. | - // $res = mysqli_query($conn , 'SELECT id FROM ta');
s' f* X8 Z. E4 K. R; Z$ z, W* L - // while($row = mysqli_fetch_assoc($res))
u4 v/ W) r2 N - // {
! U3 ]# V$ H+ g - // $id = $row['id'];
4 v) A- S/ w: N! T2 J6 R5 i+ h& J* X - // } s2 v- x0 r% Z
- // echo $id;
复制代码
( m* K& g6 Y2 g5 Z3 p& B) g9 \9 U8 B, m
/ Z& k% b+ w4 Z+ T6 D+ |" w/ C( c1 D
PHP文件锁示例: - /*
7 Z8 ^4 C1 i. @# p) I; I9 Z9 Z - 模拟秒杀活动-- 商品100件
) U! s, h& [/ c J - CREATE TABLE ta
" S/ I9 Q9 V( X% Y - (% G/ J. J) F- B
- id int comment '模拟100件活动商品的数量'
1 d0 L+ t! j$ j - );
; b6 g, @- N. `7 x$ ^ } - INSERT INTO ta VALUES(100);
& p( U g! { v6 u2 J9 A - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
_% ` u. \% O - */
9 _) o8 C6 ]% k, `6 w& A6 ` -
4 ?" r2 j4 E4 x5 f9 n - // 关闭错误报告
$ n6 i6 l" E! {" [ - error_reporting(0); / x: G$ g6 k: @- {5 A8 z2 z
- ! J2 @3 y& B. E( R5 J) R& q& j
- $dbhost = 'localhost:3306'; // mysql服务器主机地址& k( x/ ]# c4 I( J! u/ W8 S. a
- $dbuser = 'root'; // mysql用户名
4 h, h0 J2 `0 W7 ^+ W% M - $dbpass = 'root'; // mysql用户名密码. Q$ J4 n1 P3 K# _ l
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);* T/ i- @; h9 g2 k
- if(! $conn )) @, m% E) U# j0 A
- {, j* A( V, v; q: M7 Q: F
- die('连接失败: ' . mysqli_error($conn));" o7 I* o: p- @/ S }
- }
p- `4 s, S6 f+ M' H% e* W3 t - // 设置编码,防止中文乱码* U. E/ m3 L j* f7 N. G" u
- mysqli_query($conn , "set names utf8");
' C+ c6 B* N7 X' F( y - mysqli_select_db( $conn, 'temp' ); 6 v D0 G' e \5 ?9 L: T
- - s! j+ g. b! I, N9 r
- # php中的文件锁
6 z/ i0 C' B: C$ N" G - $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 : k7 r, J2 A6 J/ }5 ~
- flock($fp, LOCK_EX);// 排他锁
k* i6 Q Q F) ~* D
" O' ]2 Z: c; b8 l9 p, I5 Y2 K- $retval = mysqli_query($conn ,'SELECT id FROM ta');
, A' C- `7 r7 t; K/ V" J - while($row = mysqli_fetch_assoc($retval))
2 i! [( R" N; N) p7 Q - {
& F- Z Z1 T, n5 O! s - $id = $row['id'];
; K& y6 E e& t7 K - }
- ?1 B; y1 i+ @7 j - + m5 R* J4 G8 e6 Q' j/ V7 K
- if($id > 0)
* v. T: j1 c2 ^9 Q8 G7 ^; } - {
- ], q9 k* [# [, J4 I) l - --$id;
3 X* `. g4 {& H- z* m; W - mysqli_query($conn ,'UPDATE ta SET id='.$id);
. N6 e+ z$ r% O7 p/ D% M* W - }
* x; v& b6 m+ i8 _ - # php的文件锁,释放锁 ' t- {1 v( ^: R4 A, O
- flock($fp, LOCK_UN); ) I5 F) L) m/ H: F& y' J) @
- fclose($fp);
: U0 Y1 z7 m% t) T& w3 y% M - . }9 ?5 H0 K% d" u: n8 i
- // $res = mysqli_query($conn , 'SELECT id FROM ta');9 v3 [* h) a: j
- // while($row = mysqli_fetch_assoc($res))- U# n& M7 c+ r5 g: k
- // {4 F; ], ^9 R. ?. }- }( ^
- // $id = $row['id'];
, W4 {$ M, x- z( w$ }( S; q - // }( B$ r, o, ~# T5 I- x1 F3 W
- // echo $id;
复制代码
/ p) C0 w* u [; p' R$ V C, d; `% c! P: |& H
抢券活动实例: - public function envelopeSnatching(){0 O9 T) U$ \4 L) [* L l( \+ x: R
- $lingqu = $_POST['type'];
) W1 U" j' U$ {% g - $uid=session('u_id');//用户id5 ^* n. F. a1 W8 y4 e! i
- if(!$uid){
" l7 G. w( v0 q - $data['msg']='您没登录,请先登录!';9 U' i! `4 S9 M1 s& T8 |/ z/ L: p3 P
- }else if(date('Y-m-d') != '2017-12-12'){
6 a! B' H( ^0 g6 h0 q+ V4 d, r9 P3 l - $data['msg']='不在活动时间内!';. E4 |0 q# @* ]$ W
- }else{
- x5 h7 B3 M: ]$ N1 t7 | - $hours=date('H');//当前小时数
# a1 {4 t3 x0 X7 `; s - if($hours > '09' || $hours > '17'){4 t: T/ o) x1 V. l9 ], {+ q2 {
- ) }$ R5 w6 b! E' y9 T: k: p. j) X
- if($lingqu == 1 || $lingqu ==2){//点击10点的
2 y1 t- [1 p4 Z$ X0 ~( C6 m - if($lingqu == 1){
# X! R) P6 K4 c N - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过, N$ s [+ _: G
- if($hours > '09'){
8 q1 J* m/ `, B3 l2 V - $num=mt_rand(25,28);//优惠券金额
7 x+ n9 ]& P$ Y2 j0 S" m - $id=1;0 z1 I4 g. s" H! I& b) y
- }
6 h" i* J9 R. I9 N, x - }else if($lingqu == 2){
" L+ }, i( m$ Q% `' R - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
! P. V/ X+ Y* c& q- B4 } v K% s - if($hours > '17'){
3 m- w) E! R3 O& f - $num=mt_rand(50,55);//优惠券金额! D5 X: X3 n3 {' l, i
- $id=2;
8 B% J. o6 Y- Q0 c, s" l' K ^! I+ @ - }- l) N6 J% N2 W
- }' L3 O! k6 X4 ? H! S% d; S
- if(!$id){
* b( \3 Z4 l/ v, V+ R. f - $data['msg']='时间还没到,晚点再来吧。';1 T! D2 }8 u. W; w' i$ z+ Z
- }else{
* L9 D7 H# {: W% ? - if($is_lingqu){
) x" z; M2 D; k9 [1 N( x - $data['msg']='你已经领取过了,留点给别人吧!';) | i8 S3 O' ?: V p1 g* l
- }else{
( u" t9 B) a9 k - //锁表! Z4 K) A, X' G) V% r, A2 T( h/ Q
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');' N# q6 f( S6 x7 n! _
- $active=M('active_num')->where(array('id'=>$id))->find();
1 _6 D' |4 H) e/ M5 Z- P( ^4 ? - if($active > 0){
; A7 Q. M! K- ]1 b4 y; `+ ?! E# { - //开启事务
: Z# M9 Z7 h' ~! U, [ - M()->execute('start transaction');/ @/ ^2 J# C+ [% M }+ O
- $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
9 Q! G, I# F& a) p6 r. L$ K - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time())); K( J ?; p' x
- $members_preferential = M('members_preferential'); O7 m- K) T: M3 K, u
- //对应投资金额,9 e1 i1 n# o: F% e' a8 S* v/ L
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));1 a4 Y7 E, f/ F/ d# ^! ~* O9 @
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY'); V* K0 z6 `, g' }+ M! h
- $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
/ A9 t" E0 W2 P9 k5 G8 h3 t - $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
' X* o& u) F0 S! \* P - if($save && $add && $add2){; a! h8 M$ ?/ Z7 p% ]# Y/ a, F' Y# F
- //事务提交
8 w* V U! y( P4 l! w/ } - M()->execute('commit');
, R* M1 T$ t4 O0 R* f9 ]7 t' m - $data['msg']='恭喜你领取了'.$num.'元优惠券';, D3 b' o7 p4 s( f% W
- }else{
/ f; c* m$ w: A( G2 m7 x. h9 W - //回滚 y, b5 O7 |: K# l, h
- M()->execute('rollback');
( \( @( r2 k3 \4 t5 b u& \ - $data['msg']='未知错误!';5 b" Q+ O; l6 ?
- }
. z# h+ p8 |" P - }else{
2 |+ T$ Q2 | }& j - $data['msg']='红包已领完,你来晚了!';5 h9 W9 ]% `' b7 G* G$ Q' r
- }; F* b- v' J6 t ^9 w4 D* D2 N
- M()->execute('UNLOCK TABLES');
8 H" ]" _. h9 d n( x$ e M - }
9 y6 ` k* q C" V - }! u" b; C# V4 P( p+ ~; V1 p1 R
- }else{' G$ x: |5 q1 D9 |2 l. A
- $data['msg']='非法操作!';. }! f6 w: }& V9 V
- }8 ~6 ]: U0 w( Q+ W) R4 V5 u
- }else{
2 c& P! R: p' D - $data['msg']='还没有到活动时间,请晚点再来哟!!';! r- p7 S3 i3 L; J
- }
% k, ?1 B1 x0 t2 V( l4 @ - }, q3 O) p! s* n, }! m# P* m/ W
- exit(json_encode($data));
$ u+ I2 z; x) A b& _/ ] - }
复制代码
* a( m% N) W6 \2 ]
2 R- c4 S/ P. ? e' l: z, z |