|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码 / U2 j# D {) k: g) @3 `% t5 J
Mysql中的锁语法:
8 }! x0 e# n& W+ o& VLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】9 ]* J/ [1 t% r% z. m: I9 ~- K. C R8 U
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表1 [* g4 R9 k. v f! W5 u
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞4 n) y1 w, L- V0 c% e( g
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :
- ]5 \3 t" E/ M, q) j" q文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。$ o, }8 Q9 V' }, {8 Q
测试时,有个文件就行,叫什么名无所谓 总结:
8 E0 C' H6 g6 ?, P4 n) {' Y1 Z项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
+ W% u+ [( G r+ G- S1 }- T1. 高并发下单时,减库存量时要加锁
' y* ]$ C0 y9 k2 R1 _2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*/ @( X4 _# A4 @' H
- 模拟秒杀活动-- 商品100件4 V/ x6 a- B! m, K7 [
- CREATE TABLE ta
- R8 ^$ Q$ a, g4 l7 ?( }1 b - (
a3 C M0 F2 H9 J: E8 y& x - id int comment '模拟100件活动商品的数量'0 p) Q( ^# E/ \1 ~5 u+ K3 b- s0 U
- );% ^% [; N4 j& h( w' ]
- INSERT INTO ta VALUES(100);) c* i6 ]0 i4 Q9 T
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件2 Y H" O7 C6 S. k, t
- */
4 P3 s( `9 s: I! x -
4 _2 `5 w' y2 c: o+ y - // 关闭错误报告
. [; c+ w) C# v0 ?3 I - error_reporting(0);
/ u: o: n6 t! B
+ I& T9 Q3 N' p4 `- $dbhost = 'localhost:3306'; // mysql服务器主机地址# p; x. o; Z3 I
- $dbuser = 'root'; // mysql用户名
- k/ P; W' Y$ h P+ X/ z/ N% T - $dbpass = 'root'; // mysql用户名密码
: Z8 @7 ^4 D9 E - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
/ ?1 ]7 E- U3 e# U - if(! $conn )
$ {. k' |( L. D- B0 y - {3 v+ [& P q. o7 L
- die('连接失败: ' . mysqli_error($conn));4 B5 d# I2 ?6 t& I/ v: g6 @3 t
- }. a; S! ^" w3 C( e7 ~
- // 设置编码,防止中文乱码
1 M* h2 g- m9 I. p1 `5 ~1 m - mysqli_query($conn , "set names utf8");
, |$ p e7 G4 C, [ S - mysqli_select_db( $conn, 'temp' );
\6 G( r6 f( g( y - 5 F$ E7 S! y. ^1 y6 [
- # mysql 锁
8 g; S Z ^, f+ s0 _ - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
( i* ]' K8 f6 U1 ^ - $rs = mysqli_query($conn , 'SELECT id FROM a'); / m6 e! T9 K+ K* A
- $id = mysqli_result($rs, 0, 0); , r' g" K8 u: C! D3 Y
- if($id > 0) 9 `9 K3 A- E p$ s. `: d# Z* a
- { 4 T7 D+ K) k. V% d+ J$ ?
- --$id;
7 d( K- T) }" c - mysqli_query($conn , 'UPDATE a SET id='.$id);
g; N+ Q( _1 g - }
' C% j( ^0 H) _% t - ) h) j4 \% @% q2 a- y& k# t7 G1 r
- # mysql 解锁 , C& |7 K' f% S" g
- mysqli_query($conn , 'UNLOCK TABLES');6 S3 C. W% B# [# E* K! P0 Y
- //查询解锁后的id值
]5 m d8 A4 B1 v% S - // $res = mysqli_query($conn , 'SELECT id FROM ta');* k: ~: C6 I7 q. E \& ]6 Z
- // while($row = mysqli_fetch_assoc($res))7 [* k1 L$ j0 \; {
- // {
! U i4 g0 X4 [6 `+ m+ M+ d5 C w/ t - // $id = $row['id'];# A5 O! Z& D1 G" o/ F
- // }
* c" J9 }. d0 M2 h" v* n - // echo $id;
复制代码 + F. O: U6 Q4 T, i. k
- Y3 l' U9 c! p! b/ c! a
8 ?( r2 |5 P6 f5 _& {PHP文件锁示例: - /*4 S% d0 X% r! F
- 模拟秒杀活动-- 商品100件
+ V; X! F$ x- E$ Z9 S - CREATE TABLE ta
! O( I+ j. z0 k( @ - (
" `6 y) a" i: p3 |7 X y2 i - id int comment '模拟100件活动商品的数量'/ v" d, {4 Z* E9 _% x
- );
1 U7 E1 g U! g! D - INSERT INTO ta VALUES(100);# ?! b( n9 Y8 j5 ^" Q" }* E
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件! k) S( ^* L+ }( c
- */ ) D% O9 F8 B0 T2 X W
-
3 H' V8 o; o4 E% ^1 S - // 关闭错误报告' ~* t; x c2 `. E9 Q9 _
- error_reporting(0); , @0 w6 P; D/ h
+ D- i" Z% D+ S8 c/ J0 y( v- $dbhost = 'localhost:3306'; // mysql服务器主机地址8 d( g1 C8 j; `6 ]( R
- $dbuser = 'root'; // mysql用户名% H/ B' l6 L+ K# q! Q, P
- $dbpass = 'root'; // mysql用户名密码6 D Z- v }7 I% l H
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
# i, ]" y+ ]4 K - if(! $conn )
! o3 h7 F: C" E5 j7 C - {+ O9 J2 t) O( d! a$ e
- die('连接失败: ' . mysqli_error($conn));
+ k: M- M# @( u: w- }) h - }9 M. Q- D% {6 T5 O+ A) A( r h
- // 设置编码,防止中文乱码
# r8 j h* h& }/ b; d3 i$ A - mysqli_query($conn , "set names utf8");6 z* l6 K0 M/ N1 k0 I5 ~9 S
- mysqli_select_db( $conn, 'temp' ); / U3 c0 a, q( ^: }
- 2 ^0 [+ A$ B( }' n
- # php中的文件锁
+ j5 [& ~/ \. O/ w - $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
1 f% ]6 k G1 o - flock($fp, LOCK_EX);// 排他锁 ! u B! @* x# j4 _
/ Y8 e1 Y/ d. I7 |9 U$ X7 [- $retval = mysqli_query($conn ,'SELECT id FROM ta'); 0 x$ a- J0 [( m& h1 n6 _; [: a& u
- while($row = mysqli_fetch_assoc($retval))
6 s: t2 }) Y, l4 J: }% Y9 ?7 q6 \2 P k - {8 F% x: S1 s6 e* O7 A0 F7 _" ~ x' ?
- $id = $row['id'];
- v+ D; r4 h5 q3 X1 T9 g - }7 [4 U2 n8 }) H, _+ k- I
-
9 Q% l: ~* ^1 g% v/ i - if($id > 0) # e; T T4 @3 T6 C6 e! M! c8 h
- {
3 |3 Q8 l8 ]( B' I - --$id; * Q$ B3 Q2 |1 T
- mysqli_query($conn ,'UPDATE ta SET id='.$id); 7 L# b% G2 b' V1 f, k# Q, o) ^3 l
- } * a9 ?1 ?# W. Y4 A
- # php的文件锁,释放锁 2 m+ a( I8 X8 X% h6 ?0 @8 Q; o1 ]" C5 w
- flock($fp, LOCK_UN);
% T3 {8 M X7 G! L0 p* _4 c3 t* h% f - fclose($fp);) F; u: | Z8 N$ M# d( t
3 e% ^" s* y1 s. j# w- // $res = mysqli_query($conn , 'SELECT id FROM ta');" w4 \0 R& y4 r# w) U' }: X
- // while($row = mysqli_fetch_assoc($res))' I: l1 A2 r) `4 F! Z; w I
- // {
6 _% D* C* g" s; G0 }" R - // $id = $row['id'];( U& p4 m7 A7 ~! j/ n) f, i
- // } L2 K- A( {2 }
- // echo $id;
复制代码
8 U1 H, H& [; P
! t- @8 Y6 r3 y5 y- l抢券活动实例: - public function envelopeSnatching(){
! G% k; _% ^0 M - $lingqu = $_POST['type'];6 z6 f2 k) }7 t; g( n) ^- L2 ~- k
- $uid=session('u_id');//用户id
3 t- ?" Q4 } W3 M, G - if(!$uid){- M$ S% \" g* ~% k9 o
- $data['msg']='您没登录,请先登录!';* ~, M9 O% B: y% @6 x+ t- @6 X
- }else if(date('Y-m-d') != '2017-12-12'){
) X+ O$ m' d1 C8 ]- d - $data['msg']='不在活动时间内!';7 U( N' ~' z0 W3 k( L1 t( @
- }else{- I+ I* U7 K0 D& D9 A9 T' T" f
- $hours=date('H');//当前小时数, C( S8 Z6 W F/ v1 R0 `1 w
- if($hours > '09' || $hours > '17'){+ L$ n: K& |! {4 c( o ]
- [7 p% I. b6 G7 c. w4 b. x
- if($lingqu == 1 || $lingqu ==2){//点击10点的- a2 _+ O: s, u% b W6 ^
- if($lingqu == 1){- Q3 K8 r* y5 `( E4 U6 {
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
5 ^0 ~% }5 ~4 z3 U* L+ n& q8 D7 e - if($hours > '09'){
$ l; a1 j( n( l5 v" J: Q( D$ p4 ] - $num=mt_rand(25,28);//优惠券金额
2 C7 w9 @) o, n. ] - $id=1;* m% x& Y8 o- u" ?! `" Y0 Q0 O
- }- U8 c, k% @- S' I% H
- }else if($lingqu == 2){
: g( j/ o9 K, o# t+ q# o - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();, ~* z! s) c& L& F3 C
- if($hours > '17'){; G4 {9 n3 i, m1 \; t/ c6 w
- $num=mt_rand(50,55);//优惠券金额
: B" N. q# \5 `5 U l1 l - $id=2;
! P3 j9 V; u Q' Y* k3 X& p+ N - }
8 P& n+ O2 d2 o - }( |2 O E; |0 k1 i. X7 o" _ t' r
- if(!$id){0 P2 q( J2 H. ~! A: _
- $data['msg']='时间还没到,晚点再来吧。';
' Y$ i1 U/ l. p - }else{1 t, d0 d& N2 D
- if($is_lingqu){* G! o" i1 t& ]/ {7 E' z
- $data['msg']='你已经领取过了,留点给别人吧!';, o4 ^" K6 o( J# y9 c1 Z
- }else{
T( O3 d$ P; u! q9 E/ e$ K6 Q5 D+ L - //锁表; v( y1 M1 E, Y6 h# O
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
0 l4 D4 _2 E9 Z ~ - $active=M('active_num')->where(array('id'=>$id))->find();
5 Q, [: ?- ] Z0 ~9 ~% \5 ^ - if($active > 0){% F. Z) X+ D9 n* j$ F' M: }( i
- //开启事务
5 ^$ V2 r1 r/ Y9 r0 V2 ^. h - M()->execute('start transaction');
! B7 V, J0 I6 y. H5 O* d - $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));1 Y( k, {7 V- A1 `( N6 r" v
- $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
& V9 E; f. R# ?, n5 H9 x, p* y - $members_preferential = M('members_preferential');, K4 O( m1 Z9 p- o9 U4 L
- //对应投资金额,
5 {. `, D! y) `) Z - $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));) ?* i+ ~1 B; I; j: o
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
6 J' s. T3 l/ J - $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
, B% K$ h n8 M F; a - $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券7 g2 q: e' A# u. C- X4 [" H
- if($save && $add && $add2){
: t* M1 O4 ], T - //事务提交0 N- N8 j9 A8 Z% A$ u& A/ W
- M()->execute('commit');
2 a2 N. b* S6 a1 q/ B6 s( M - $data['msg']='恭喜你领取了'.$num.'元优惠券';
4 q3 \1 W- \/ S+ o, r - }else{
& _4 {4 V3 r2 g" ~. B - //回滚 ^# {* `# a; ^+ M- r. z4 ^
- M()->execute('rollback');
3 G3 M# z1 @9 Y - $data['msg']='未知错误!';
5 i3 @/ K1 S# _1 }( p6 Z - } h8 B* @- F) ]) e0 h9 o# d- K
- }else{, d4 q( G: r+ u H. _4 \0 |
- $data['msg']='红包已领完,你来晚了!';9 B, B4 y: w, D1 F3 u, W2 U8 T
- }
. p5 v6 S1 R" W4 B! _ - M()->execute('UNLOCK TABLES');) y9 K( h/ E# C. O7 r
- }
0 B# }7 \3 ^: z% P! o8 c# h - }
5 M2 n. n2 l+ ^& i1 r/ q' O - }else{
, F1 n. m! f6 _ - $data['msg']='非法操作!';0 ]! h% H% E4 M+ V$ _% |6 t* `
- }; T) m4 N L0 {/ `4 [, x1 u
- }else{
# r& j9 T7 r) k/ }# H q - $data['msg']='还没有到活动时间,请晚点再来哟!!';1 w( d) r/ K- e+ p# L! I1 @
- }. l2 {6 Z% Q5 ~4 G( [
- }
6 ?1 ]2 R1 d& T6 D3 I9 ~, O - exit(json_encode($data));
6 c, H( M; K( {9 ?3 r+ C - }
复制代码
# O, ?% w' S- _. E+ P0 m
7 V: J" T8 X; G" Y. L" ~ |