|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
1 [1 T' ^# D- u1 @& F: {Mysql中的锁语法:
- ?/ ?" u% d4 oLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
Q; b5 n3 o: ZUNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
3 l9 V+ j( t0 F. M0 K% uWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞$ K/ y8 C. i2 T" ^
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :0 O s- R0 ^' }/ V( U7 Y
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。5 Q9 C: Q; Z+ O9 \; T
测试时,有个文件就行,叫什么名无所谓 总结:
" e% U, P9 ~/ s1 l1 Y$ C8 g- A: y5 Z项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
: z0 ] W# Y6 k) w* c1. 高并发下单时,减库存量时要加锁, U+ m/ x! a# \& D' L5 B3 Y4 R
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*
" t# J/ r! h1 G* A9 R0 C) J" S - 模拟秒杀活动-- 商品100件
3 i7 B( S3 P+ F - CREATE TABLE ta8 @. G* j, k- C* }4 j
- (
8 x9 h5 c) G4 L; N6 x6 F - id int comment '模拟100件活动商品的数量'
% H" F1 M$ t3 q1 }1 @% p - );
* P& F8 \: c; K! `; C - INSERT INTO ta VALUES(100);! B9 b) K3 Y8 h; j1 {! J: W) G }
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件! g+ U/ z) A$ h _2 e$ d
- */ $ N2 v$ `5 \8 t2 y' ~& ~3 h
-
4 p3 O( m( P8 q6 z# d - // 关闭错误报告0 e9 O4 U4 X: h. g3 m
- error_reporting(0);
. z) z' R$ N# @- [ - J% F { k. a1 n3 v/ A
- $dbhost = 'localhost:3306'; // mysql服务器主机地址
: G- H! Z n# Y/ s - $dbuser = 'root'; // mysql用户名! h% a/ C5 E1 N$ B7 S
- $dbpass = 'root'; // mysql用户名密码
/ z5 T5 o9 N% M+ N* e0 ~ - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
" U) [ t1 H; N - if(! $conn )
8 k( M- {( \/ _- c+ L - {
* `, r8 K( t7 G, k' H - die('连接失败: ' . mysqli_error($conn)); Z6 g/ A/ n( r* j! z5 H" Q
- }, q( h$ z/ e# h! A) O* i3 G# A
- // 设置编码,防止中文乱码3 [% Z* f4 W# ^% d9 @
- mysqli_query($conn , "set names utf8");
9 q/ C p$ R3 g: ~8 y - mysqli_select_db( $conn, 'temp' ); ! a6 |' Z9 S3 p# r B; n4 P5 ^) p0 ?
- 6 N* M, N8 @5 c& a- t* T) e
- # mysql 锁
6 v* @2 ^8 I4 u( t - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
- C% Q; n. a% F% Q! {) E j - $rs = mysqli_query($conn , 'SELECT id FROM a'); - L% G) e, k/ N: b- `
- $id = mysqli_result($rs, 0, 0); 9 U! `: r3 }& Y0 {3 j5 k
- if($id > 0) 2 j' | t6 p7 Q1 {! a- S' P
- {
, V/ m' O; a/ z2 s - --$id; % b& q C0 h9 s& D) X9 S
- mysqli_query($conn , 'UPDATE a SET id='.$id);
" O& ?0 s: D- _0 O- G - }
4 C! g4 v8 `* Q/ e( |# c3 k% D# \
|5 s' _1 Y+ Y% s- # mysql 解锁
& K- ~# M' L7 u9 F, `$ G - mysqli_query($conn , 'UNLOCK TABLES');) t! A# |5 b# G- b& ^4 _5 q) Y! k& ]
- //查询解锁后的id值
2 T6 u/ G: P- J - // $res = mysqli_query($conn , 'SELECT id FROM ta');
' H a9 g, g" H - // while($row = mysqli_fetch_assoc($res))9 _ g$ E3 ~9 T9 @# M
- // {3 x$ Y/ {0 Z" f5 e) b4 y. e9 {4 U( F
- // $id = $row['id'];
3 v5 ^* x* Y* P- x - // }
5 |4 h1 g0 s& C: Y5 D1 L - // echo $id;
复制代码 - b1 Z3 g5 b9 c
8 B% ^: M+ Z$ c; a
: D2 s8 m- y- A" [PHP文件锁示例: - /*, `6 D: d2 z/ J) ?) k
- 模拟秒杀活动-- 商品100件 D0 N" X4 ]/ E" j6 p
- CREATE TABLE ta# S' a1 h1 {4 A& ~( I
- (
' z1 O' \+ z0 O! j f5 K8 E - id int comment '模拟100件活动商品的数量'. U8 T7 a% J: Q9 `6 o$ q
- );
+ i4 W+ T( T* x - INSERT INTO ta VALUES(100);
1 S/ w7 J$ \* Y" r o# r- d - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件5 }; g V3 A8 v; n. s8 F( `
- */
2 ~' `2 r$ W1 p0 p7 T - 7 S6 _5 z) L: n
- // 关闭错误报告. M- b, r" J) e5 o# Y3 V/ J
- error_reporting(0);
1 `+ V) e4 L8 f% I" r' a( j - 2 K: y0 k; d3 Y4 O& z3 _6 ?$ p- B( U
- $dbhost = 'localhost:3306'; // mysql服务器主机地址4 X: p$ Q( U7 i( e) i |0 |
- $dbuser = 'root'; // mysql用户名1 I- J6 B( a. p. A" X3 L
- $dbpass = 'root'; // mysql用户名密码
2 z% |: M& H J' K - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);! J$ x4 u) `& ?2 k9 K8 L
- if(! $conn )
+ [2 c3 N' v) d: ] - {0 S4 J! c% T% K$ \% I3 T% J
- die('连接失败: ' . mysqli_error($conn)); V* n8 x! s3 T; ?5 {2 |0 b$ `, y
- }' P! L8 v- X y& s: f3 F
- // 设置编码,防止中文乱码: b+ Y% v/ D z2 Y2 Y- u0 o; W
- mysqli_query($conn , "set names utf8");
! k5 {3 O w* l- |/ S6 E% K8 a3 v& m - mysqli_select_db( $conn, 'temp' ); 4 m X* \; F- v8 j6 _
- 7 C5 `% @! O4 p5 W3 s
- # php中的文件锁 : ~/ _! t( R. S- {$ `" r
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
. C" \ q* R& B% G* S1 F - flock($fp, LOCK_EX);// 排他锁 " p, G- O0 Y/ D: I4 J, H5 l6 T1 i
- $ j; s; A+ s8 @
- $retval = mysqli_query($conn ,'SELECT id FROM ta');
% J/ Q: n2 D# A6 X6 E8 x - while($row = mysqli_fetch_assoc($retval))
! n8 Z5 v3 s' a' p4 @1 Z - {
5 e$ |' j' j' ]- a$ X, w - $id = $row['id'];4 ^# ]+ a# X8 c9 r$ N
- }. L1 H8 c$ |+ G1 l
- 0 o. P4 c* m+ |& r9 m
- if($id > 0)
: H, W3 T+ A# U- Y* a# q - { 8 }. m' ?( d' p' }3 g
- --$id; * o8 L; ^+ u/ f5 \* h1 e
- mysqli_query($conn ,'UPDATE ta SET id='.$id); & O% {: o4 T6 W, c
- }
0 ~4 ~. W; v: v0 u - # php的文件锁,释放锁 8 N; b; |2 W. ^8 P3 J+ u5 \- b
- flock($fp, LOCK_UN); " N. Z# K8 ~5 q) d" S' v# d2 w
- fclose($fp);
# e2 e* B2 a2 R8 u9 S1 W - 1 o: j+ s1 J$ @3 z [8 [7 ~3 i1 ^
- // $res = mysqli_query($conn , 'SELECT id FROM ta');& N9 A. J& b& ~* @! J& s8 |
- // while($row = mysqli_fetch_assoc($res))
4 `* H. C; [$ |: L3 ^6 M - // { u! ^; `1 ^3 G. c. n
- // $id = $row['id'];
7 M4 Y8 u) T7 x/ M' l - // } _ J; W4 z& k2 [+ s9 n' N
- // echo $id;
复制代码
5 I* B# [6 x; ~9 U3 w. r( C. R$ ], M, I: E
抢券活动实例: - public function envelopeSnatching(){
* d6 M/ S6 P! ~0 w8 P8 j' z - $lingqu = $_POST['type'];
$ _% ]. E+ E- J2 j - $uid=session('u_id');//用户id
- p" ?2 d& k* H8 m0 S% q y& Z; W - if(!$uid){
3 V1 P. `( m! e - $data['msg']='您没登录,请先登录!';; ^ O: i& S6 ^
- }else if(date('Y-m-d') != '2017-12-12'){
% g6 [; ?9 u4 j1 c! P - $data['msg']='不在活动时间内!';
% w5 r. O4 ^4 a9 x, F( d% e - }else{) o+ g2 d j* J4 P: s. b
- $hours=date('H');//当前小时数' u6 L2 d; I6 P Y
- if($hours > '09' || $hours > '17'){
5 A+ i: g3 S& G* H9 S - 0 y _; c6 V5 E8 O% x
- if($lingqu == 1 || $lingqu ==2){//点击10点的' n: y% {8 m! i0 T" m! i2 R- f
- if($lingqu == 1){
+ _/ k! t3 [( V- @" s) ~ - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过, Q3 z9 S# D8 C7 `
- if($hours > '09'){5 |8 c4 D: f' G5 E+ C8 P% t' W- a4 B
- $num=mt_rand(25,28);//优惠券金额- @ T3 L6 U5 M+ T: e3 {6 f4 L
- $id=1;
' a( J. `' H' F7 o: R" \# @ - }
4 B2 i; q7 n* Z) L+ z3 @% k - }else if($lingqu == 2){
7 L0 _$ O- _8 {- u: ~; ]7 G; O1 H$ d - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
+ d1 ]% k% H: ?% _- t4 { - if($hours > '17'){
6 S4 \" `$ U2 j0 e" k8 m - $num=mt_rand(50,55);//优惠券金额
2 K$ m5 ^6 j( ?2 U: A$ X - $id=2;. A+ E( s5 @5 |( c$ y. u
- }
! I% ]8 x) H" ~3 d3 J# f [ - }; `, K9 [0 O6 _- s
- if(!$id){
# u" \. V2 P/ {6 e - $data['msg']='时间还没到,晚点再来吧。';* n D7 {% |1 i2 G" J
- }else{
" k' z4 [) e8 f* d1 r - if($is_lingqu){) j. M: Q9 S& Q: v1 n
- $data['msg']='你已经领取过了,留点给别人吧!'; q' Z Z. L2 _
- }else{
) \7 r. n* _% A( M8 B - //锁表
) K8 P% _! m4 A! J - M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
/ D8 A# `* S9 I- h+ S F1 m - $active=M('active_num')->where(array('id'=>$id))->find();
% [+ U$ }4 z$ Y5 m: P" H - if($active > 0){/ {4 s6 A) M* L0 g% A
- //开启事务
1 @5 B+ X# f: }( e6 \* N - M()->execute('start transaction');
+ n7 @' X9 w+ M8 b) X1 E - $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
! }: \* a9 N% m8 \( Q1 I - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));! }' d# e S a/ b
- $members_preferential = M('members_preferential');
' |: a' o( ^* i" X1 u* f4 K - //对应投资金额,& { g; A4 L& o2 j" p& T
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));. E1 b9 F3 R! s# d- Y) N
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');2 K1 i, h! Q" s" m" T2 Y
- $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间* b7 m1 i% w' m! h7 y- n. r6 W
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
8 M6 c6 b, }$ f6 c2 m' u - if($save && $add && $add2){
' n1 p/ v# i4 d3 V% b - //事务提交
* W% g6 X3 `. [9 O% P - M()->execute('commit');% k: q$ M! G# S- F: y( R
- $data['msg']='恭喜你领取了'.$num.'元优惠券';& @2 n* z" ]* l
- }else{
; u( }1 b7 y$ [& }% c - //回滚
5 ^0 Y5 Z0 J3 c0 [; s5 q0 s& e - M()->execute('rollback');
8 q! w K8 d2 B) Y+ V( c3 p+ @3 e - $data['msg']='未知错误!';4 K3 X! p4 Q7 P, q
- }) m9 G% K; L4 C1 ], U) |2 q
- }else{, g H% r; ?, B: R& z' P7 u& @
- $data['msg']='红包已领完,你来晚了!';
7 E! k N! ~- i- X& t- d - }
: Y! G5 P, c" G - M()->execute('UNLOCK TABLES');
( `, Z" }0 ~9 {/ G( b8 c) z - }
7 P9 c: u1 G( q' ]% Q - }3 \$ X- J! Y2 e$ L( c3 Z: n
- }else{
" N: J9 w; |0 H9 Y. b - $data['msg']='非法操作!'; k4 a, P/ p% m, D" Q% s; y
- }( [7 J& f+ H2 G' _
- }else{/ \2 L, ~7 S2 `: u" s1 K6 p
- $data['msg']='还没有到活动时间,请晚点再来哟!!';, B0 E* u7 G. j! t
- }3 A+ J O2 {, o8 \/ a* ]: i
- }+ n, _" g$ j7 Y B
- exit(json_encode($data));+ n% k! Z$ ^* W( F) ^9 f$ A
- }
复制代码 2 s1 E+ q* G6 m* m! ^9 i" Q0 a
7 ^4 V$ i1 x& Y/ G |