|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码 1 D( o( v* x" J! [, ?4 T
Mysql中的锁语法:9 W$ j' S# J: j! ?* c
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】9 n, ~9 `6 Y, P) P# C
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
d! F' g7 f8 ~" DWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞! Q6 \" `, G/ A
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :
/ Q% a k8 D% R0 Z% u文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。, o6 _1 z L V+ [7 Z" x: y
测试时,有个文件就行,叫什么名无所谓 总结:
* j: f8 J3 X6 ?; p2 a/ R项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
?& ~: E5 Z* u, @) K7 g1. 高并发下单时,减库存量时要加锁- G. A! C- u/ X1 G! V
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*/ z, K! q L0 G9 ~
- 模拟秒杀活动-- 商品100件
8 B2 e; L" C' H+ W- a- V% {7 v" Y - CREATE TABLE ta
+ ]7 O5 F. @% T- N, C( f - (0 e% P: s/ J5 M+ F0 y; V
- id int comment '模拟100件活动商品的数量'
4 h2 v6 p3 N9 H - );
' a/ V% \+ W5 U' _/ ` - INSERT INTO ta VALUES(100);
/ T. w2 Q" N) j# ?5 O1 ]& Z - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件) R0 a4 { H: N1 A# A. d
- */
3 ~" A3 P) b* b2 g+ f" F -
* M) Z0 A. d' ] - // 关闭错误报告5 N/ I7 t2 @. |5 s. S- n1 p K
- error_reporting(0);
' y* ~; X8 R% S+ ~- }
G9 a& T, K! R0 q! P- $dbhost = 'localhost:3306'; // mysql服务器主机地址" ~! d# @- T. f# [' K7 | j( w
- $dbuser = 'root'; // mysql用户名$ U& K. C/ B( ?7 _
- $dbpass = 'root'; // mysql用户名密码5 H1 n W: I2 G- {
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);8 v( T% |$ K* |, j
- if(! $conn )( K& i; `5 a% q: n9 ?
- {
0 } W7 g' m& ?# i5 j1 p9 R - die('连接失败: ' . mysqli_error($conn));
$ T' Y. n: U' K - }
_8 a8 ]. X" \, T7 [ - // 设置编码,防止中文乱码
9 v3 C4 E; l1 t- h3 Z - mysqli_query($conn , "set names utf8");
: N- v( [: S7 I - mysqli_select_db( $conn, 'temp' );
; N) E4 G% I3 F - / T& b1 O" f+ @6 l& Y
- # mysql 锁
; A% d& I# l8 ?" P3 G - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 5 T4 i1 z, b, I! c$ T( ^) [
- $rs = mysqli_query($conn , 'SELECT id FROM a'); 6 n1 u/ y9 t R$ w7 \) a" r# y3 M4 N
- $id = mysqli_result($rs, 0, 0); m8 g+ q* i- G! ?
- if($id > 0)
' G6 G( K0 F# r% C0 W - { * }/ r1 g- l( g4 d& I
- --$id;
8 H# V; v" \" P( r9 g- |" {& Z - mysqli_query($conn , 'UPDATE a SET id='.$id);
. L/ t2 O5 d' `3 G5 F' C - } 7 {4 S+ m- V# s4 @
- 0 s8 w& C. |4 I, i
- # mysql 解锁
, Z# | `. N/ i+ z& ~1 p( A - mysqli_query($conn , 'UNLOCK TABLES');* L& o5 ~8 v6 F; |$ L
- //查询解锁后的id值, t$ y' ~7 F, X/ G7 D3 \' `
- // $res = mysqli_query($conn , 'SELECT id FROM ta');
! N$ o$ j2 h1 d. Q1 p - // while($row = mysqli_fetch_assoc($res))
; m4 R% D K7 T5 V4 o* \ - // {9 E. B } N+ U3 n7 ?5 [
- // $id = $row['id'];
7 ?! J6 U1 |- R; \" p - // }. m+ n# F% `% V- X' f
- // echo $id;
复制代码 ' _ r3 k2 J6 W& q+ C3 G8 _
3 p0 u: C( H, n |) J/ N1 u; ~: W! j
PHP文件锁示例: - /*
" a* S* ?7 B# G; ?; {; r - 模拟秒杀活动-- 商品100件. n0 k3 f: e2 L& V( U) m+ Q5 T
- CREATE TABLE ta
: S+ b# f/ o+ q5 v$ M2 P! ]' C - (
: C- R1 p) f4 a3 w - id int comment '模拟100件活动商品的数量'9 [8 F, ~6 w( H
- );3 H' f$ q' d6 A0 P4 E* Z
- INSERT INTO ta VALUES(100);& \( ^5 j5 J+ n$ `
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
9 J7 P9 I# t# o4 E9 Q0 ]1 R( i3 h7 ? - */ ! H' x @1 E7 m N
- ' B2 N! _: @2 O0 q: w9 S8 f5 H: h
- // 关闭错误报告! h2 c) y8 l$ ]
- error_reporting(0); ; r7 }4 h5 C9 J$ `! I* [
( H' U$ d; b/ h# Z$ W- $dbhost = 'localhost:3306'; // mysql服务器主机地址7 }% X; u* v8 ~- d7 c. G; z# N2 W
- $dbuser = 'root'; // mysql用户名
, H B" w2 {) f/ p3 n2 V9 z - $dbpass = 'root'; // mysql用户名密码8 k) V5 M: p( ^$ x* n
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);0 Q8 V$ T# y5 E6 @" ]
- if(! $conn )
$ K! K& h4 K, A) N0 ^) y, I @: E - {5 }; u4 L) u/ Y9 y
- die('连接失败: ' . mysqli_error($conn));
/ F, j+ g' C1 i( j) b - }2 M6 z6 Z3 Y; f+ }* E2 E% L9 f+ ]- N
- // 设置编码,防止中文乱码
2 T( c5 I% X$ M. h, \ - mysqli_query($conn , "set names utf8");2 `. C6 Q; w, m% _: G8 X
- mysqli_select_db( $conn, 'temp' ); % E# t# p$ }6 T, p8 I- R
* ]* w+ t' q1 b/ U- # php中的文件锁 1 r, ~4 l: ^" U/ \* R% P. l
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 & p; k, D4 d, R6 h) C5 ]0 D
- flock($fp, LOCK_EX);// 排他锁 * X; |0 g, B1 I. i& r. T$ |
- & }: V3 x: y9 Q2 y! v/ _2 O
- $retval = mysqli_query($conn ,'SELECT id FROM ta');
3 \0 N) [1 |# v [' |* J6 ^ - while($row = mysqli_fetch_assoc($retval))
* D. Q$ T& _: m - {
4 j* `9 J, y. C - $id = $row['id'];& A( v7 R/ U- w j. e1 _
- }
) I7 ^2 T5 o2 `- E -
8 ^; k% x* r2 e9 \8 S- \2 I+ g8 y - if($id > 0) * X, K6 S9 S$ O T: x: \
- {
3 y& ?1 U) ?* T G: v - --$id; ' m/ y _, C& s6 ^' X. ?- W
- mysqli_query($conn ,'UPDATE ta SET id='.$id);
* d7 v- B: X) M7 k; ^8 s# T - } 9 [8 s5 g4 H3 i( Z2 Y
- # php的文件锁,释放锁
, ~/ E; g! y6 s( W+ w- b - flock($fp, LOCK_UN); ( I4 g7 o% ^+ j* C9 A1 K+ o$ k
- fclose($fp);* Z' F$ |* Y5 C# K4 k G& x0 s
' V: d$ X) g8 ?2 ?, w! H% q- // $res = mysqli_query($conn , 'SELECT id FROM ta');5 F4 B( I u/ Y9 C& ?% }8 u
- // while($row = mysqli_fetch_assoc($res))4 f! ^7 \$ x& s$ s1 [3 u. l
- // {' g& f) Z/ F2 `; @1 J% U) D( S" p
- // $id = $row['id'];# {/ \) F, |) o8 B; ~
- // }3 {0 m9 G0 S- C$ w. I* P0 l
- // echo $id;
复制代码
4 F* p. F' X+ Z9 I( O, i0 D5 c! A# f. I, e
抢券活动实例: - public function envelopeSnatching(){
0 D8 X9 Q8 f$ i4 h0 i v - $lingqu = $_POST['type'];
! Y, u8 w5 ~! n0 r/ z - $uid=session('u_id');//用户id
4 W4 Z* A2 p+ F" T - if(!$uid){# x, T8 ~$ w; l' }/ I6 E1 n1 @/ b+ m& R
- $data['msg']='您没登录,请先登录!';
8 q9 `% x7 S) j( Q2 B8 N9 ^4 k - }else if(date('Y-m-d') != '2017-12-12'){ d" c: L! q' r. x
- $data['msg']='不在活动时间内!';
# p& n* `0 [! z1 F1 W- [ - }else{* h; I( K& L- B9 D, W) B: d' T
- $hours=date('H');//当前小时数5 l& ]& K. k% H5 s/ S0 [: {/ w
- if($hours > '09' || $hours > '17'){7 Z+ y; b7 ?5 P& Z+ c A
- 0 W+ r9 g4 \: {) A6 G1 k
- if($lingqu == 1 || $lingqu ==2){//点击10点的
7 W/ z- A' n8 M7 @$ Y- d# @0 U - if($lingqu == 1){
0 }- Z/ {* T1 L - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
1 z& |% B7 ~( k - if($hours > '09'){
( T1 x+ x, M2 Y0 H* p$ G" [2 H - $num=mt_rand(25,28);//优惠券金额
5 ]" x/ _3 X0 P - $id=1;
% g3 ?3 ?7 c8 X$ }" A; z8 ]3 q e8 s - }
: f8 E1 ]# P6 @( z - }else if($lingqu == 2){( l/ {* e4 {$ C* E3 D% O' {
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
7 L0 b" H: V* a/ a7 j( q; x& S# Z: ~ - if($hours > '17'){ J, }! h$ G" U+ D
- $num=mt_rand(50,55);//优惠券金额
- D. ~( R. L, P! M! e0 d1 q - $id=2;' ^) z* i; i7 O( Y; z
- }
, Z: B, V4 F: ^3 h/ L v5 w0 `1 f - }0 ?% I6 x5 Q9 [- E9 r1 H5 u
- if(!$id){
- w5 k! j% A3 d - $data['msg']='时间还没到,晚点再来吧。';6 {- k$ V) l0 q
- }else{
7 k' b n( q+ K% X m - if($is_lingqu){2 b- U c5 Y5 x% w& t" b$ }
- $data['msg']='你已经领取过了,留点给别人吧!';0 `, G# ~. P9 i: G$ z, P
- }else{
3 [3 F+ i0 V4 b: n3 g% f - //锁表- Y, B/ N7 H% o& Y
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');) A! }5 y& E, H+ r# ~% G3 C
- $active=M('active_num')->where(array('id'=>$id))->find();
. l3 v0 |6 ]' j* _8 x0 c2 { I - if($active > 0){
( u+ C. \( @# W/ e# J. X - //开启事务
* t0 l5 b1 M3 o& D7 h - M()->execute('start transaction');% I% s. q# J6 N$ }" h
- $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));- I: w7 w4 q) L) f' D3 [' p5 \
- $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));4 ^* X( W3 E4 r' n
- $members_preferential = M('members_preferential');) P7 e2 e- W3 {+ p# D& J
- //对应投资金额,
0 X4 C. i$ j- |2 b8 J6 Q - $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
* U+ N D$ l! p% h- G# |* W - $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');! M9 \" m2 H4 M: H4 B- c
- $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间5 R0 K" I0 q7 t! ~- B! l* J
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券9 ]1 h$ I' c* h! y& B f
- if($save && $add && $add2){
2 O* k- Q7 O2 G1 Z1 C+ v) v; z0 X - //事务提交% o( l; h! m9 U8 }
- M()->execute('commit');
! K/ W8 V$ y: o$ d# f6 j - $data['msg']='恭喜你领取了'.$num.'元优惠券';
& R1 Q8 L1 A# n3 g - }else{0 C C* `6 e: E
- //回滚0 S8 b, H7 J8 N' |* T6 h
- M()->execute('rollback');1 I5 }+ G+ h5 ^/ P3 j) N# W) v
- $data['msg']='未知错误!';
) X8 c; @" ^5 P7 w) @ - }0 k* F% r% e+ P; @" B) o- q9 ^! O
- }else{
7 R; A& }$ t" h- m - $data['msg']='红包已领完,你来晚了!';
1 s, L( ~2 [. _4 t# V5 d9 r - }
: \- K8 ~1 T8 l, D9 c5 p3 X( s [ - M()->execute('UNLOCK TABLES');7 I+ y6 c% a( u9 m4 ^6 R
- }2 ~" Y! D4 Y( j& E
- } s0 u& ~: ?' w2 W/ E
- }else{# f/ ?4 [7 g e; g& | ~9 n: [
- $data['msg']='非法操作!';
! x3 E0 f% \7 b4 z3 }; f) i% r' D - }$ J. l- b0 ^$ D5 I. B
- }else{) m+ ^( E% L. F5 ~' D! Z2 y
- $data['msg']='还没有到活动时间,请晚点再来哟!!';- [* |9 l2 h+ m( k2 r% V
- }
$ o4 i# ]. |6 U8 ` - }4 {7 M) W& G& s$ p
- exit(json_encode($data));7 k# `2 I$ Q. x/ B
- }
复制代码
. C% K$ G% Q9 m/ a; A. A& b- Y& T& M
# L2 Y1 u' _ c2 p% C$ e9 j |