|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
- i' L1 M3 O* t' R8 G- M0 f$ @Mysql中的锁语法:
# u( H: g5 \' @4 K- pLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】% y6 A6 L$ i$ u: ?3 w/ [3 y2 e* F
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表) `& }. h3 m7 E; W# P. [+ h$ z
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞 u- ^" P, c1 M" S( M5 ~
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :
2 d: }/ [1 d, ^; B% {- B6 [- d文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。! M6 ]! [4 N4 D7 S" _$ Z$ z5 w
测试时,有个文件就行,叫什么名无所谓 总结:6 Z) }, |4 }0 F
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:( L. C7 O6 |8 c: M) F& }
1. 高并发下单时,减库存量时要加锁+ a6 g9 p+ q; j
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*3 F# I9 A/ U2 h) T5 Q0 n
- 模拟秒杀活动-- 商品100件1 I3 O2 H: ]) H) m* u
- CREATE TABLE ta
2 x' t3 B8 {* R, y - (
" Y: i; \8 ~' W$ s, {0 S - id int comment '模拟100件活动商品的数量'- d& u$ B [. N
- );! T6 I' b& X; Y% b r3 p
- INSERT INTO ta VALUES(100);9 o, O6 X# \1 h/ q( x
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
* _/ ^4 w5 @8 c, N7 p - */
0 P2 H$ Z9 p S -
1 D6 p4 Y) c9 _, _& Q* a - // 关闭错误报告
7 V! U! L( j4 q) ` - error_reporting(0);
# m7 a; F! p2 ?) e* b d2 K
! h" J' a. h+ [6 n' m- $dbhost = 'localhost:3306'; // mysql服务器主机地址) v# @) g, Q3 A3 e
- $dbuser = 'root'; // mysql用户名
/ j3 b2 ~6 J; F& g/ b6 x( H - $dbpass = 'root'; // mysql用户名密码+ J% u5 R/ z Q+ I0 G0 j: c/ K
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
# I* i5 ~+ X; `; {/ }; k( m - if(! $conn )
% j. L X* _* h% z3 `, s* C - {% u! \4 T3 l! _6 V9 m
- die('连接失败: ' . mysqli_error($conn));6 g) j" r8 C6 A, Y5 W8 E: L
- }
4 R1 ]; X1 i# U7 O& y; H" }, ` - // 设置编码,防止中文乱码( Y# u# E: f" V" b! K& O* e2 G
- mysqli_query($conn , "set names utf8");5 L3 Z& @, l) J4 w
- mysqli_select_db( $conn, 'temp' ); * T# @( `2 `7 W; @' N. a2 Y/ M; x
9 i5 b$ M- W6 q- # mysql 锁 $ u& q) O- ~+ [/ W; n
- mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 2 }( z0 o2 a! T v1 T: d
- $rs = mysqli_query($conn , 'SELECT id FROM a');
0 f1 ]# a. R3 v7 D - $id = mysqli_result($rs, 0, 0);
5 D# V% M/ }' { E7 a+ s# ] - if($id > 0)
( |, L+ }" c; R" C! _+ N9 ~ - {
N, H5 E% @9 P) C5 l - --$id;
/ d6 J% X7 o7 u - mysqli_query($conn , 'UPDATE a SET id='.$id); 5 ~2 S* Q; ?9 P) R1 |& t
- }
$ L& L' t% h& D& x0 d+ v
( e; @ T3 @9 {8 a; N- J3 l8 n$ g2 j- # mysql 解锁
: o' @) V. ^) e! w. g& K" u: `4 X- t - mysqli_query($conn , 'UNLOCK TABLES');
0 _, e; y5 [2 w) d# k" A - //查询解锁后的id值8 c5 `8 b! Y/ l4 f
- // $res = mysqli_query($conn , 'SELECT id FROM ta');9 W4 I( A' q& |; w8 |& ?
- // while($row = mysqli_fetch_assoc($res)). o" [8 [$ l- M8 c3 b$ J w
- // {
$ S! D0 Z) R" o+ x - // $id = $row['id'];6 U( ]2 a' ?9 H9 y: u( E
- // }# l2 u4 }8 M$ k" Y: @$ m
- // echo $id;
复制代码 6 M- x K5 o% i% ?2 B8 K8 @4 C5 e
5 O& c- O: X4 l) U
! ^! y' ]6 k( M' {2 t: p2 b* BPHP文件锁示例: - /*
& y' M# n) R7 V9 W' y8 q; A - 模拟秒杀活动-- 商品100件0 H. d2 f# g& ] t7 K! O `! S2 A
- CREATE TABLE ta
# J0 K& }" f+ j1 U - (
" ~. ~8 |, x. l# O - id int comment '模拟100件活动商品的数量'- k' E, j+ F& I$ U( b7 A
- );
: S3 D, y) v7 K - INSERT INTO ta VALUES(100);
8 `: @. X* Y$ S0 R( a# A$ a, ]0 f$ m - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
' ^ V$ u- {( J- m3 p# b8 G" V - */
7 @' X5 ~: J' w; j8 y( I' g8 @5 C - " ?. C+ ?. S7 j L4 t5 w
- // 关闭错误报告
* Q7 |8 f( s4 G" K, o6 G. D - error_reporting(0); - U: A9 \$ k. K
: l8 B. H# U/ ]9 j. ^. E2 o- $dbhost = 'localhost:3306'; // mysql服务器主机地址
) B* S0 i: z% v, e3 Q7 E - $dbuser = 'root'; // mysql用户名/ {/ t. x( |% J- C: M9 P5 B3 e
- $dbpass = 'root'; // mysql用户名密码9 A2 a% O# E3 k, u B
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
5 O4 Z0 O3 D& u8 h - if(! $conn )* ~. O" R" a" M; F4 |8 w7 G
- {
) e9 x) R" D# o% B - die('连接失败: ' . mysqli_error($conn));
# c! }& h8 d# H1 G! O7 T: @5 ?; v - }9 t9 D! k! [8 h0 Z' l
- // 设置编码,防止中文乱码" Q5 i {3 m# L( n2 r
- mysqli_query($conn , "set names utf8");
7 Z2 R8 R! h" N: K* \/ f0 ^ - mysqli_select_db( $conn, 'temp' ); 8 _& x6 e8 @# S
- 4 O8 v* r- k0 i7 f) A
- # php中的文件锁 2 I' e9 E) O7 u6 K+ K
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 # ~, P! a* {# v
- flock($fp, LOCK_EX);// 排他锁
- j, M4 \& p5 F1 [; _5 A
6 T3 d& A, k& F, W n x- $retval = mysqli_query($conn ,'SELECT id FROM ta');
. Z5 X6 w' f- m6 ~& K2 P4 k0 C0 W - while($row = mysqli_fetch_assoc($retval))
3 W4 R6 t, n& b7 v - {
$ P* e: \6 u5 y0 r6 i$ A- J - $id = $row['id'];
: g; q# H9 _/ b, [! }1 t* x, M - }
3 z+ k7 X5 }+ ` - - Y! d Q5 X% v) b& E7 T/ n
- if($id > 0) : V( K6 {- p) T
- {
! I; a& X; }+ R6 R- y - --$id; 0 ?8 D( R/ a" Z
- mysqli_query($conn ,'UPDATE ta SET id='.$id); ( Q/ F4 ^4 |; x& a9 k
- } 8 R! o5 u5 e; y1 t+ _
- # php的文件锁,释放锁
, F8 j) }3 a g+ f# f* G5 Z6 b - flock($fp, LOCK_UN);
+ n) g3 i( d% I: g |1 ] - fclose($fp);
- P# w7 v8 w# @ - 0 I! P; v9 Q6 u
- // $res = mysqli_query($conn , 'SELECT id FROM ta');7 m$ w0 t. [! \. M0 h4 n2 l
- // while($row = mysqli_fetch_assoc($res))
) g, l6 c/ g x - // {
9 A. P; p5 i6 T- e" `: x: J - // $id = $row['id'];( l& s$ ` N4 C6 p7 ], K
- // }
0 q( B! y/ I( w% [ - // echo $id;
复制代码 6 I& n9 T: l$ X1 B, O
* X6 W! T4 f1 p6 ]抢券活动实例: - public function envelopeSnatching(){( y2 B- u+ _" v# H
- $lingqu = $_POST['type'];7 |5 ^$ j' A# b k
- $uid=session('u_id');//用户id
6 \: f* d q; N8 h3 A, w - if(!$uid){$ R# d- l8 ]! D% I2 y
- $data['msg']='您没登录,请先登录!';
; s, _% i4 S* N! h! d# u - }else if(date('Y-m-d') != '2017-12-12'){) W; ~2 X+ W4 u' c$ s
- $data['msg']='不在活动时间内!';
1 p# d* p7 w j; U - }else{- p( |, G" L. z, C' d
- $hours=date('H');//当前小时数& {! a; }, L9 A/ O7 ?3 q
- if($hours > '09' || $hours > '17'){
) e O8 y4 Y: ]8 x* J - ) c6 ^" N8 ^5 [! x( \$ g
- if($lingqu == 1 || $lingqu ==2){//点击10点的
; d7 ^$ a! {9 Q+ F- v m( [! J - if($lingqu == 1){
4 ^ i0 c: l9 M. b3 v' @ - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过* C, f7 g- d' d$ z! [* C
- if($hours > '09'){
+ K7 e, y" E' I1 [3 h, d4 b - $num=mt_rand(25,28);//优惠券金额
4 h. y! [0 T( f) q - $id=1;
" G2 }3 r! r$ ~0 h; v( m1 X - }, h" o) E1 @& Z8 ^ t9 W, e: i
- }else if($lingqu == 2){
* D+ W# N6 Z2 c% z! M+ @8 N. ^ - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
% }0 t: p8 M5 B2 M0 k/ L - if($hours > '17'){( F( V6 s0 g: V p* u9 M$ F
- $num=mt_rand(50,55);//优惠券金额
! I" y. y! `: P# M5 m - $id=2;
" [$ c$ h: a" }2 ^8 B8 P: J6 { - }7 |; i& J, _% K9 e1 `# v
- }* H7 u O$ s7 Z- r# r% N6 F4 \
- if(!$id){
$ a6 Q& A z9 i7 C - $data['msg']='时间还没到,晚点再来吧。';
" u0 f' G8 T8 Z6 N: m6 P - }else{$ |9 L" o4 H6 J7 R; h
- if($is_lingqu){
$ e0 M4 T* S$ b8 G# E0 h - $data['msg']='你已经领取过了,留点给别人吧!';0 ]" z5 B7 I0 p8 @" ?
- }else{
/ f* p8 |) b5 ~) k4 ] - //锁表& r5 |- E3 Q! N3 `( x
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');' m) D, S1 O' k) r$ e5 A3 k
- $active=M('active_num')->where(array('id'=>$id))->find();
2 d% Y+ u5 [- {$ n, Q) w - if($active > 0){4 F& t( H8 ?! b
- //开启事务
m( m- r) B4 w2 _" r; a' F - M()->execute('start transaction');
/ ^$ q& e/ I* [0 b; v - $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));5 \. y; u6 ^& u
- $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));! W. V, Y' q8 P# R! v* m4 s
- $members_preferential = M('members_preferential');
0 z; y8 u* o( y, F - //对应投资金额,0 L/ i4 |, t3 q% V; l# j/ ^
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));4 [$ D1 p3 m, o- }; k/ m
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY'); |. q6 h& Z( k+ p! X& k2 F
- $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
: X2 o2 w3 d. s3 C' [: e" t. D - $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券: ]% S6 k5 ~; G$ P% i2 A
- if($save && $add && $add2){
( A; L( B! t- Z8 F! [ - //事务提交
0 I, I8 U( W1 M. a - M()->execute('commit');4 F) Y& L3 c& ?0 `% G* ]7 z
- $data['msg']='恭喜你领取了'.$num.'元优惠券';( `* }3 }; g( [$ r, k' q: U
- }else{
' g0 ~. @, i9 X9 _9 |% a - //回滚
. U* P5 F) `9 p- { j! Q - M()->execute('rollback');* e h V: \$ t) A5 ?) b
- $data['msg']='未知错误!'; ^% k' J% i9 G5 `
- }
% U7 j, e! o s - }else{9 B$ K6 P. E7 W# n6 U
- $data['msg']='红包已领完,你来晚了!';
1 |3 ]8 d8 [* f1 t" J - }
7 ]4 T7 C4 c1 s. m - M()->execute('UNLOCK TABLES');
0 ^- }' e; j9 i6 v3 k$ Q - }
& l, B, ]1 `) ~" K - }8 |' D7 q: V9 r1 C
- }else{
& q* S# W2 K6 c8 `- H - $data['msg']='非法操作!';
! O& E v5 \ V* A/ G - }, ^ T7 ^! h9 ]& h/ w/ F
- }else{% R; C! @( e, E' L, y
- $data['msg']='还没有到活动时间,请晚点再来哟!!';
& v) V# r( x. |4 u1 E7 M9 L - }4 a, P$ }3 c, t5 q% V
- }
+ ^; a" H7 t0 Q+ q8 P, T - exit(json_encode($data));0 a1 K! {/ h9 Z
- }
复制代码 1 s! z7 Z6 ]1 Z# R0 `" d
. J: K3 h- K3 U3 F7 H" z |