|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
4 A7 E( k7 t; i8 g( z7 [Mysql中的锁语法:
# q9 b8 U" u5 }8 z: r( J# ^. {LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】$ H. j! ?7 T; y- C7 W
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表2 p" I8 B- t, }( _+ s" u* D1 f
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
1 ?9 [# v7 _7 h注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :: K1 i9 k x, ^0 T1 r% Z9 r" t- J
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
( y6 ]' U5 V& e6 [/ `# d' M' i测试时,有个文件就行,叫什么名无所谓 总结:
% r. C5 N( E0 a项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
+ y; e4 X9 [! h' i1. 高并发下单时,减库存量时要加锁
7 T4 h) R- C1 _1 D2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*9 j8 P7 W& y' D
- 模拟秒杀活动-- 商品100件
$ W7 V$ G# ^" g3 x, x8 J# V, v - CREATE TABLE ta' u/ S3 D. Q+ ?! n
- (8 q4 U% m) ~! S
- id int comment '模拟100件活动商品的数量'
/ g% I: q% n5 `6 O9 [4 A1 m6 q - );; R: v" v" j8 ], H \! D6 r- ^: f
- INSERT INTO ta VALUES(100);7 s- D) e) Y7 V, @6 g. F9 {
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
4 g, M! T" t! q# R9 C0 M - */
) m- x: ~) k: l, {! F! ~% H -
5 }6 `% D H' ]0 p; n - // 关闭错误报告' b9 {4 |) ?& ]! C+ t3 T3 K# F
- error_reporting(0);
" }2 e W) H7 ~7 C
, F+ t7 ]9 R. e9 X5 y- $dbhost = 'localhost:3306'; // mysql服务器主机地址4 ?$ T3 C4 O U6 v" ]3 |
- $dbuser = 'root'; // mysql用户名
4 h- {. }- G @' e b) ?% r; \ - $dbpass = 'root'; // mysql用户名密码
M6 t8 Y3 f. f# J4 s( g - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
0 H0 |8 [8 L% e5 R* g2 k - if(! $conn )* ^- G( h2 G* [! k4 x
- {5 x: }+ B# G! x/ p i2 n( w: v% f
- die('连接失败: ' . mysqli_error($conn));( O2 K' ?' c5 P
- }
8 d- v. n2 `! i% F: F! [! n2 k - // 设置编码,防止中文乱码6 e7 O. i2 U) o& m6 G
- mysqli_query($conn , "set names utf8");
( Z4 w. i% J& ~& q - mysqli_select_db( $conn, 'temp' ); , R9 r3 M. Z3 @$ { F- n: c/ i; F
- 1 H) m3 `' K* D' I. Z
- # mysql 锁
, P4 g' o; |% T8 |- H# j - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 " D: a% } E8 y
- $rs = mysqli_query($conn , 'SELECT id FROM a'); 8 T5 C6 I- }6 @9 t u
- $id = mysqli_result($rs, 0, 0);
" V1 E& a0 J; G( ~# }# [1 J - if($id > 0) 7 `" d* Y+ \# G& A) K' v
- { 6 ^- j" K7 q; I% i" ]- M
- --$id; 2 f; O2 q: }& g r% q6 _5 {* S5 d
- mysqli_query($conn , 'UPDATE a SET id='.$id); $ \# r! b) d( S" Y
- }
; Y! k+ o* l) u
! Z. H0 a2 W5 q) g' j1 N c- # mysql 解锁 : Z. D- Z0 }5 B" _9 _7 L+ M
- mysqli_query($conn , 'UNLOCK TABLES');
2 H& {& l8 D1 z% o' b E1 b - //查询解锁后的id值& H% v- ~: t5 C" l) ^, P9 \" K
- // $res = mysqli_query($conn , 'SELECT id FROM ta');
! v9 z; J. Z3 q$ C$ t' f - // while($row = mysqli_fetch_assoc($res))
X$ o) T7 a7 | j3 ~ - // {
: e: l# M; y6 K0 h6 L - // $id = $row['id'];
! w( @# H7 @ _; s; W1 n9 a; i - // }9 W2 w7 x6 {- M
- // echo $id;
复制代码 # r7 _( d3 P* P9 e" q7 Y& i
* R! I/ N; H. W! \
' v9 P7 p0 Y6 k: M
PHP文件锁示例: - /*
4 n; I8 H( L! `1 |# m) u - 模拟秒杀活动-- 商品100件
9 X5 _/ G }* g% x% m - CREATE TABLE ta3 v, o6 a9 c" g
- (
$ u# [3 K: c( V. _$ m. J1 t - id int comment '模拟100件活动商品的数量'8 H. v* v( {- G8 m8 _: ^( s
- ); ~& y1 B# E1 p: Z! o
- INSERT INTO ta VALUES(100);' T( I( H3 u( h/ q% j
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件: d3 w2 T7 k W3 D
- */ 6 \7 k. k! ?. q9 E( o2 x6 s. x
-
9 a5 ]/ K; u: @/ m - // 关闭错误报告
, a- U$ e. v6 V9 Y9 R( Z - error_reporting(0); & d, t, ~* b. J8 i/ d) ~/ ^1 q
( V8 h+ Y7 [* i$ y- $dbhost = 'localhost:3306'; // mysql服务器主机地址: R- m& E* O! f, f. I- {- x+ L1 r
- $dbuser = 'root'; // mysql用户名, G j6 r8 L& [- C) b/ V
- $dbpass = 'root'; // mysql用户名密码
# w9 L0 m R: z4 o$ D" g - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
2 H& |$ i+ A8 L W. U - if(! $conn )
7 @2 {1 [+ V) n2 q8 ^9 e0 S( w; x - {3 Q6 F8 E' w( z+ u( `5 ^- z
- die('连接失败: ' . mysqli_error($conn));
1 y( B! j9 {. k- g - }
. p7 {, d2 o# U2 B# e z - // 设置编码,防止中文乱码
: k A1 T+ O7 D" l8 j# J' J9 _ - mysqli_query($conn , "set names utf8");
) |6 I6 `* d8 J* B4 Q p1 t - mysqli_select_db( $conn, 'temp' ); 3 }, G) `0 m1 D, L+ ^: \0 H
" ^# ~. c7 M" I& r- # php中的文件锁
& f" W$ r( s( G! ^ - $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
f0 B1 c0 \3 p" p6 D - flock($fp, LOCK_EX);// 排他锁 * u1 s. \$ q! `2 W) M. ?% |
6 ~' k8 V! p. V- Y% A" f- $retval = mysqli_query($conn ,'SELECT id FROM ta'); ' Z0 ~' W [8 ^' o. p5 r: H
- while($row = mysqli_fetch_assoc($retval)); ?5 o5 d. D) P( ~
- {7 e( g! T$ d' p1 A9 J! G, {
- $id = $row['id'];
: E5 m5 d) ~8 f, C5 L3 K4 {: h2 i - }6 S0 t, J9 D( e9 S
- * x- V/ i$ I0 h9 N
- if($id > 0)
$ Y/ m4 l, ~( [- n7 `/ f! p, | - { & q' A7 U' T6 k ?7 N% R
- --$id; - x, `! V. F9 {8 D, L
- mysqli_query($conn ,'UPDATE ta SET id='.$id); 1 c/ i* l3 f. r
- } / ]: w2 e+ B9 i; M
- # php的文件锁,释放锁 ; w+ I- x ^1 z. b) {
- flock($fp, LOCK_UN); 6 {0 e* S# t1 h2 W+ u
- fclose($fp);9 g1 B% D9 [+ y; R& b4 F1 F7 d
; u5 Z n' n8 T- // $res = mysqli_query($conn , 'SELECT id FROM ta');! K# h! Q" |* [3 o( `' F8 K
- // while($row = mysqli_fetch_assoc($res))
. z) y% C4 E- Z6 T* f1 c - // {, B; g1 j' m n( z' g9 J
- // $id = $row['id'];
6 g$ }% R4 ~4 P1 e7 m - // }# {1 f% ]+ e' q+ E
- // echo $id;
复制代码
; f7 T+ r7 j* U# R
2 p8 B7 `* x4 i7 H抢券活动实例: - public function envelopeSnatching(){2 n# p1 r7 r6 _1 T% o9 C. ?
- $lingqu = $_POST['type'];$ O4 Y3 q! e$ _; t* E3 `
- $uid=session('u_id');//用户id, b$ a( M& U0 o9 R8 ~ E) r
- if(!$uid){
: g$ j8 h% N F9 t+ y - $data['msg']='您没登录,请先登录!';
! A# Q5 o% }5 H* K" Z; k2 ?1 p - }else if(date('Y-m-d') != '2017-12-12'){
6 q# Q# T' c2 M$ U3 s* c9 | - $data['msg']='不在活动时间内!';
/ W4 ~7 R) ~+ }1 q& k - }else{
+ ?) Q/ q4 X) ]# o' L - $hours=date('H');//当前小时数
" c) a3 \! ?4 ]8 [, w6 B - if($hours > '09' || $hours > '17'){1 [/ }* s1 E; z' A9 @ \
- . |$ Q* v, f/ c+ o8 i# L
- if($lingqu == 1 || $lingqu ==2){//点击10点的4 ?* ]7 ]; X" j8 [+ G
- if($lingqu == 1){: V8 j: L2 R( W& b5 |' k
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
1 s) Y+ P4 O! _; ^% `" p# K, m - if($hours > '09'){
6 |% P* }9 ~8 \1 q1 l/ d3 P - $num=mt_rand(25,28);//优惠券金额
! l* m' o! q: c0 V* L( Y) z, x" d - $id=1;7 K! P5 S$ A: c, ~$ G9 [
- }, [9 Y5 O3 ^8 N' a8 V, A
- }else if($lingqu == 2){) X/ [; i! `5 w$ t/ z
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
' U5 `$ c* j9 \2 B7 ]2 W - if($hours > '17'){9 _8 g0 ]: U7 v- R+ g1 A8 e
- $num=mt_rand(50,55);//优惠券金额
( C0 D4 ~7 G7 C7 n - $id=2;6 ?6 x% ]$ k/ |' S
- }( A$ m Q1 ?' m' O, d# |1 P
- }
5 _4 U& g8 h, E" W% m9 w7 q - if(!$id){
0 E$ T0 W' ` a - $data['msg']='时间还没到,晚点再来吧。';4 a' ]* ]( \9 h) x
- }else{
3 ~& t% {9 C2 W: L8 O1 Y% K0 r) Z; M - if($is_lingqu){
8 Q6 ?* [6 V: G+ b - $data['msg']='你已经领取过了,留点给别人吧!';' [; E1 S1 d% Z) S& P9 m
- }else{, m f3 M8 a5 i
- //锁表3 O3 }2 [( q N9 O U6 {& M
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
& T s- H9 ^5 J$ p( j$ Y9 B - $active=M('active_num')->where(array('id'=>$id))->find();! C; s, P/ x/ N P4 `& h
- if($active > 0){
# j9 r. P; @: R0 X, W - //开启事务! g# r/ J# L. A' U) M' k
- M()->execute('start transaction');& n5 U3 U. v. ?1 M5 [, E
- $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
" \8 l/ q7 E9 u, y - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
+ Z8 a1 T: m2 r: }; `' ^ - $members_preferential = M('members_preferential');
0 {! }" c# A6 K - //对应投资金额,$ f _& C1 ]) G* {2 D
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));3 B9 r; k1 }" ^: R
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
$ j$ M- W7 c; L! P - $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间3 C7 e; n: K8 y+ N
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券# d7 O/ q" G" |3 c6 E9 N3 l- k
- if($save && $add && $add2){7 D, m4 [8 k d8 {5 [' z2 d% g
- //事务提交- d2 z a8 B2 u6 @ b% _
- M()->execute('commit'); y F, q' H& B4 i9 b
- $data['msg']='恭喜你领取了'.$num.'元优惠券';9 b/ j1 ^: w3 K$ A/ g$ K: N
- }else{! H8 V# X" C( z8 X- ^- ?. g( X
- //回滚
9 Y5 K% ?. b% k% x O - M()->execute('rollback');. b2 i, t0 s3 z, m1 m3 @- q
- $data['msg']='未知错误!';
- @; @$ O8 v2 o1 f( A; U5 V c - }1 `+ }8 K% Q/ r I
- }else{0 D/ P. e. o# O9 y; u
- $data['msg']='红包已领完,你来晚了!';
! n" v' {1 Y% n - }
+ Y" ~1 b; b; O - M()->execute('UNLOCK TABLES');
; l. K9 V/ n6 B9 `$ k& {3 A' l3 ` - }2 S& ^( v- K; ?( f% |% i
- }
n, ~- B0 T' u6 I - }else{
$ h" D+ ^9 u ^6 Q6 j" b - $data['msg']='非法操作!';0 Z, O3 g8 s% p/ l
- }% w$ |+ U a& z$ ^% Y
- }else{ a8 A; S0 I; V8 k6 W1 h- q: {
- $data['msg']='还没有到活动时间,请晚点再来哟!!';$ @( J9 I' k+ ^3 g% _% E
- }
5 t& D9 A0 ^0 y3 ]% A - }' R, L% ^3 f4 _' |, a0 Q
- exit(json_encode($data));
/ s: j5 u7 o$ p# z% _4 ~, d: M. k - }
复制代码 9 q C* K; z. H- y
$ D6 x( u) E2 g6 ]( p
|