|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码 $ ~' q/ A% Y9 u3 f$ A
Mysql中的锁语法:
# w/ P- o' i$ b6 U! l8 J5 y% y& MLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
% a+ l. ]+ [# m, WUNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
. H' e5 b* T$ N! f1 R5 e: xWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
% P b+ X: v: W注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :& S$ K- X, f0 F2 u9 \; p- f
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
! _- G; q' e1 U8 g6 E测试时,有个文件就行,叫什么名无所谓 总结:
! Y: B+ w0 b, ~3 A项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
: i5 b" p+ n7 R' F9 P) } e1. 高并发下单时,减库存量时要加锁
4 b" X+ B; p# S& Z6 \2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*# W! f3 F0 j" F5 S
- 模拟秒杀活动-- 商品100件
3 U% l3 P5 |7 J0 ]& T) W2 K" N - CREATE TABLE ta
7 g0 }0 a# U, z* z - (; I% U+ K/ |( c6 t4 I
- id int comment '模拟100件活动商品的数量'
: F# B/ a! y* Q" Z7 x$ @% l( z - );
( B& k; W! ~* X$ ^* p1 E - INSERT INTO ta VALUES(100);% f- k* b5 B& m: @1 v
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件5 k* \* {) p1 ]9 k9 d
- */ % {9 Y+ h P# C0 O
- 4 j5 t! F+ S1 W+ `+ ^+ T$ }
- // 关闭错误报告4 h `, F5 _. U& U9 F& k
- error_reporting(0); 4 ^ L8 y7 d# l1 w. i r& b4 a
8 r& c# h; c1 U6 ^- $dbhost = 'localhost:3306'; // mysql服务器主机地址: W8 F9 v& T% a) n6 Y2 A7 N W/ `, [
- $dbuser = 'root'; // mysql用户名" i. X2 v+ J G7 \9 m
- $dbpass = 'root'; // mysql用户名密码1 E6 `$ H7 z' M" a: Z* d
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
0 V$ s: x! Q1 t+ F3 q - if(! $conn )
0 e- b$ @: R& o* ^* P - {6 _# D: [/ }6 `$ s( @2 u) z
- die('连接失败: ' . mysqli_error($conn));7 v- b: t# N1 ^: S6 D& J
- }" G* q& [) ?4 E- s8 _
- // 设置编码,防止中文乱码9 [1 ~# O2 K) a( h' [
- mysqli_query($conn , "set names utf8");3 c1 v* F/ V+ r0 ~
- mysqli_select_db( $conn, 'temp' );
}! i( G4 t6 d: _( B; E1 i" J9 D - 8 k: t, K% {- ?+ c/ V4 c2 k
- # mysql 锁 9 ]9 G8 |8 g" x. K. E
- mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 , O9 Z# b8 l1 C
- $rs = mysqli_query($conn , 'SELECT id FROM a');
1 A7 N4 O ]$ h% t8 c* [# v - $id = mysqli_result($rs, 0, 0); , b. t2 k/ Q( n& l
- if($id > 0) + K' l" y, W. R% F+ E
- {
# {5 S# H) o E0 }% y - --$id;
* }5 Y# W; T3 B( y9 N - mysqli_query($conn , 'UPDATE a SET id='.$id);
: r; ^) ?, f; M+ d7 M; T9 j - } 1 M$ f6 U% T- U4 Z; v4 S" V
- D# ~3 M6 O7 @, y" a- # mysql 解锁 $ l" S4 P& [3 M. s8 j, x5 e
- mysqli_query($conn , 'UNLOCK TABLES');. u' B! `+ W5 @8 p! T+ ^
- //查询解锁后的id值8 ]1 P5 Q0 n% H' N3 E% _" a4 @' O
- // $res = mysqli_query($conn , 'SELECT id FROM ta');# e- o& g; i: t
- // while($row = mysqli_fetch_assoc($res))1 c4 {- `; K/ \8 k6 d: S0 u9 x
- // {3 q! `- v0 B. P- ]. Y) E) L, g
- // $id = $row['id'];: w+ K9 y1 I( h$ B
- // }
2 G A0 P* m; s% s/ H9 @ - // echo $id;
复制代码
: i! ^& w$ o; [8 E
6 c) W* ^" _# W: b6 B/ Z1 |( A! Y8 y$ J5 v
PHP文件锁示例: - /*
/ O! P* a! ^6 Q7 s9 y" |5 W! _" i0 U - 模拟秒杀活动-- 商品100件
. |7 G9 Y/ h; E' m - CREATE TABLE ta" H- v8 ?3 e/ Y
- (
: O8 l3 E! D: C6 e+ |" X% E: |' B - id int comment '模拟100件活动商品的数量'
: [& Y" y- t' E/ O - );) j% H3 I2 F& M. d! q
- INSERT INTO ta VALUES(100);
9 r- K5 m* q( U @ - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件; n5 l+ i1 m. ]4 F: E
- */ 6 _# q" g( F7 Z
- : @' {9 s& N7 i, ~6 X5 o
- // 关闭错误报告) O+ o U3 T: s" N. B
- error_reporting(0);
* l' U9 y6 F/ K! d
5 ]! E1 T3 ?: A# b* T: F- $dbhost = 'localhost:3306'; // mysql服务器主机地址
' } S+ _3 L- A3 Q* y6 T3 V! } - $dbuser = 'root'; // mysql用户名
/ Q" U. v, W! e5 O$ W - $dbpass = 'root'; // mysql用户名密码
# Y8 k2 ~9 ^' h3 t2 M9 h - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
: K8 ^( b5 O! ]' ]3 S7 r; Z% F - if(! $conn )
, h& c1 J. M: |/ _, V: d - {
4 Q# x; I2 m' b( e; d) `) X - die('连接失败: ' . mysqli_error($conn));; h3 n- H8 N+ }: B L
- }, B9 Z: `7 {- E {
- // 设置编码,防止中文乱码9 [) o5 H- B9 P4 _
- mysqli_query($conn , "set names utf8");1 W) T7 v/ Q/ h7 [1 t/ Y6 _) A
- mysqli_select_db( $conn, 'temp' ); 2 ^- a( g4 `7 C, Y6 B, V4 W, O$ {& a
- ' ^! u0 Y4 Y" Y9 B' A& Q T- C: v
- # php中的文件锁 ( a8 r- }) e# b3 g7 n! D! T$ ~
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 * }9 D* q6 @) M% n' s$ t/ p5 Z# a
- flock($fp, LOCK_EX);// 排他锁
& K" m: v# i* G6 C) | c) O - 0 u7 m" C# j& k& m# I
- $retval = mysqli_query($conn ,'SELECT id FROM ta'); 4 Y3 s9 }& S2 L. s
- while($row = mysqli_fetch_assoc($retval))6 {$ E! E5 T0 p4 F" z P; E! Q( R
- {* ^% l& d* _$ P: t* d
- $id = $row['id'];
( ^! z; j; Z8 r - }) H! t5 D# J! \% g5 Z; s: F
- ! r" ]2 C6 o1 Z: m. O1 q" M
- if($id > 0) 4 c# ~; R7 I8 D
- {
4 b3 \3 V1 p( A: V - --$id;
' C2 a# x' ]8 N, X - mysqli_query($conn ,'UPDATE ta SET id='.$id); 4 k4 I7 u, Z" T1 ^' V% |+ K& w H% Y. ?
- } 0 k2 A% D/ g) G z* D4 T
- # php的文件锁,释放锁
, O ^. V: |! ^1 d1 v3 j7 o1 J0 N - flock($fp, LOCK_UN); 6 @# R4 O6 J' x. |) y8 k" A* Q
- fclose($fp);
: z2 T6 D j4 A" x - " S# Q2 L' c( P+ u; r, h/ E
- // $res = mysqli_query($conn , 'SELECT id FROM ta');
5 _' I$ E5 K5 D( x - // while($row = mysqli_fetch_assoc($res)); e7 D2 o) c, V O* P
- // {
2 A& Y, b! s! ?9 {1 x - // $id = $row['id'];
c' Q5 S; k* h$ h! ~; L# H$ E - // }* L2 B4 ^9 |( H
- // echo $id;
复制代码 9 c( d# C+ \! g/ E, r& {; u1 x
: B% q+ U, [" Z* G
抢券活动实例: - public function envelopeSnatching(){7 ~: n1 G1 n) ~! {7 w% T0 X
- $lingqu = $_POST['type'];
4 q6 Z& [8 i+ S9 V' M. @ - $uid=session('u_id');//用户id+ r( z& x7 r0 w% |
- if(!$uid){
5 ?! T2 T* w- R$ i - $data['msg']='您没登录,请先登录!';
$ N$ }2 X* ]3 E* U& I$ u$ I - }else if(date('Y-m-d') != '2017-12-12'){; o& x" L/ D8 }3 O
- $data['msg']='不在活动时间内!';
5 a7 }) `4 |4 _' G4 I, N - }else{" [% J8 M$ \; D6 T/ J
- $hours=date('H');//当前小时数9 G5 y# O: x) Q6 q
- if($hours > '09' || $hours > '17'){
* D3 R' f+ k! L1 j% B- v" C
* n- P- Z- V- ]3 K& M6 x- w, k- if($lingqu == 1 || $lingqu ==2){//点击10点的
O- d, K1 H% V5 U+ J* l( Z4 v# x+ @ - if($lingqu == 1){
, G4 L- L* A' m7 ?8 R$ S8 e - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过4 f- F& U3 @/ C' V8 [0 V3 t
- if($hours > '09'){
! ?& K. `+ N& @1 h - $num=mt_rand(25,28);//优惠券金额
s8 q$ v4 d% A3 X, L - $id=1;
' M; v$ I' y& ?8 \/ h8 q - }. v9 y: @+ T9 f9 @) K: l+ J* j+ v
- }else if($lingqu == 2){
3 _3 |9 ?: u: l. U7 M) @& Y% W - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
3 C0 ?+ T6 P9 f( t2 i - if($hours > '17'){
+ n* N: b; R4 K8 w3 [, Q2 ]0 I$ N - $num=mt_rand(50,55);//优惠券金额9 O3 p1 j' x* [/ c. n9 B
- $id=2;- r* j5 }( O3 q% Z8 e7 b
- }6 V2 b/ ?6 a* a/ S& h
- }
+ t+ Z: e/ f, `, j& p. u# V: J - if(!$id){
; I3 z* f/ w3 z) d, z - $data['msg']='时间还没到,晚点再来吧。';
5 ^" e' B8 K1 T3 A8 J9 p - }else{
" s( e! Y; _8 M2 i) E7 o6 T5 y: x - if($is_lingqu){: E2 R0 a' D* Y
- $data['msg']='你已经领取过了,留点给别人吧!';
- ?% ?! Y4 |0 t0 D, t- L, u - }else{+ L* O5 B- c9 R J# G
- //锁表
: k' a, ~. u6 N& o, g" ]# D - M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
0 B k9 S3 b( U. K4 F& E- a- F- s - $active=M('active_num')->where(array('id'=>$id))->find();5 f6 s1 X. M8 J
- if($active > 0){
& ^. p! q- m# Y3 i( i0 f$ @ - //开启事务, b: w& m9 e0 D. w6 y. I0 l+ o
- M()->execute('start transaction');
D* v' T, Y2 ?7 h2 o - $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));2 O y. G: Z7 s' Z' _, ^2 C# G' J
- $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
6 G7 V" q" S0 m u# {6 G - $members_preferential = M('members_preferential');- e" i# X! x: D
- //对应投资金额,
# N& ]) \' R2 E( F N w1 U% [ - $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));" }3 j4 T* N) S! e* m
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
+ m# h P, u: j+ S$ w: Z" H - $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
+ M5 n# B; Z( \" u - $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券, ~* F* g0 m! z, e
- if($save && $add && $add2){* h* p9 Y" r. R; Q
- //事务提交8 f* ~% ^4 t3 v
- M()->execute('commit');1 r; W4 Z; H, I3 }+ E! u% {" C- ?
- $data['msg']='恭喜你领取了'.$num.'元优惠券';
+ f. y8 M2 S. v0 B% _) r - }else{3 c3 x- W% B6 J) I! N, P/ c% B
- //回滚/ h; z: u7 b P/ I( w7 d9 e
- M()->execute('rollback');0 R) X1 P0 E8 h! r( h6 k: l
- $data['msg']='未知错误!';
! J J' i" U% k2 C - }
4 t; i1 Z0 w$ j - }else{
0 B: r9 }; f# l, E; F. j: M - $data['msg']='红包已领完,你来晚了!';/ y9 h! V; [/ |$ s3 G
- }* I0 z% A( P* c* s3 I$ A7 Y
- M()->execute('UNLOCK TABLES');( H1 F6 o( j. _6 Z
- }
; |6 K# C0 J u( L7 U0 Z - }" a: P2 Q8 r# a4 O1 K3 [4 @+ h
- }else{2 d1 I' l& y3 D Q: |
- $data['msg']='非法操作!';
# k' q! r' w# N/ Z5 \ - }4 }* v0 [" F9 N5 Y, V
- }else{
1 G0 C" s$ b: l! d8 y/ X8 @1 z, C - $data['msg']='还没有到活动时间,请晚点再来哟!!';
* C0 \" l" F. h) l - }
, h0 [' ?2 M) n% J, F - }9 _, c) C3 C2 {
- exit(json_encode($data)); _7 O9 `, X) `- U/ d- D
- }
复制代码 ' `8 C+ ^" u; l. _ x. R% w, Z
9 T$ Y. A! u# S2 T" ]+ E0 N& f
|