|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
2 C$ k2 @5 h5 w& t( ?Mysql中的锁语法:2 |; t- @% g6 L' I! z' _- Q+ W7 Q8 D
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
1 h: H# Y% \* S d2 t& T# T/ |UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表( h3 T& L2 Z3 d; Q% t
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞2 g2 U& n9 X. H$ }' ?. T( X! p, k
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :
, E, e( {5 c2 S文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
3 I+ K7 t' E' T2 `: Z! R5 x测试时,有个文件就行,叫什么名无所谓 总结:
' A+ |+ W0 @8 @ ~6 P; k* [项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
9 e6 a- B; y9 z$ `# X' k, }1. 高并发下单时,减库存量时要加锁
. ]! T0 A! Y* R7 d8 J1 {2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*
. o) r* f5 l7 H) h8 Y/ S - 模拟秒杀活动-- 商品100件
8 w3 V6 S$ d/ v" a: n4 j, M - CREATE TABLE ta- h4 j, _ s& ~8 W
- (
; z& X9 j+ y8 @ H - id int comment '模拟100件活动商品的数量'4 K" T0 V+ M% t) I7 J" m
- );# A" j% R; `4 A, M: _: C
- INSERT INTO ta VALUES(100);
# U5 p2 i: x3 S: k - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件3 `) b$ w. Y0 u3 F
- */ 1 k/ v* c9 K% B& P# W4 P
-
" j. c/ U9 N4 N. G" K; C - // 关闭错误报告; g ~* h; M# H# [& ]
- error_reporting(0); 2 R! P& T5 q; v! B! m
- ( l0 p g. Z; n( L5 J. g) @
- $dbhost = 'localhost:3306'; // mysql服务器主机地址. G+ m2 O8 |$ D7 Y9 d& v
- $dbuser = 'root'; // mysql用户名$ t) b* H! Y4 {: K2 R6 Q
- $dbpass = 'root'; // mysql用户名密码
, @" z$ k7 s6 U, \, v Z! S - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
2 p5 I( g* y7 Q: h9 K' v - if(! $conn )3 o& `9 u$ ?$ ]. [( r( l
- {# `8 @: G, i' n
- die('连接失败: ' . mysqli_error($conn));
& o/ U$ R8 O1 ]( o2 m3 f - }3 N1 [1 Y+ b% h, W
- // 设置编码,防止中文乱码0 e3 c- s7 Y$ Z) q- c- L
- mysqli_query($conn , "set names utf8");% Q* ~- R% ?9 k5 u# e% o" V8 f4 P \ a; F
- mysqli_select_db( $conn, 'temp' ); ! A5 m' U, F6 G" p9 Y% W
# `! q* e( D: a0 V( s8 P: G7 E( \4 }- # mysql 锁
) Q5 q4 R2 ?/ m3 f - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 % N3 ^9 _$ e, `! ^- N
- $rs = mysqli_query($conn , 'SELECT id FROM a');
1 D9 Q# }' W S [7 a T3 v* | - $id = mysqli_result($rs, 0, 0);
/ y* ]- A) P. E, } - if($id > 0) 6 ~1 H3 j2 q! i. \, x0 B
- {
2 V# Q, Y" v. M* l$ K - --$id;
& Y. u) l3 | Y, s- Y7 {" C - mysqli_query($conn , 'UPDATE a SET id='.$id); 0 Q/ H2 A& K, ?( Z z# D
- } 9 @& O5 {( d) ~5 e
- % ?$ q6 s- X. @' h! Y4 A$ e4 O' G$ E
- # mysql 解锁
. E) S4 I0 U: P1 A! c - mysqli_query($conn , 'UNLOCK TABLES');" j) b, z. w+ I
- //查询解锁后的id值
% ?4 H8 [6 l; w* ?! Y# n; d% y- z - // $res = mysqli_query($conn , 'SELECT id FROM ta');
" `) E1 ]: t' G# ^8 F9 y% | - // while($row = mysqli_fetch_assoc($res))7 H8 @* K: G" E& v
- // {7 x3 i. v- v. K
- // $id = $row['id'];3 `: n# n( N( \5 u
- // }
- S; |1 a. _4 i! k - // echo $id;
复制代码
2 ?" Q8 o! n5 r8 k* a7 E8 H+ x# ~/ m, r }. r9 M5 K
4 n0 I7 n4 Z- d8 zPHP文件锁示例: - /*, g- p8 d/ G* h U s. ~& D7 m
- 模拟秒杀活动-- 商品100件" g- Q Q2 c0 R( A
- CREATE TABLE ta
8 L u- n& n( K3 E8 C$ W6 _) F - (
& c$ e% E1 ]; H - id int comment '模拟100件活动商品的数量'
; t/ D: |, C `; y. D7 [ - );( v4 d* S0 s( W g3 M' C3 @
- INSERT INTO ta VALUES(100);9 @, m$ O# h, M3 H. E- i8 U* R5 X
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件/ p5 C/ t: C' X; @6 G+ Z
- */ ' h; S6 r0 v$ M& n. e& r
-
, |$ C' Q" _! c2 Y( i9 K - // 关闭错误报告/ a1 a$ R! _* H, R3 q( t) N* d# R4 W
- error_reporting(0); + x! r U8 f! ~6 }' o. j# \
3 Z o. w$ t; n! ~5 P- $dbhost = 'localhost:3306'; // mysql服务器主机地址+ {! ^+ w- g4 k# }' Y
- $dbuser = 'root'; // mysql用户名
( M& Z" V' E1 y1 e" U5 V! G - $dbpass = 'root'; // mysql用户名密码
' Q, E9 F& q3 f- G' o: l - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);! p8 [# t9 S4 F# V
- if(! $conn )
6 C9 e% Z6 w% y - {& A1 |) x- n( a! n- W$ T$ k
- die('连接失败: ' . mysqli_error($conn));$ p/ a Y3 i# q; @; N. W0 d6 x) S
- }& u8 @% a; o( n2 P/ \5 [
- // 设置编码,防止中文乱码
( i8 M% m% a' q0 p% y. d - mysqli_query($conn , "set names utf8");
6 A# ?* t# c* @! x7 r. h! D - mysqli_select_db( $conn, 'temp' );
$ e& d; l( _, o+ {1 N/ j' i6 \
$ z( }; ]$ D6 T x* l- # php中的文件锁
( A; |; p. Y; n2 \' P - $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 % Y+ z* {5 Z+ Q4 T: A) L
- flock($fp, LOCK_EX);// 排他锁 ?( N1 Q+ ^0 _% h% l
- " i) X* T/ X2 Z/ s7 v+ J
- $retval = mysqli_query($conn ,'SELECT id FROM ta'); 2 X! u9 @# d; N5 y8 J, O
- while($row = mysqli_fetch_assoc($retval))$ G' J6 O6 {% o2 T/ \4 t
- {
% v8 Y: @3 y; n. n - $id = $row['id'];% \0 Y" g1 d. `, r, u$ d( m+ X
- }
# D& N {% [. _ Y' b" [: Q - ) I1 ~' k" N" y; i+ G
- if($id > 0)
. J9 v9 y4 n$ R* O6 k9 l1 G' P - {
7 k3 ]: }- |7 x6 I$ R - --$id; & U4 o2 {3 W/ R" t% G
- mysqli_query($conn ,'UPDATE ta SET id='.$id);
& [* F9 U( s7 Y7 k$ [ - } , e0 o, w1 J( W
- # php的文件锁,释放锁 0 n' K; {: H. W+ g! n* { f
- flock($fp, LOCK_UN); % z W: K: \! V, b. a
- fclose($fp);
6 Z, h7 U# \, z8 Q# R- U+ ?
z% V" s% M3 ?$ N3 ]- // $res = mysqli_query($conn , 'SELECT id FROM ta');+ s0 O! B6 V% E1 J7 H- ?. t
- // while($row = mysqli_fetch_assoc($res))
$ A( I# [$ Q' p7 h( ] - // {
& P0 ?; v* `5 V& V: [ - // $id = $row['id'];& I# I. |- Z" ]5 u' E& P
- // }
4 C( v7 s4 i' ^ Y. q - // echo $id;
复制代码
7 p/ B# y; n, I* G: A0 y7 [6 Y( R
8 Q8 w9 ^. G1 m. C" K+ I7 m抢券活动实例: - public function envelopeSnatching(){
2 N y% Y% ?" F5 D - $lingqu = $_POST['type'];; a6 r: ?3 E1 P" j. w
- $uid=session('u_id');//用户id1 I' Y; [1 ~6 R* t( S
- if(!$uid){
( S/ V: M% t$ u) T6 d5 y$ X - $data['msg']='您没登录,请先登录!';5 d$ `+ Z8 W* y5 ]+ V
- }else if(date('Y-m-d') != '2017-12-12'){ V- b! Z7 C/ h9 f
- $data['msg']='不在活动时间内!';2 e5 J* j* d- M1 ^( K0 o9 i
- }else{
! \6 J* A( F/ c# `/ K - $hours=date('H');//当前小时数
7 t8 r+ R6 l3 o* r& X9 ~ F - if($hours > '09' || $hours > '17'){
2 t. _. @ Q; a3 w+ Q - ! {& b* `$ B: x3 h. o/ p
- if($lingqu == 1 || $lingqu ==2){//点击10点的
# ~; U; [4 \, r5 n# q& ] - if($lingqu == 1){
/ H( _9 ]' g/ |' D' q. |4 G - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
/ p5 M! u( ?: @) k( ?8 Y' ?3 D - if($hours > '09'){" J- w$ A0 i& }! G; W: W
- $num=mt_rand(25,28);//优惠券金额( _) p2 C- n. I3 k, i1 c
- $id=1;
5 B0 J9 k3 C4 t& Q+ ?1 o3 ~3 X - }$ z' P; F! G3 z
- }else if($lingqu == 2){
, \; m) K6 X, @) d - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
1 {2 g1 v3 @9 u% I3 n: k! N r - if($hours > '17'){
7 o. i& v) s- O- C: u% I9 r - $num=mt_rand(50,55);//优惠券金额
, ]- L) Q) A" O4 g/ f, }& D$ x - $id=2;9 V0 C/ s; B2 c8 q3 W$ B# | m% ?9 N
- }+ ^2 `$ L: L$ l9 p& j g+ c
- }2 V/ n9 f# K' T! j, n' L
- if(!$id){( a' |3 n4 K/ j, U n; F
- $data['msg']='时间还没到,晚点再来吧。';
5 m! O6 v L4 N+ q, V' i- ^ - }else{
; t @4 H3 K/ d9 Y! G9 O8 h# V( x - if($is_lingqu){
- ]% b2 x5 x2 ?1 v7 N - $data['msg']='你已经领取过了,留点给别人吧!';
% \* q6 U6 P' \$ h - }else{, d e' Y1 o0 R7 ~
- //锁表
1 c9 H6 V/ I* p% h5 ^- O - M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
' U! | }" [4 c) I) k8 ^ - $active=M('active_num')->where(array('id'=>$id))->find();7 s* d) X6 m( x; d9 ]( h5 X. t# K
- if($active > 0){ `; q; W: s M7 p
- //开启事务4 s' ?3 H9 d$ n9 \7 a
- M()->execute('start transaction');
3 `4 {" @ H' ?) s/ u4 z6 v' ^ - $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
$ e1 Y, x9 p+ }. y- L1 o - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
w7 c7 ^3 s% y/ }3 v) x - $members_preferential = M('members_preferential');7 O' B: C* F0 A, y) k! O
- //对应投资金额,
u, e1 K0 `, j8 @$ e9 D H - $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));3 @5 M& R5 S; ^, f( S/ m1 g
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
# z. k6 Y$ z! J9 T* O" I; P$ ~ - $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
4 o: x# u- d1 [& V% [1 O - $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
# X! n' I# O3 J6 R - if($save && $add && $add2){
# @& n; m6 T- m, X - //事务提交
' M; s$ o6 ^9 O- |5 Y- G' Z - M()->execute('commit');
, V6 ?2 j! m. ` E( F9 r - $data['msg']='恭喜你领取了'.$num.'元优惠券';7 n6 `, M: b: P9 L9 }* R0 n
- }else{) `) E3 `4 q3 b1 O! p( n
- //回滚
0 L! e8 ?( l5 U - M()->execute('rollback');; P% Q$ C7 o5 n' a( S/ v) a
- $data['msg']='未知错误!';
! Y2 u" B! V' h - } e; r& l9 T: Z7 u1 z& F
- }else{
9 J2 q$ |: w- P R0 T& s4 d% `, } O - $data['msg']='红包已领完,你来晚了!';/ _ F6 T: L7 M5 g
- }/ W, K, a# \, h# i- Q& V; w" w
- M()->execute('UNLOCK TABLES');1 X; |7 Q2 D2 K% k7 L: L- y
- }
: h T9 ]% s! t% E2 {+ I7 Y: _ - }! K2 U& c5 f; ~* U
- }else{
8 ]3 J a/ W4 h7 f6 A- O - $data['msg']='非法操作!';
* ]1 @/ A# W6 d8 K- H2 e - }. x8 {7 m$ @" m9 A
- }else{7 h7 M' e; F! g ^- E/ {
- $data['msg']='还没有到活动时间,请晚点再来哟!!';2 {! ]* T& S3 W l1 l
- }
5 K: j) p/ m n' ?4 W1 D b - }
9 v" Z& ]3 @! V5 S - exit(json_encode($data));8 S9 r1 D# n' k" F4 u6 U
- }
复制代码
8 Q$ k$ S" r0 Q6 `$ q& w" E" X) Z% c0 D z$ D! G
|