|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
! r8 w7 i1 l: \4 kMysql中的锁语法:* E+ L$ ^! [8 {* N% x# r+ X
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
$ K1 B' ~$ f1 x- oUNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表, d7 k* B( M9 g/ [
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞; q) n3 k( v( u1 E
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :4 F* C1 u \' S% E( V4 U
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。0 }1 p# c; r. ^
测试时,有个文件就行,叫什么名无所谓 总结:
: V( B2 k4 E- t项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
# Z; ~ ]1 G: B" n: r/ \# |( \1. 高并发下单时,减库存量时要加锁/ c. Q- [4 ~2 n, Y* L) J( g: }
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*
0 V$ y: U4 w+ m V" N6 B+ f - 模拟秒杀活动-- 商品100件
6 s) i. o! q$ |$ `! N4 J - CREATE TABLE ta( Z% ^- H' P+ p/ U" I5 \* J9 g
- (
1 `: f9 s; A: g L [- Q6 s" Y - id int comment '模拟100件活动商品的数量'
( ^8 L; j& g, N, u4 x1 ]. W - );
; V7 l& l& I2 u" l" W+ X - INSERT INTO ta VALUES(100);
1 t L/ [' m0 w$ t6 n5 l3 L - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
7 N! b& n. |( r2 E/ D - */
3 l6 W; V6 W2 r: h - & S% r; z5 j6 a
- // 关闭错误报告; s/ d) o9 m. H$ e
- error_reporting(0);
: P4 Z( ?" V4 V0 A - 0 }7 r5 ?; @! _
- $dbhost = 'localhost:3306'; // mysql服务器主机地址$ D" A A& v: s0 ]! M
- $dbuser = 'root'; // mysql用户名; E9 B( A* q. c) N- `
- $dbpass = 'root'; // mysql用户名密码
7 ~) f5 D5 r @2 A* g. W" D9 S - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
& A" t z8 F3 b/ Y# _5 ] - if(! $conn )) |) w4 O# \( X3 x6 A
- {# k/ Y9 z/ U0 Y
- die('连接失败: ' . mysqli_error($conn));
8 }2 H% j2 s+ R! v i - }2 O p* J0 J) f4 M4 w: U' k# S+ Z
- // 设置编码,防止中文乱码5 [) h: _# g5 q# ?) `& A. Z
- mysqli_query($conn , "set names utf8");, K2 u2 ^# F' A' O1 u% P u
- mysqli_select_db( $conn, 'temp' ); ! v& ^4 v9 a6 e) e/ Z: I; Q
$ c5 d4 @5 ^0 B. F- # mysql 锁 $ {) d" I8 g, ^3 N2 I% S
- mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
3 F4 p; C1 f: ?) t - $rs = mysqli_query($conn , 'SELECT id FROM a');
+ o) l, N( e; E" t: p - $id = mysqli_result($rs, 0, 0); : t/ e r: ~5 b8 q/ m
- if($id > 0) - X; H) _/ E4 `* k% ^; H+ q5 G
- {
* x4 Y: N" J+ ]; M - --$id; ! d. h# O2 j, `1 w6 z0 ~
- mysqli_query($conn , 'UPDATE a SET id='.$id); ( z8 I% n9 g) ^" n9 m
- } " g$ X+ I$ _2 j/ `: B2 f( X
- ) C! P3 R& J6 H P" \5 C# j$ u6 d6 b5 V
- # mysql 解锁
2 N& X6 _' d: t6 R/ Q6 f. ?$ R( x9 M - mysqli_query($conn , 'UNLOCK TABLES');
+ }! b5 i, Q. x - //查询解锁后的id值
$ H1 ^' ]* O' F$ G M2 L! c I* U - // $res = mysqli_query($conn , 'SELECT id FROM ta');
1 H6 n, U/ y1 R, ]) X - // while($row = mysqli_fetch_assoc($res))
" ~1 O' Q* P% x1 a9 _0 a2 H) a; r o - // {$ C, f1 D% i Y
- // $id = $row['id'];
7 F& |. Q/ f2 I# `' ?) g+ `* j - // }
3 f" K |5 x- P: J - // echo $id;
复制代码 6 R- t# A9 p; A0 e* `& y5 A
2 A8 ]* j3 T6 M5 E# |
% ~6 J' x6 P/ v$ a+ J0 W; b! T
PHP文件锁示例: - /*
/ u6 F' T8 M- [+ D1 i R - 模拟秒杀活动-- 商品100件% a: K5 B+ ?& q4 _* g4 v' H1 K1 p" p
- CREATE TABLE ta
* Q7 f8 \5 d8 P% X( K1 A - (+ @6 _; m6 w: @. V* d$ i! ]
- id int comment '模拟100件活动商品的数量'
3 q0 s0 y) R" W - );
; N1 h$ i4 ^0 H: p1 ?; v( c - INSERT INTO ta VALUES(100);
* ^0 m: d' R# P W3 ^$ Q, n1 D - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
# m1 e5 p/ _1 y - */
( b/ |6 Y9 ^: C6 n8 {5 ?% G - 3 [) N( X+ u0 \2 R5 R8 ]
- // 关闭错误报告8 y' p' u" @( }) t
- error_reporting(0); / P* a& L( n) d0 v# b. k
! k& }; V* G! r7 i4 s9 G3 w- $dbhost = 'localhost:3306'; // mysql服务器主机地址
6 a) r+ }6 ^9 h - $dbuser = 'root'; // mysql用户名
& l& Y- T$ O/ D* @& a! t7 d - $dbpass = 'root'; // mysql用户名密码
5 x3 w) x! g Z* V/ q& S - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
0 l) m; }. J/ `3 G! P" y( V0 f - if(! $conn ) d) [- s4 ?: u) z3 T: h
- {/ z. ~6 M8 B4 y7 U! m& O4 m- M, c
- die('连接失败: ' . mysqli_error($conn));2 g! C( R, S& k
- }
# ^/ l; D" T/ L; a% A* S* g - // 设置编码,防止中文乱码# G3 M" J9 _2 \# O+ G
- mysqli_query($conn , "set names utf8");
6 F! o7 h2 I" G+ B4 W7 `& z$ U - mysqli_select_db( $conn, 'temp' );
" K( h& Z) {) _1 v; ^0 a
2 }4 m2 d( ]! o- v- # php中的文件锁 ; G$ L& r+ I: Q* `2 y' @+ C. S
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 ) C4 o3 X3 \6 X L) ]
- flock($fp, LOCK_EX);// 排他锁
# n0 j: ?. [5 s! r; b; J( ?, b
2 H1 [0 o9 U2 W: b, u- $retval = mysqli_query($conn ,'SELECT id FROM ta'); 1 }3 V9 X6 `6 l/ i
- while($row = mysqli_fetch_assoc($retval))
/ _3 c& B! }% T3 [3 T - {
5 c3 t9 m2 E2 |& J) M. n$ ~ - $id = $row['id'];
0 a' q$ k2 k8 x& i) z7 i9 o4 D& D7 H - }+ P' T4 H9 ?$ P2 |% k0 I% j8 V
- 4 D" }8 N, \" l: a- |& b* f9 J
- if($id > 0) 8 j% s( x! l6 t) v! p7 F* q' a
- {
W2 X0 S. p+ x - --$id; * \$ @2 l/ C8 [: A) G
- mysqli_query($conn ,'UPDATE ta SET id='.$id);
$ \$ Z& E( B0 h$ b1 m' e1 @0 u - } 0 I% e' N) [: Y5 E3 M
- # php的文件锁,释放锁
8 u3 c, k2 E3 k' Q* L8 | K( V - flock($fp, LOCK_UN);
6 l% K/ e6 Z7 K( a& _ - fclose($fp);
4 F. }& l7 p6 |9 X4 @5 F) W0 b
& G, o+ y$ u* [/ B! g% ]; a8 d- // $res = mysqli_query($conn , 'SELECT id FROM ta');, h; _/ s3 U6 p
- // while($row = mysqli_fetch_assoc($res))2 E) j2 o# G) X1 u/ O) P$ z
- // {
. z& _8 @! y1 h7 a - // $id = $row['id'];3 r, T7 J4 ~( O6 J" N' b
- // }7 y! q( R3 f/ J: Q0 e' ~2 S$ G7 C
- // echo $id;
复制代码
7 [% G$ ]9 S) B# b* @$ `0 G
/ F& x. X% h" l k抢券活动实例: - public function envelopeSnatching(){
n4 D3 U/ ~ |0 Q - $lingqu = $_POST['type'];- A; N8 e& z9 Q# E( t5 D
- $uid=session('u_id');//用户id, u" j5 H1 C7 v$ h9 q9 |) S" Q
- if(!$uid){
7 e) E: o6 n7 F0 M - $data['msg']='您没登录,请先登录!';
- W# z: g1 g2 z - }else if(date('Y-m-d') != '2017-12-12'){* N3 e1 i% t- R# u4 R7 v$ e. R
- $data['msg']='不在活动时间内!';
! d' Y" A) B7 o2 ~4 @ - }else{
& K- }, Z& D. \4 k) v - $hours=date('H');//当前小时数
8 c) V; C4 @" ~ - if($hours > '09' || $hours > '17'){ J3 m' P( Q1 W4 e( e
# Y7 w5 ~, B; ` j- if($lingqu == 1 || $lingqu ==2){//点击10点的- @6 v) g( ^' W* Z6 U( G ~
- if($lingqu == 1){
: _+ p7 S9 r; A% d - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过: F7 ~) J1 y# B( B# P
- if($hours > '09'){1 [- l- c" @: I* j" _" ^
- $num=mt_rand(25,28);//优惠券金额9 \( R. t* q. {5 ]; N- }+ [1 P
- $id=1;; S9 Z3 ? G6 s3 Y* L
- }' f. X0 k5 g8 Q( _% w
- }else if($lingqu == 2){
+ e7 P, k* A* w* W# p+ A - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();" ~5 N& F" `$ I" T7 u% @
- if($hours > '17'){4 l3 t; x2 \# ?9 W4 r, I$ z. X I
- $num=mt_rand(50,55);//优惠券金额/ G0 Z: {4 c3 G' }& O
- $id=2;5 I, G2 v# k7 m$ R! M
- }. e- ^8 `9 N+ i
- }
5 O3 O' D. }6 B+ Z, l - if(!$id){, Z9 ?% a$ T" h! n. h; O3 [
- $data['msg']='时间还没到,晚点再来吧。';( {* R; o3 \* J0 _+ l: i
- }else{
, ]. S- \7 V5 g - if($is_lingqu){
" i3 ~9 v7 k4 K; c8 t' s - $data['msg']='你已经领取过了,留点给别人吧!';+ L# q0 U& J+ F1 {; [0 C
- }else{
; n/ y) @& `, _ - //锁表8 t& Q5 I% F- O6 f8 u
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
7 z% y0 ^4 ^9 a; ?) w8 @6 e% c% p - $active=M('active_num')->where(array('id'=>$id))->find();8 O, N1 [. E0 P# q9 E7 K, N2 Q
- if($active > 0){
8 `- D7 ?3 R9 F9 l$ T1 a( E( d- r# g' r - //开启事务
* Z6 u G/ _2 O* o3 z+ e" Z - M()->execute('start transaction');
' f- _9 E6 W! g" l - $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
1 R& [( P* f Y3 u2 ]2 }2 s6 J - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));0 d! E& e4 ~ [& v5 D
- $members_preferential = M('members_preferential');
9 K5 S- b* q) F/ @' L4 U - //对应投资金额,! J, |6 l. H# `0 H4 Z7 e
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));0 l5 d) G& n: ^' ? t" `
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
3 }6 I: P. P t- u% r( l" j7 `' e - $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
' y4 v7 k% y& Y# {0 \. L - $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券 q0 Z2 B, ^: F8 s
- if($save && $add && $add2){
2 {5 u6 L! v& C {2 ^ - //事务提交8 O) M5 ~# U- z3 b% D& I
- M()->execute('commit');+ j: `0 Y5 B g8 \
- $data['msg']='恭喜你领取了'.$num.'元优惠券';
( p1 X3 ~4 L( ~4 Y! o$ H# t N - }else{
7 } ?% J/ X! @ - //回滚) u& ]: w. r; E5 X0 V3 w$ P
- M()->execute('rollback');0 s4 a% `2 g# e) y9 p0 v! m
- $data['msg']='未知错误!';8 ~& m6 `2 E) e: v* a M6 `
- }
' c1 V& w; g0 C$ W: g - }else{5 M m! d; m9 Y8 y" ^7 A0 p. s, ?( p" R
- $data['msg']='红包已领完,你来晚了!';
5 }3 I0 h, Z1 N/ f* Q: U: a# d - } u. T @5 H8 u
- M()->execute('UNLOCK TABLES');
# n2 `! D* r0 {5 A! N2 R - }
6 w. |1 p5 h, R, b - }
5 K' W) m' x4 U4 u; k+ o) y - }else{; y" C" {$ x: P- f
- $data['msg']='非法操作!';
' Z7 E# n% S% C - }( ]5 x- f+ V8 Y- {% N8 u" ~
- }else{1 B+ g# W' i9 w2 X- t) c
- $data['msg']='还没有到活动时间,请晚点再来哟!!';
" O( o6 |! `, F# R - }& r7 _) s6 T6 t) E
- }
% u: H. V) h) [9 T( ~/ B. Q3 P; s# h - exit(json_encode($data));7 W. P& v( j2 Q! j. }! K7 X- o
- }
复制代码
$ |4 A5 V5 I) Z; k5 m
; d9 y( v$ Y- w9 k( F/ d |