您尚未登录,请登录后浏览更多内容! 登录 | 立即注册

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 5739|回复: 0
打印 上一主题 下一主题

[php学习资料] MySQL(表锁)、PHP(文件锁)锁机制及应用场景

[复制链接]
跳转到指定楼层
楼主
发表于 2022-3-17 15:53:00 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量
  1. C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php   // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码

# d; X6 p- o4 Q- i( B; e" l
Mysql中的锁语法:& D3 z0 S5 a; g% |+ M2 T
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】" a' G/ u0 ~+ J: \
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表: d9 Y* @2 q$ _. v* p
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞# B2 Z! ^. e; ~2 f: e1 m" R
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :  b! O' @5 t8 }" T" N
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
* H+ I0 Z+ k2 W9 }+ G: s测试时,有个文件就行,叫什么名无所谓
总结:
8 a: S+ a+ R7 J项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:1 p% V, X0 c9 k
1. 高并发下单时,减库存量时要加锁
  W' t$ [, G  S  ^2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*2 o# F' [9 o3 J0 |5 n4 r; Y/ D
  2.     模拟秒杀活动-- 商品100件
    0 N1 X! p% a) J$ r. B: ~6 y
  3.     CREATE TABLE ta# Y  P" t1 @9 Q2 @" ]
  4.     (
    4 v8 ^3 I: W0 Y/ v+ j; k
  5.         id int comment '模拟100件活动商品的数量'
    8 K' Q8 Y2 q- v
  6.     );2 P! G5 x5 s6 |2 L
  7.     INSERT INTO ta VALUES(100);
    / Y% u9 W0 U8 _/ P; P
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    ( U- `. g* i/ Y+ E/ _( H# [) }( T. M
  9.      */ 6 Q$ R4 Y( n$ p- m; ]
  10.    
    ) O/ f0 ?. M" Q) t- M! y
  11.     // 关闭错误报告
    1 b3 N' c+ {6 J. ^5 i% [; p
  12.      error_reporting(0);
    " ]  _" D# Q3 h+ o; C$ M8 }* y

  13. 4 H% B9 q* O5 |% h
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址" {& `) F1 w, \3 J" F1 Y& _% O
  15.     $dbuser = 'root';            // mysql用户名
    . f$ ~! a6 g6 O! E: R3 @; ?  G& C
  16.     $dbpass = 'root';          // mysql用户名密码$ \/ q' Y: O( g- ^8 `6 t
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    0 o7 o! b$ z: l8 ^! D' B
  18.     if(! $conn )& V* Q0 e8 p% h+ `
  19.     {2 _6 u4 `/ G$ U8 r$ R
  20.         die('连接失败: ' . mysqli_error($conn));
    0 H% s" r( h. p: W
  21.     }
    $ t% ]9 `+ X% Z. Z* b
  22.     // 设置编码,防止中文乱码) r* _, u4 X! p5 J
  23.     mysqli_query($conn , "set names utf8");
    9 G# M- B8 L* k2 x6 t$ Q
  24.     mysqli_select_db( $conn, 'temp' ); 6 f/ F2 b" j' }9 M% X

  25. * N& `4 b6 h6 E$ z8 w. i. N
  26.     # mysql 锁 $ l( ^' N: k+ {1 n
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    ; l1 P) r, |$ M
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    % D0 y/ m) D4 z5 S% T
  29.     $id = mysqli_result($rs, 0, 0); - [, R$ y- D5 S/ Z* P) S( U5 L
  30.     if($id > 0)
    % e# d$ {1 x9 q
  31.     {
    " O+ Q6 ^4 ~) i
  32.         --$id; + S. W7 b5 f2 [' s* a
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); - Q& f0 ^$ m, h4 \, b
  34.     } . p% A" G' ?- Q/ w! m% ]
  35. ) G) g, \) f5 o; p
  36.     # mysql 解锁 * \2 K; O1 v+ o, |- M! I+ Z
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    / J  n- i9 a" c% y" o/ H& [  T
  38.     //查询解锁后的id值
    8 b6 H& r) x3 h" Y
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');5 o: j4 x1 `# g4 F; i
  40.     // while($row = mysqli_fetch_assoc($res))& Y( y: H$ r* j  V# u9 C. t6 l
  41.     // {. @1 Z/ Q7 `: w+ c# j; _* o
  42.     //     $id = $row['id'];
    0 ]' G( l/ m) {# q1 P
  43.     // }
    - N6 B& `! j. v- r1 O
  44.     // echo $id;
复制代码

& L: ^! N6 j6 A0 {1 Q# a( N) m
0 l1 S- \- e! i/ g' d& ^

+ u" X- E, Y$ f
PHP文件锁示例:
  1. /*8 v( W3 r" S1 d1 y* ^
  2.     模拟秒杀活动-- 商品100件. S+ @7 M' W; _5 B
  3.     CREATE TABLE ta7 C% s$ y, n( c: }( q$ I
  4.     (1 k; b! J& C! v0 i0 N5 H- ^7 Y3 ^
  5.         id int comment '模拟100件活动商品的数量'
    # t8 ]! b' E' U; w& ~
  6.     );
    + Y) u; ^1 L! I2 B+ s
  7.     INSERT INTO ta VALUES(100);% l. b, s  h2 v- F
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    . Y2 P& J7 F$ j
  9.      */
    3 U5 E) u5 U) R2 Y( m$ {! x
  10.    
    3 O$ }  @6 o6 @9 `! f
  11.     // 关闭错误报告
    / E* P( z7 ?5 O. d/ `' f
  12.      error_reporting(0); 0 Q5 n- M2 F" ?2 g/ p3 ^! v/ w" r
  13. 7 O, b! `/ q7 M# {
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址1 I/ ]' b2 d1 J' X( _3 ]; N* n
  15.     $dbuser = 'root';            // mysql用户名
    8 f) _! T6 `* p- b! y! g
  16.     $dbpass = 'root';          // mysql用户名密码& O4 N. j$ L/ O/ W, n; r) |5 B  D! U
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);9 V: ^) J# U% t$ w
  18.     if(! $conn )
    + D- X$ _  v9 }: |: H; z
  19.     {4 o1 S( D+ f( u" i0 K
  20.         die('连接失败: ' . mysqli_error($conn));
    1 |- Q) @* ^. e/ i" K1 a/ g+ a6 x, T5 u$ X
  21.     }4 Z6 d. @& I6 A: g( p
  22.     // 设置编码,防止中文乱码2 @6 s& _# e$ N  H3 R- a
  23.     mysqli_query($conn , "set names utf8");% m5 G. p+ \( x$ `! o# B, d3 G, l* Y
  24.     mysqli_select_db( $conn, 'temp' );
    ( ~6 D9 b0 j0 L1 Q) F
  25. ' f1 ^( }& W4 m3 U8 @+ l/ T
  26.     # php中的文件锁
    $ l! K8 B0 ?) }6 z, M) ~
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    6 o, ~& v- }7 N
  28.     flock($fp, LOCK_EX);// 排他锁
    7 P  E. ?7 f8 i
  29. . \. z: b% Y; q; A" Z, k! h
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); , l. Q; w& |* K6 Y' f1 d
  31.     while($row = mysqli_fetch_assoc($retval))
    9 ?  L1 X; E3 i5 F1 B' X
  32.     {
      p0 k& \8 P6 S* w
  33.         $id =  $row['id'];
    0 i* b# `  s1 C8 n2 G* m+ q8 [- w
  34.     }% ?" X( X% J0 l  k
  35.     + B5 u7 _/ b! z/ ?0 X
  36.     if($id > 0) . L& D$ b. ?$ F, B  M' n
  37.     {
    8 {! Y# M# v) N6 ~7 d1 w$ ^
  38.         --$id; # ^4 \' q( `0 Y: ?1 x
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    3 ], E- s* J6 {
  40.     } + p0 ~/ L, B3 N# H; _/ N
  41.     # php的文件锁,释放锁
    4 z( t8 A6 T: H' r8 f* K( {
  42.     flock($fp, LOCK_UN);
    ( ]9 z! W8 r, Q6 r
  43.     fclose($fp);' M. a) }1 `* Q$ D+ f  D

  44.   Q4 H; u" r0 E! S
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    6 \' Y3 D2 F. M1 Y4 @
  46.     // while($row = mysqli_fetch_assoc($res))
    / S* {- H( I) C1 `
  47.     // {/ }" b6 g% J$ H& }) [
  48.     //     $id = $row['id'];
    # ~8 d1 a: Q- {4 k( l
  49.     // }
    9 F* S. F1 H- F4 }! N4 U* S
  50.     // echo $id;
复制代码
" j7 n  a' P! A' V- y
* N$ j# ?) [5 @2 o1 v$ a/ d
抢券活动实例:
  1. public function envelopeSnatching(){
    : g0 |! W6 n' |, y- ]6 T8 i$ Q4 U
  2.         $lingqu = $_POST['type'];
    2 \7 [+ g3 n1 Q: a" v& X
  3.         $uid=session('u_id');//用户id* t% g+ P* J9 L/ `: F% i. r* W
  4.         if(!$uid){
    , a  ?% B* O$ a- J9 F9 b
  5.             $data['msg']='您没登录,请先登录!';% B$ R. n. p/ z: j5 r+ [
  6.         }else if(date('Y-m-d') != '2017-12-12'){2 S. x( T8 `" F4 y% y7 {! W0 p
  7.             $data['msg']='不在活动时间内!';
    / J, f& V- x# G0 b
  8.         }else{
    , s% n( X+ o9 P/ ]$ M, }& J
  9.             $hours=date('H');//当前小时数* K& {% u/ ~5 ]. P
  10.             if($hours > '09' || $hours > '17'){3 ?" S1 G5 B# I+ C' H' z

  11. 2 \( K. i. I- A3 W3 z* f
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的5 b3 X5 s3 D- Z% R0 X1 T2 U, u) @
  13.                     if($lingqu == 1){
    - w4 G1 c8 M% u7 e3 n" D
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    ( S3 o/ d9 w# A5 a
  15.                         if($hours > '09'){3 y5 O6 Z8 t9 U, }) N: ^4 v
  16.                             $num=mt_rand(25,28);//优惠券金额
    ! d5 K& n* o& U7 r
  17.                             $id=1;7 ^& K* q) l# C. X
  18.                         }
    : }' p3 h+ f* o4 Z% P: k$ B7 r! ~7 o
  19.                     }else if($lingqu == 2){
    . S- p* W+ _: g0 d/ r; |
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    4 `4 _$ G8 M0 w. R/ ~
  21.                         if($hours > '17'){) F& K5 i9 J" }) Q$ F7 i
  22.                             $num=mt_rand(50,55);//优惠券金额
    9 K/ _8 E% N. ]4 H( P
  23.                             $id=2;
    % X8 c/ m2 L0 y: T4 C
  24.                         }
    $ ?. p1 V: B* o5 H& |& k$ a
  25.                     }
      ~/ k* a) P$ S! X
  26.                     if(!$id){
    & Q6 A1 K8 q8 w" R/ v
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    - Y1 o( [3 S1 A+ L8 f) d9 X
  28.                     }else{
    # V, k) o4 d5 |9 L, U' \+ c: H" r
  29.                         if($is_lingqu){
    8 g4 F* w, A0 N
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    6 F7 |6 l! s# j; ?5 ]9 z
  31.                         }else{
    # c+ k& B1 y( Q* j) [; C. h
  32.                             //锁表
    $ x# F# A% C8 O- k
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');, C* M0 B" X( L! p9 z
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    ; p. [6 d1 ^# F
  35.                             if($active > 0){
    2 T# V$ Y! w  r6 i7 _' r7 `, @
  36.                                 //开启事务8 s; L- x& B  d# _" U, x
  37.                                 M()->execute('start transaction');
    5 I7 m6 B# r, M+ }( o/ G
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));) @1 Z% c" [5 j$ r3 d) s
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));0 E7 h1 I* n+ b- L% c. C
  40.                                 $members_preferential    =    M('members_preferential');
    - U% q$ ^, C$ L& W9 L
  41.                                 //对应投资金额,
    % z, r0 S. S7 u
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    ' D* A+ z2 b. _2 {
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
      W, S- o' H+ ~; k6 C5 [$ @* H; I0 M
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    & G2 E. U5 X( S( L, N/ n; ^) L2 t
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    : e5 P" t, {* m7 P% ]. {
  46.                                 if($save && $add && $add2){
    ( D7 p9 h% I1 s9 _! [/ ?: X6 m" [% S
  47.                                     //事务提交3 Z5 V+ B6 E, m! g' J/ k1 W2 Q
  48.                                     M()->execute('commit');
    ! [: ^4 E6 ^; J$ q5 I
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';3 k; W0 u" ~, H3 b
  50.                                 }else{
    1 Y& A& T( L; S* o4 s! l; |, d, R
  51.                                     //回滚
    7 _# q* n4 s! J8 A# e! W& c5 M4 g
  52.                                     M()->execute('rollback');/ I) W* l0 J* `$ O, Z
  53.                                     $data['msg']='未知错误!';
    ' I9 g( H. P2 K. z+ L; m6 [0 h
  54.                                 }" K9 X3 [% i# X4 ?
  55.                             }else{
    5 P5 {. S5 l5 M, @2 t. K
  56.                                 $data['msg']='红包已领完,你来晚了!';1 j  }1 k* D* m% [7 c
  57.                             }( s1 F/ D5 I% l0 X$ F
  58.                             M()->execute('UNLOCK TABLES');: p8 i% Q7 G( O5 `; B3 [" {
  59.                         }8 {% r& j  k: i9 C" S8 g
  60.                     }
    - q6 A% b* U. r6 M; H; f
  61.                 }else{
    . \1 Y# _, _) G# d1 c- W
  62.                     $data['msg']='非法操作!';
    ; k" C6 N% r% T' Q. {3 Y
  63.                 }$ Q$ C. j! ^8 W5 S) n
  64.             }else{2 j6 O  w8 C( u2 J: {; |  Y
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    / u; L0 i- O, X. d! m: n5 a# [
  66.             }
    * l8 u5 K2 F* X2 k' F, {; ^/ c
  67.         }- K6 T8 I! q7 |, h9 f; X: _% o* h
  68.         exit(json_encode($data));
    . \" O4 n5 n! B) |$ W
  69.     }
复制代码

$ t- S$ `) F* O3 t' G; W; {. f8 a% \& r' l9 H3 A  o/ n; o
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 16:12 , Processed in 0.106625 second(s), 20 queries .

Copyright © 2001-2024 Powered by cncml! X3.2. Theme By cncml!