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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8214|回复: 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" e! D: D1 b- q
Mysql中的锁语法:
4 ~7 x1 [$ s: h3 @8 {0 B4 VLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】7 V" M7 V( K: r) L! H0 c. H
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
* }- o9 ^, ]: e! C& xWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
. B$ R9 M7 v$ j. M) J注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :$ M6 [9 z* j1 q4 u/ P
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
2 A" n' G; d$ b3 Q% e5 j# x测试时,有个文件就行,叫什么名无所谓
总结:
. f4 e, w& t; f项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
8 c, i# Z) n0 d2 m3 K1. 高并发下单时,减库存量时要加锁
, m1 d& G# g6 J( M/ p: [4 q2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*& k- T, Q( }8 O
  2.     模拟秒杀活动-- 商品100件
    # x4 J: n' g0 y; t: P7 p, D
  3.     CREATE TABLE ta, b5 t9 v" H* x9 h' y! Z
  4.     (( O3 |# q$ g: a$ I  c, m
  5.         id int comment '模拟100件活动商品的数量'
    . P* E# x+ H0 |$ U% D$ r, X/ a  W
  6.     );5 \; u7 A- V- P* u6 z
  7.     INSERT INTO ta VALUES(100);9 t* H7 u5 P. _. ]) z
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    ! A; v2 n* ~/ L8 ^% t# f% M
  9.      */
    ) e0 A  a5 @9 d% M+ j
  10.     ! t. l( Q' k0 H8 n/ n
  11.     // 关闭错误报告. [; B5 \0 `3 ~: i) ^4 a3 h
  12.      error_reporting(0); & Z0 [2 \  c* {

  13. $ P  h( Z0 F/ \( i, }2 ~
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址8 s" [( K3 {) w# v4 J2 g
  15.     $dbuser = 'root';            // mysql用户名
    : m) d: q9 E" k5 {- {: ~
  16.     $dbpass = 'root';          // mysql用户名密码
    + Z. z  o5 ?2 b% }$ P0 V
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    * K/ N. ]5 @+ A" [' p$ a
  18.     if(! $conn )
    # K- E8 a+ R! v( [2 T& p- S
  19.     {8 d3 [$ K/ O* ^" T9 U
  20.         die('连接失败: ' . mysqli_error($conn));
    ! z2 t2 B* M. t* ~& o! c! a
  21.     }
    7 O$ f& H! C1 K8 @: g6 B
  22.     // 设置编码,防止中文乱码
    , @, K6 s% D" D
  23.     mysqli_query($conn , "set names utf8");
    % h6 X" L' O5 d% T" k
  24.     mysqli_select_db( $conn, 'temp' ); 0 V. F/ ]$ y  l  K" r2 j
  25. + z0 ]9 c/ R( ]' R* P
  26.     # mysql 锁 " V, S( p2 N3 o/ E4 s: P. E
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    1 j6 |. z* D; {! S- Q  H9 d
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    " V6 u7 Y. X; M1 s0 x
  29.     $id = mysqli_result($rs, 0, 0); ( ?$ o, A) Y4 H4 R" c! Z) d3 w
  30.     if($id > 0) 0 b4 ~5 }3 j! j  o$ R: g- O
  31.     {
    ! A7 ^' z: {# a$ d2 {
  32.         --$id; / r/ u, ]; `- X
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 7 z8 W. m6 _4 p, `
  34.     }
    ( z6 Y" y. s6 ^7 F* [' U
  35. - i  q( i% f0 o; `1 y( i" Z, S- h
  36.     # mysql 解锁 0 }9 V1 O1 i$ B. ]8 ?
  37.     mysqli_query($conn , 'UNLOCK TABLES');' a1 T, c3 h4 ?/ q
  38.     //查询解锁后的id值# b7 F/ g$ @: ^8 y
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');) U; \3 [- W: R2 a  o3 }/ k0 P
  40.     // while($row = mysqli_fetch_assoc($res))
    5 j4 O* Z" c$ Z- m# c: ?7 v
  41.     // {
    * U& j& k' p3 `; w6 x  T
  42.     //     $id = $row['id'];! O" ]  Z0 g" K2 n
  43.     // }
      x" t' N3 x4 Z' j( t
  44.     // echo $id;
复制代码

% V* d. y$ q" V. b" H+ f" k" G+ x2 f
, r6 y2 X7 E2 U' V8 f7 ]" P# Z$ \
PHP文件锁示例:
  1. /*
    " D% I( j3 {$ v0 e2 q" [6 y' P
  2.     模拟秒杀活动-- 商品100件
    " _$ m8 O& [! C. c! z
  3.     CREATE TABLE ta. h* Q5 u$ @# Z' a
  4.     (
    + m7 W7 Y/ z. P1 K" h
  5.         id int comment '模拟100件活动商品的数量': p3 z" V; _: q& q! Y
  6.     );8 R" V. W. [% q! ^
  7.     INSERT INTO ta VALUES(100);
    ' x& d% n% S- D8 J) F2 Q
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件" g8 H) v: y! u4 k. [' U" ^6 }
  9.      */
      I# X9 Y( t' U" O* Y
  10.     $ O! m7 V* i# Q4 b
  11.     // 关闭错误报告
    1 G! o0 ?: u4 s0 Q' q
  12.      error_reporting(0); 6 W3 ^6 o: q, u. ]9 D- s

  13. 5 E8 K- h0 L' e1 q7 p9 t. {
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址* e* V( B/ A4 {% G: Z9 U& D
  15.     $dbuser = 'root';            // mysql用户名2 l/ M9 t' e# b. P1 j
  16.     $dbpass = 'root';          // mysql用户名密码
    0 o4 Q( b) |! _& ]5 k; U
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    % g& z+ V/ g1 ~( N( R
  18.     if(! $conn )
    # j, t0 A3 s( o# c0 O
  19.     {$ u+ y* b5 f% o; j, A7 {5 r+ {2 j
  20.         die('连接失败: ' . mysqli_error($conn));7 x* u8 O; P2 ]. _9 d) {
  21.     }& x& V; }# r% w1 ?6 r
  22.     // 设置编码,防止中文乱码
    , Z  S  L3 H3 l$ t
  23.     mysqli_query($conn , "set names utf8");; E* G$ A5 ?* g! o5 @- B# O, b9 b1 M
  24.     mysqli_select_db( $conn, 'temp' ); 9 S  {3 a" s7 ~  a8 r
  25.   `* u$ T( |/ V% P8 S
  26.     # php中的文件锁 2 v7 [( l7 s1 D0 H) `! K) I1 {
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    6 p9 U5 o$ M4 ~, c
  28.     flock($fp, LOCK_EX);// 排他锁
    4 U+ F5 k# I  P% t& A* x3 h

  29. : z! h1 z8 V5 V& [  H$ R8 K
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); - O1 U. F1 a! E# R: N8 G0 ]  t& w8 u
  31.     while($row = mysqli_fetch_assoc($retval))
    3 \* ^9 t* _: }* X9 [
  32.     {  u+ O5 U- v7 \' f- f. g( c0 n
  33.         $id =  $row['id'];
    ' p  I* m: t- u% H4 `- ?, b9 q5 U
  34.     }
    * ^7 t- z, r3 Y4 C
  35.    
    9 G/ I) N& b3 i5 q3 b+ m
  36.     if($id > 0)
    + Z. ]4 }/ {1 n% |# \; D: k0 }- E
  37.     {
    + L1 @/ |- ?+ p1 G; d6 Q! w2 r
  38.         --$id;
    , V- q1 o7 _0 q4 A7 c4 V
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 2 P5 J0 {- K# a) w. I9 @* ^
  40.     }
    $ X/ U$ X0 c1 D& U+ [2 t
  41.     # php的文件锁,释放锁
    3 h% @& E% E' C2 K, v  P: n& I
  42.     flock($fp, LOCK_UN); + y5 N5 v0 R- d
  43.     fclose($fp);
    7 H1 Y% n7 L6 O& _
  44. 0 N: X* T5 h6 N
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');4 ~& z+ u* G" }. M' ^5 N
  46.     // while($row = mysqli_fetch_assoc($res)). p. E8 [2 }( ~/ x' W1 ]2 R
  47.     // {
    + q# Y% T, l  i7 _6 h0 I
  48.     //     $id = $row['id'];
    ( \$ E* W1 w" I$ T7 D
  49.     // }8 ?+ o( x+ U& L9 _4 l
  50.     // echo $id;
复制代码

  u7 |% l- M5 w: W, m) T6 f6 S: i1 r. k9 j! l6 h/ Y. @* r
抢券活动实例:
  1. public function envelopeSnatching(){
    4 U* C) {- k3 z
  2.         $lingqu = $_POST['type'];, n5 u3 j) N- N7 r& i
  3.         $uid=session('u_id');//用户id2 s2 c; e4 O& h
  4.         if(!$uid){
    - \. O9 h4 B4 Z% A9 B/ Y
  5.             $data['msg']='您没登录,请先登录!';- |* O; v! ]1 t4 x
  6.         }else if(date('Y-m-d') != '2017-12-12'){; K" e; q  T2 c6 x" X
  7.             $data['msg']='不在活动时间内!';
    & L. Y/ S2 m  J% W! @
  8.         }else{" B  z0 ^. i$ k7 o% v% d# w
  9.             $hours=date('H');//当前小时数
    . Y, w: G/ `+ G9 s% t+ L
  10.             if($hours > '09' || $hours > '17'){
    ( h0 M) D7 g0 B

  11. . Y" l' v" `. y  A0 b5 P! f
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的7 t: B$ q2 m6 w% Q+ Y" ~+ D$ H  u
  13.                     if($lingqu == 1){6 c' D  ?6 k) n, M, L/ T# R8 _7 [
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    3 i6 \$ V. k. b- p* ~; r- Q
  15.                         if($hours > '09'){
    : z3 k, g; _- j8 T
  16.                             $num=mt_rand(25,28);//优惠券金额( z& S; f$ |; F7 [5 U7 `
  17.                             $id=1;
    / H" Z; Q' ?. w& q) U7 P
  18.                         }: e7 e7 z, ~# X: h% Z6 x
  19.                     }else if($lingqu == 2){% H! a+ p! X- X5 G8 i
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    5 P6 ~. o8 r) _0 W* T# S: B- q
  21.                         if($hours > '17'){. L4 S  w/ C8 J6 x8 `4 o7 C% x
  22.                             $num=mt_rand(50,55);//优惠券金额  a. {. M* N; H5 w. P: l: G
  23.                             $id=2;
    % p7 V6 P. S- ~+ d
  24.                         }
    ; [/ N- J" ^2 O
  25.                     }
    8 m- Q0 S( {3 w
  26.                     if(!$id){, F1 p0 g- R2 t9 g
  27.                         $data['msg']='时间还没到,晚点再来吧。';2 \9 Z7 s8 L) T4 a' P& B
  28.                     }else{0 E: }3 J& @' }! T+ [; [: V5 r
  29.                         if($is_lingqu){
    - y& R5 n" t; S& ^7 l7 H
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';# g7 Q( Z' N; ]: X3 V
  31.                         }else{
    3 K7 w- T0 v8 M9 N% B& E/ h0 F! E$ ?6 S
  32.                             //锁表
    ! E2 d1 D8 X. h( s: V) r+ d8 K
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');$ X; C' W" n/ M: F# @' ^
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();$ B6 Z9 H/ z. h( Q
  35.                             if($active > 0){# j% ^3 A( a8 t, w7 k9 ?
  36.                                 //开启事务
    7 t, i  p% N+ d  h4 u; D: n
  37.                                 M()->execute('start transaction');0 H( N  {& b& _$ H$ Z
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    - b: Q1 i# z5 Y2 I
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));# z. d# O2 r: N+ }
  40.                                 $members_preferential    =    M('members_preferential');
    + h7 k/ Q6 k) |: J8 ~$ q
  41.                                 //对应投资金额,+ z+ h' d. V, f8 s: x
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    # q; E: m5 M% _: l# O5 W4 z
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    " q: V& y3 _# w
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    9 \3 E$ y9 F  }9 ^5 r7 {7 r
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券( Y  G, n% T/ |/ G* F* @
  46.                                 if($save && $add && $add2){
    + J4 u/ `+ `+ n# T5 u7 ]6 `$ E
  47.                                     //事务提交
    1 j! m: v! R2 a* A( [  f
  48.                                     M()->execute('commit');
    . G6 [/ R6 K* g$ _4 g2 b' Z
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';9 D7 @+ x, P- k# C9 R, L
  50.                                 }else{2 I# {( |6 p( i4 ]. j5 ?3 }
  51.                                     //回滚
    ! }# {3 {- H% g' J8 Y, }# {
  52.                                     M()->execute('rollback');
    - o* p# n) c; y
  53.                                     $data['msg']='未知错误!';
    $ I7 S) b, Z) q$ G% B$ R
  54.                                 }
    ! G8 F2 M8 }% U3 W0 I+ G. O
  55.                             }else{
    . P5 h% \5 ?1 @0 q
  56.                                 $data['msg']='红包已领完,你来晚了!';  s5 g; _9 l1 c5 {) Y; f
  57.                             }
    - r- T: _) d' P! T: Q* C
  58.                             M()->execute('UNLOCK TABLES');* k9 }' b" K# L, |# {
  59.                         }
    ( W, A: w9 m- J5 ~
  60.                     }7 c: ^. Z& G5 ~4 a- }2 K5 |: @. i# I
  61.                 }else{
    % q' F7 Z' l$ C1 n
  62.                     $data['msg']='非法操作!';3 _* S3 S3 Z* Y" q
  63.                 }  e" O/ K1 k7 z3 W2 a( `
  64.             }else{
    9 W  e* J) P8 [9 f
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';! t6 a8 }+ I  O* ~. r: y8 M6 b1 b
  66.             }: L7 ]  l9 _1 r3 _
  67.         }  @, \3 G# s' o1 y3 a5 M7 E
  68.         exit(json_encode($data));6 ^$ K' J. ?1 D' P- d  x0 @
  69.     }
复制代码

' X5 n# S3 x8 ~8 z1 e: m4 b5 D! i- V5 z% B; V
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 15:53 , Processed in 0.061780 second(s), 20 queries .

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