|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
+ R8 i% f! w X. ]4 jMysql中的锁语法:
, _5 q' R, V+ C7 k" o$ s# PLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】' }! w' ^ ]8 R+ N
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
! L; R3 Z# L6 k# ?; P9 T' tWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞7 d" z5 V% n7 k- I
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :
+ w$ U. q3 D7 F# x0 d9 v文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
7 z! m$ U& k# N# [9 w4 v- i测试时,有个文件就行,叫什么名无所谓 总结:
6 @! f+ g2 B: ?- g" b- r5 W项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
& B# H0 l( r; }4 \8 E+ i1. 高并发下单时,减库存量时要加锁
3 j- g2 U. |! C2 z/ O2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*4 q$ D( S: j, w C- ^, d% _+ w
- 模拟秒杀活动-- 商品100件3 g% R* D7 v+ i$ M
- CREATE TABLE ta+ N1 c. P. B. i; G0 D( A2 o
- (
! }) [* J$ }3 Q6 h) b" ^7 } - id int comment '模拟100件活动商品的数量'/ g6 s$ }, v+ N8 [8 o
- );+ _. j5 Y8 K% n' c$ H
- INSERT INTO ta VALUES(100);4 }" ?: I6 p4 H# t5 U% q" U
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
' l4 E- _2 \' Q: Z - */ * A |" A, B; J' X
- ' R& P5 X" p+ ~/ ^* N8 s
- // 关闭错误报告( G) P! D0 \1 v$ Y( g8 @/ `2 O' n
- error_reporting(0); 4 Y7 \$ T1 a3 c/ p* J$ r5 X
- 9 f6 v5 F! K- A6 |9 u
- $dbhost = 'localhost:3306'; // mysql服务器主机地址
& t C; F$ Y# {: l( g - $dbuser = 'root'; // mysql用户名
! e0 H* m2 H' r8 ^ - $dbpass = 'root'; // mysql用户名密码
7 [' @0 h; h% d1 v" ?% E* e( ~; x - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
$ t% Q( Z: s4 j: g! M0 P - if(! $conn )
* b) P4 S3 V' g8 ]( v& z( V - {: x9 z% o* Q" }2 u
- die('连接失败: ' . mysqli_error($conn));0 `. s1 b6 D) H; e$ w9 t
- }
& R( ^3 A% W: k2 m- e$ b" c, J - // 设置编码,防止中文乱码
$ F4 v1 j& [5 z a' ? - mysqli_query($conn , "set names utf8");! s# m* Y' W6 N5 d/ L7 F
- mysqli_select_db( $conn, 'temp' ); $ P6 T- E- D5 A# O7 ~ R$ m
- ( \* D( j7 S# c6 R
- # mysql 锁
) f6 t; G f) @% q5 P! F2 b! d - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
, T( U0 j( ]) x - $rs = mysqli_query($conn , 'SELECT id FROM a'); ( u8 H. x- r2 g, w
- $id = mysqli_result($rs, 0, 0);
5 g1 s4 v6 N( n - if($id > 0) & w8 m7 c# m; C0 ]) D3 i* |. O& W
- { * a$ V# [1 V& o& d
- --$id; $ j) q. t8 i! \7 n2 u2 P6 d
- mysqli_query($conn , 'UPDATE a SET id='.$id); " {) I0 N# e: A, g5 U" K5 `
- }
3 P& L( u9 g) s. I - 3 w- M- b! j: h% A4 ~
- # mysql 解锁
5 P" f4 b8 ]; w* M - mysqli_query($conn , 'UNLOCK TABLES');- A$ N% U7 A6 C/ ~
- //查询解锁后的id值7 o( f# F# u! I% X, f+ R! e7 t7 u
- // $res = mysqli_query($conn , 'SELECT id FROM ta');
6 S( z3 a4 O8 M# b - // while($row = mysqli_fetch_assoc($res))( n- Y3 I( I8 l0 w ?9 l& ?
- // {0 j3 d4 P8 C; c/ j6 Y2 K
- // $id = $row['id'];
* }. y% q+ G- R: f/ u/ N - // }, }7 `% _' @6 k: a, `
- // echo $id;
复制代码
; U+ a. {, F h2 z5 H* m
& V4 x0 a- u: ?1 k/ V$ b! S* W8 B' _4 J4 i0 v4 _
PHP文件锁示例: - /*
) Y8 g4 Z+ H1 i& \0 a2 k( X - 模拟秒杀活动-- 商品100件
) J* H' P0 e2 x$ | - CREATE TABLE ta
% ]3 r$ e0 C3 y# [; A* ^) C - (
. {+ p* U& J; t) Y! u( Y) r - id int comment '模拟100件活动商品的数量'
- k- r, w* I/ L# R3 v. i4 H - );- `0 [% i' u1 Q7 n7 d
- INSERT INTO ta VALUES(100);
$ _" R( s1 \3 D1 r3 S5 {& F - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
5 v5 t0 R( g0 r - */
. C* p& N y1 ?1 C5 u- P, Y5 b - * F8 b* G7 ]5 y7 ^4 Q& h* m9 i- i
- // 关闭错误报告3 R- n1 `0 I [/ i% `7 ]
- error_reporting(0); $ v. F' F T5 o, _% C! v3 d% R
4 r# ?" O9 G; m$ J" U- $dbhost = 'localhost:3306'; // mysql服务器主机地址( L) L: l2 _2 d
- $dbuser = 'root'; // mysql用户名* u) H2 j* o4 w" x: t2 n
- $dbpass = 'root'; // mysql用户名密码& h) v5 C3 L) @2 Y# @& _2 J0 T$ e
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);+ y, Q7 e! r# y
- if(! $conn )
# Q- D+ \+ A5 z: ^4 f h - {# {9 V) q8 t6 [" o0 E5 A8 J. O! v
- die('连接失败: ' . mysqli_error($conn));
. m- m6 T1 w4 ^5 r n7 ] - }* q: U$ l. X4 ?, c
- // 设置编码,防止中文乱码
0 q/ J/ N3 N0 Y, Y! d$ F# k - mysqli_query($conn , "set names utf8");
- n. r/ U0 X- b# E: V$ D; s - mysqli_select_db( $conn, 'temp' ); 0 ~: B8 E' E% a. L0 {
- & T4 y) z& I7 J5 R+ R" p
- # php中的文件锁 8 \3 s4 r: Z7 P# Q. G, y W, L
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 ' y3 O( z9 B. x, V
- flock($fp, LOCK_EX);// 排他锁 - N4 k. M* H( d
9 W. w2 d. c! T- $retval = mysqli_query($conn ,'SELECT id FROM ta');
+ f: a( r9 z3 { - while($row = mysqli_fetch_assoc($retval))
9 ^& W) W- ^3 Z8 ]( P) V0 Q' Z! P - {1 }, Q1 T- U! l4 b" o, |2 y. @# d
- $id = $row['id'];" r7 e, r2 Y* D) J: p6 J. z' y1 Y
- }' K+ j5 a$ h% R9 x8 H
- & a# s$ ^' l9 v
- if($id > 0)
8 b6 a* L& E: P1 _- i - { * l, U& j" b# e" ?4 O1 a } M' t3 B( F
- --$id; 5 i0 c/ r7 P6 B) ~4 `
- mysqli_query($conn ,'UPDATE ta SET id='.$id);
- ~% g6 e5 j( i - } - h( G0 q0 M( u! m& f* E) p
- # php的文件锁,释放锁 ' k3 ^% N" c# O6 M% B
- flock($fp, LOCK_UN);
/ f; Z; I: q8 i Q! S - fclose($fp);& l" D. [ E2 D* d
- 0 n8 k) V6 V: K- Z6 n
- // $res = mysqli_query($conn , 'SELECT id FROM ta');; l, K* e: @- u& I- ?. u
- // while($row = mysqli_fetch_assoc($res))* h3 J" a2 r' y' J; q) y6 d% Y
- // {
0 q, D+ `* J$ p" W% K; d1 W: O; m - // $id = $row['id'];5 U* {3 t5 t9 {% ]. I9 y
- // }
$ r! m: G' X' ]( J0 s - // echo $id;
复制代码 5 l+ C( t7 R( b& a
1 u( l' m$ h- v/ `
抢券活动实例: - public function envelopeSnatching(){
) D, Z' H v- e- ]0 K" }( F1 { - $lingqu = $_POST['type'];- T8 r7 H- [; x" H0 ^% y
- $uid=session('u_id');//用户id
! ]1 a2 G# H+ _ - if(!$uid){) _4 g, ?4 t. e1 _; {" e
- $data['msg']='您没登录,请先登录!';
8 {4 W0 c% X; f - }else if(date('Y-m-d') != '2017-12-12'){
. ]5 n7 ~1 J* b, [( |3 t6 i) M. T+ @ - $data['msg']='不在活动时间内!';
3 |% c3 @$ f: o7 I& H - }else{
& [; P! ~" G, r. ] - $hours=date('H');//当前小时数9 ]; r9 C2 p8 M# }7 L* ]5 x
- if($hours > '09' || $hours > '17'){
1 i7 i" _6 X4 Z, _/ e - " \4 G* G) t; Z% q
- if($lingqu == 1 || $lingqu ==2){//点击10点的- ^$ @ ]/ L" ~2 I7 r) ^7 x
- if($lingqu == 1){
. b) P1 _% Z8 i, l/ J, W - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
4 l2 T j9 \6 ]% N. L - if($hours > '09'){* u. s P, o4 d4 c3 X' r; e& }, Z
- $num=mt_rand(25,28);//优惠券金额
( m; }* F0 I9 z* W8 O/ B5 a/ b - $id=1;3 p6 |+ \* t, Y* S0 f! T: N
- }
, d' K7 V, k0 l, o6 @. ^0 F - }else if($lingqu == 2){ x$ N% \! @& \4 m% k! S
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();5 n' T8 r. y, T2 t. i8 W3 p
- if($hours > '17'){
0 `+ {( _: T! Q; V( I2 C0 Z* P - $num=mt_rand(50,55);//优惠券金额
" q w' H' b8 T- k2 L3 T - $id=2;( o/ ]2 {3 O- k0 @/ {
- }
# J) E/ i4 B# C - }4 }. T0 a" F1 q3 M
- if(!$id){
! ]+ }9 Q; \) {% Y) Q2 T7 } - $data['msg']='时间还没到,晚点再来吧。';1 c- S* {3 m2 M$ n
- }else{
* C5 Z4 r0 l7 u, v - if($is_lingqu){. `1 k5 l% S; x3 K' l1 J5 o
- $data['msg']='你已经领取过了,留点给别人吧!';* f4 r+ Z) X# ~. c: n
- }else{( O4 N. E; {- h' B
- //锁表) a8 T# f" D) [( G
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
1 N1 x0 F# E; N( G - $active=M('active_num')->where(array('id'=>$id))->find();. Y9 d7 p$ x$ i( |
- if($active > 0){
0 D; q4 W8 r0 J - //开启事务* j t. O9 E5 f6 i/ P- L( z. Y
- M()->execute('start transaction'); q$ a1 i% i' a: h- n, O
- $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
, r5 l( {, X* G n; o - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));( b$ U; \2 Y& d8 {- X
- $members_preferential = M('members_preferential');
) x0 }6 U8 Z' [( k& r - //对应投资金额,
" k* Q; d0 [' Z; K$ h - $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));2 ?. b# ?- i* ^* X1 ~( S
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
3 ~/ r5 v" Q7 B, F$ R: M - $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
1 h* {2 @6 F4 J2 [" i/ \ - $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
& N* k5 c' V9 Z3 K, @ a - if($save && $add && $add2){
2 l J1 b" c; Q' w/ n) h% z/ N# ]! ? - //事务提交; @- _% ?" b' L. P. M' ^# I
- M()->execute('commit');
1 H' I( u5 N/ l - $data['msg']='恭喜你领取了'.$num.'元优惠券';) B, m& O" w& E% S
- }else{
6 B) \+ ~8 X- `7 f! w; N1 U - //回滚
1 t z/ {% J o' M+ n" P - M()->execute('rollback');
. i9 p9 s, q8 e* ?9 m. k: U - $data['msg']='未知错误!';+ ~/ o8 |8 ^7 P3 u- x ~
- }
( b, ?! p5 f4 e9 A, i# u7 r; p - }else{
( \& Q7 H, @0 F+ ~% Y+ C! y - $data['msg']='红包已领完,你来晚了!';
6 R$ H: Y) Q' ?. s6 t2 i - }1 F# H7 }/ K. A& X6 Z2 G
- M()->execute('UNLOCK TABLES');
; t9 R3 a* T% ~$ Z% n4 Y - }
( \* `' G' @9 S - }1 H& L4 Q$ Q( n) E* Q# c7 X
- }else{- j2 M# H3 w! p6 n# S, i
- $data['msg']='非法操作!';0 r$ c! c1 Z" [' N: V Q
- }: _! N% b/ u1 c$ f9 m2 Q* e
- }else{% E) }2 _) X& x9 M6 Y9 Q/ r2 \4 ]7 r
- $data['msg']='还没有到活动时间,请晚点再来哟!!';3 y! M7 S3 X) j; u2 U. n
- }% h- N/ ~. j2 P5 F6 E, ?
- }1 b4 O, B T% N+ I; X6 k. u* g
- exit(json_encode($data));
E& J7 a: @+ B - }
复制代码 7 _9 I/ ^5 a% X+ a6 }+ C) ?* R
* k- R- |+ N: x; b' V! _
|