|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
1 _' L, Y. M @Mysql中的锁语法:( ~( G4 n% `" z9 h3 ~7 v: c3 R
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】% {7 I3 b2 W {: [ N+ p& V
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
( I j/ f" |( G2 GWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
: D: U- o x3 M注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :
8 c! ^+ ]/ \ n6 C7 }9 w9 L文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
: E2 l! T, _' Y4 `! v; N测试时,有个文件就行,叫什么名无所谓 总结:5 X: X) K" E- C/ q1 H- H
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
/ t( |5 H9 b# X. b: z% K1. 高并发下单时,减库存量时要加锁
5 l4 O& d6 J$ p6 ?/ e2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*
& u k) V3 C2 {: A$ R - 模拟秒杀活动-- 商品100件1 h8 N5 ^' k5 e) y+ j
- CREATE TABLE ta
; n4 A+ ?1 Y! k" p1 ?3 b - (0 s; s+ T# c# m; u+ a4 o
- id int comment '模拟100件活动商品的数量'
, w* E% M6 q0 r( P+ _) n$ B - );
w9 Y, W" S1 O! m/ ^ - INSERT INTO ta VALUES(100);
' E( }& O1 w& w1 p% z1 K( { - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
, y2 o. b, A* M& R7 Q - */ + ^2 E; I U3 e$ x' |( n- ~
-
6 C3 Z, ^% q$ l8 l& K. G - // 关闭错误报告
- ~0 S1 _* k) d6 N+ q- L6 W% x - error_reporting(0);
: V8 L# t8 x+ g0 d5 B
8 S3 n V C- L6 J" @5 _ T: g- $dbhost = 'localhost:3306'; // mysql服务器主机地址
; ?! y, f, ?' {: N' v3 S. R! B7 | - $dbuser = 'root'; // mysql用户名
% l2 g8 d4 u4 S$ Q: V7 k& [3 X - $dbpass = 'root'; // mysql用户名密码. X) K, u& t$ p6 {
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);& b( @4 Y% ^$ k$ b9 t+ L1 ~
- if(! $conn )2 n+ o" k3 ?' l+ H3 D# ]9 y
- {* b- C5 t0 I6 K8 S$ W
- die('连接失败: ' . mysqli_error($conn));
; d: @- D. l% }( C; M9 ? - }
2 M8 @4 W0 ]# H$ t, D! c - // 设置编码,防止中文乱码$ I4 m1 l) B: J: r0 m* F) r6 P
- mysqli_query($conn , "set names utf8");
& C+ V. Z7 H* h. h) k - mysqli_select_db( $conn, 'temp' ); 1 T( F" ^- |( `% W9 }/ Y6 Q
- 7 E. g. Z3 I* t" b1 V
- # mysql 锁 6 g6 Z! e) n9 J B1 B, r- `$ ]
- mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 / k6 g% h7 L; d1 [
- $rs = mysqli_query($conn , 'SELECT id FROM a'); 3 N+ l k- C c O! j. `2 a
- $id = mysqli_result($rs, 0, 0);
& c" C M. e* A: Y - if($id > 0)
& ?. v" _) y7 X) m. \/ a - { 5 M1 ^' H' \4 X2 F" I
- --$id; 7 \, ~1 X7 n1 y& K2 X; b
- mysqli_query($conn , 'UPDATE a SET id='.$id);
( z0 F9 `# ^8 k& x/ n - } . i5 x; k' r! H0 w
/ M# U$ y' b* H2 q \- # mysql 解锁
' D e9 v& z' F - mysqli_query($conn , 'UNLOCK TABLES');8 ^) E3 ]3 J# v& E- d/ W
- //查询解锁后的id值
7 t$ d* E8 p$ ~6 w9 z- h/ U - // $res = mysqli_query($conn , 'SELECT id FROM ta');
9 i$ e' p! O3 k+ X - // while($row = mysqli_fetch_assoc($res))% Y' a! T3 `7 \9 |3 _* Q
- // {8 V; b) u. n& H7 d
- // $id = $row['id'];
0 U O1 E! G9 i c3 W5 [4 b. Z* r - // } P+ _! L' x( r; w+ k3 l
- // echo $id;
复制代码
( \5 Q6 ]# I9 y+ a" Y) D3 x7 i t4 X6 h# W; o4 j5 r$ E# T* F/ k
) \( v: q& ]( o" gPHP文件锁示例: - /*9 Y( g h/ A; K, w
- 模拟秒杀活动-- 商品100件7 b4 x; t, h( T6 c+ z. B" b1 [( N ^
- CREATE TABLE ta
4 v) r: h$ n4 |; Q0 X5 c - (
; W7 y; I1 n. C - id int comment '模拟100件活动商品的数量'9 u6 f G; F' y c- u
- );8 [) z7 M$ P% E/ w4 n6 I
- INSERT INTO ta VALUES(100);: [( A. B0 n6 o1 E U; O. }
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件# a- q% u, L1 q. s
- */
; P; M6 Y N C! f3 N - - K0 Q1 L% I- a& r$ ]) n, f
- // 关闭错误报告
8 S* P9 E2 D3 c% c7 p3 i* ? - error_reporting(0);
+ A8 G- ~, B; s/ T) f
1 G, x) F; [6 C% Y) w- $dbhost = 'localhost:3306'; // mysql服务器主机地址5 |2 F) M# ?4 a" F% g! s. e4 v3 M
- $dbuser = 'root'; // mysql用户名
" W7 G" M$ W n; N+ S9 Z - $dbpass = 'root'; // mysql用户名密码6 M: E% r7 V! H6 b7 s2 P1 j) f
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
. W4 z, B9 Y U& l4 r3 ^3 z - if(! $conn )# A0 z/ A; F' k) b0 _* s3 s! `
- {- ]: K) Y. G! O* q
- die('连接失败: ' . mysqli_error($conn));% h. [* B/ V; {+ L x* K& h
- }
: D S) M r/ ^3 Y' V% V - // 设置编码,防止中文乱码/ T& D4 M4 ?6 q5 L3 b
- mysqli_query($conn , "set names utf8");
6 k* e3 S) v# _+ }' z Y. W - mysqli_select_db( $conn, 'temp' ); 6 V! k& u& c C E) D
- 6 L% h. W9 ~, K3 K3 E: s
- # php中的文件锁 5 s8 e6 U6 O Y: E- C" L6 D, _: @
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
6 o5 q, x' T7 Z9 w8 a - flock($fp, LOCK_EX);// 排他锁 . _$ h! u' x$ H% S* _, O; C5 ^6 Q8 i
- " u" c E, F% y% V1 }" Z, \
- $retval = mysqli_query($conn ,'SELECT id FROM ta'); # N& e2 ?) N1 g& f m. K" k
- while($row = mysqli_fetch_assoc($retval))$ J7 f, ]0 U, n! U/ u( p
- {
( }$ y# P, N/ }3 Y: ~ - $id = $row['id'];
* H* ?5 Y/ }* c- M - } o! d' T& R' ]! x
-
j, J+ ?+ ~( k$ ? - if($id > 0)
8 `" O: y- {9 y1 K6 Q9 q; a) L' U - {
* ]% ~: I+ I E; Y, k H, x - --$id;
, k% e4 j4 U+ i( [ - mysqli_query($conn ,'UPDATE ta SET id='.$id); 2 X1 d: [. T' X9 R2 ~
- }
+ j' M/ t2 O7 n5 D5 P - # php的文件锁,释放锁
: \' Q9 w0 e2 p9 t3 c - flock($fp, LOCK_UN); # t3 Z5 @# ]/ x3 Y6 G* y
- fclose($fp);3 L3 E' k7 o3 |! x0 V
& i# [5 x9 Q8 ]$ S! @: \% J- // $res = mysqli_query($conn , 'SELECT id FROM ta');/ k# s& t( j' l8 N; W
- // while($row = mysqli_fetch_assoc($res))( I+ x! ?8 Q1 J0 P/ `& i2 ?7 L
- // {5 U- d4 L& S7 @
- // $id = $row['id'];
0 {8 r- {; p$ }, g5 A - // }
. S$ ]8 r' a- u9 f; C' K: B) u% p - // echo $id;
复制代码
0 w$ H) Q; }; X3 b3 Q8 N6 M7 D; n( G
抢券活动实例: - public function envelopeSnatching(){
& j L0 R0 P( y7 q3 e3 o: H - $lingqu = $_POST['type'];
, Y3 J H" L9 D$ {/ H - $uid=session('u_id');//用户id% c2 y9 b6 |6 A* j0 n% X4 O
- if(!$uid){
- ~5 k) c+ o- _) ]" p5 U( I - $data['msg']='您没登录,请先登录!';( m. d. v4 m) @0 ]' {
- }else if(date('Y-m-d') != '2017-12-12'){' w& n& G$ ?3 h8 v* B
- $data['msg']='不在活动时间内!';
( t% D9 l8 u4 @& |- L+ j - }else{
/ S+ [2 L. ]- N G - $hours=date('H');//当前小时数
`5 R* h( M4 O6 f; B7 p - if($hours > '09' || $hours > '17'){
5 c8 U H4 T2 f0 {$ U! W
' P6 ^6 Q, [/ Q6 o- if($lingqu == 1 || $lingqu ==2){//点击10点的6 X& g$ X7 ~; y, O$ L
- if($lingqu == 1){
1 Y7 q: t; w: k3 o& U4 I - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过, F2 x& Z- M" P- Y% R' L/ S2 r% G
- if($hours > '09'){
8 F; r0 }) E" Z" F - $num=mt_rand(25,28);//优惠券金额
! o" a8 B7 y+ E. z { - $id=1;, E4 ]' u$ x: M
- }
/ @: M I" R5 T1 w, f; X+ W9 v - }else if($lingqu == 2){% E+ g/ n: l: U A, e% u
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();. X+ p" b2 h! o0 T, u& a4 S
- if($hours > '17'){
$ n9 j- C3 R0 w p+ s - $num=mt_rand(50,55);//优惠券金额8 F. U* e5 M5 H( Z& `) U' q0 Y' }
- $id=2;
2 E/ ]# v4 f% N - }
7 O% Y0 i. P) `+ n5 v1 v4 m - }
; V3 R& a+ E/ V5 z: l! V% b% O - if(!$id){
; m8 _5 e. g( S8 Y" R3 |# S# s, W2 w% r - $data['msg']='时间还没到,晚点再来吧。';
& R- @* s) o" _7 t4 D3 m* Y - }else{/ h `) ~ ~0 ]9 Y$ Y- j8 E* n5 |! K
- if($is_lingqu){
" `+ w& ? _3 |6 ^ - $data['msg']='你已经领取过了,留点给别人吧!';" w0 L& v7 A9 [& S& c
- }else{
& o& H- N9 [9 D) w& I: @% J6 Z - //锁表 i K' n# d3 |* n9 Q" L( ]
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
$ I0 X3 I- Q; s3 f0 b - $active=M('active_num')->where(array('id'=>$id))->find();& b3 z J7 s/ Z
- if($active > 0){
7 `7 ? [. a( u/ v+ E1 ~ - //开启事务
" B( f( M3 I5 M8 p& K - M()->execute('start transaction');
( ^# X4 t- E6 b$ b - $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
. H" _: c& V/ ^5 o1 X2 z - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
, a8 W' U. o2 H" {8 ~2 \ - $members_preferential = M('members_preferential');
; L F8 e( P0 X9 k5 f0 P - //对应投资金额,8 d9 e w6 B" Y, H% h
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));. O3 u5 C4 h* l- O' \, B
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');9 o1 g X4 W7 W! X3 S+ ~, Z6 B+ y
- $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间% b4 Q+ F' K8 S0 k0 U0 e
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
! D, `3 P! j: j; H. ]2 o - if($save && $add && $add2){
3 [" E$ R0 Y! p0 m( s2 \9 m" F - //事务提交, R5 d: q; K1 A% c6 _ j. U! U
- M()->execute('commit');
' u4 q" i, D) H) R. c8 m/ a - $data['msg']='恭喜你领取了'.$num.'元优惠券';
7 j" h5 J) V4 F! y0 r7 J" Q - }else{
& F1 n8 i- a" S* B+ a% Y r - //回滚
: G" W9 O! i/ a G! ^ - M()->execute('rollback');
X' l# N+ r/ H5 C - $data['msg']='未知错误!';
/ I# _. n% f4 D1 U8 T4 c1 A - }
. z% A) t6 \' x- J- B1 p - }else{
' ?+ Z$ h& f% f, C, o- U+ n - $data['msg']='红包已领完,你来晚了!';% H; W9 k$ U" b# U' W$ X; t
- }
/ J; e. T3 X4 Y/ R) s$ }* M) o. i - M()->execute('UNLOCK TABLES');
% g2 Y+ N8 e5 F% Z7 C2 F - }
7 Q' k& ?5 [- ?) O1 H - }
# R& E: l7 R0 C4 D/ z - }else{
% h4 N3 Y; F, S - $data['msg']='非法操作!';
4 J) U w$ J/ K ^/ g a - }! T: `, `+ ^" c) V+ H/ G) ]
- }else{
+ U! {" r8 Y* M/ y) q5 R; H - $data['msg']='还没有到活动时间,请晚点再来哟!!';
4 x; G: t4 [* N+ C8 V7 F8 A - }. K- M3 ~9 C3 {- U
- } Z2 {/ i( g& g. n+ i) G
- exit(json_encode($data));- }4 _7 A9 \8 ]
- }
复制代码
" r, a9 w- k/ t' D' f# |& L
( H4 E. r& R& `6 N/ C |