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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8893|回复: 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://请求的脚本
复制代码
. |9 F0 p- |) ^) Y
Mysql中的锁语法:! e- {# l9 @, ~, @7 G. U7 J1 D' p
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】# v" E# v8 t  h/ m* I1 V9 i
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表5 m2 H5 _' `: B( I% e9 ]; u
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞$ w9 k+ E3 }$ \
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
: T9 }* @% h8 {" j  ]; B! F文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。/ q% E1 l2 g$ L4 h4 M
测试时,有个文件就行,叫什么名无所谓
总结:
. I! }& t. o7 ?$ [项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
; F1 ~3 b! I: l5 D: j0 g/ ^( e1. 高并发下单时,减库存量时要加锁( C& E8 R/ }, `  q
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*# U1 a2 x+ w; w1 z5 t7 x. \
  2.     模拟秒杀活动-- 商品100件1 c# g" {* r0 i7 \. r, k
  3.     CREATE TABLE ta
    4 n) ]0 [" W6 c9 U8 o9 {
  4.     (6 p* ^! H4 S$ J$ g0 U0 H
  5.         id int comment '模拟100件活动商品的数量'
    , K1 m9 ]8 A+ A% ]- V
  6.     );; {" M5 i& l8 p0 k1 n
  7.     INSERT INTO ta VALUES(100);
    & ^' s8 r* V: D# k3 L/ z0 K& T
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件7 q' |) B  h, |, B8 p
  9.      */ ) x8 `8 G3 Y  h9 }
  10.    
    7 p% j0 \' @. e. c
  11.     // 关闭错误报告! _; T# G" Z% s( X) G: _5 a  K
  12.      error_reporting(0); 3 U' M9 M# I% Y4 B

  13. ) @5 R' ~# o* D3 i8 z( G5 Y
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
      f* V! K% E3 [
  15.     $dbuser = 'root';            // mysql用户名4 I. w9 _+ h7 c6 Y$ V
  16.     $dbpass = 'root';          // mysql用户名密码
    5 c( F* D9 s5 y1 c6 w  k8 o/ ~
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    # ?3 o- ~) R3 x( _: r
  18.     if(! $conn )  R3 X; m) H; ?2 u7 R( W7 D+ Y" ^
  19.     {, d( {: o6 }. V$ ~% w4 o
  20.         die('连接失败: ' . mysqli_error($conn));9 ~9 o4 K, r* }- H
  21.     }
    ; {& Y# x" x' d* B  N8 P, J) D! y" K
  22.     // 设置编码,防止中文乱码* F% E0 p: P  u* @
  23.     mysqli_query($conn , "set names utf8");+ [, s. d; A5 p2 o  X
  24.     mysqli_select_db( $conn, 'temp' ); 4 C- Z) ]( P; u

  25. 4 {; A" q5 _+ k+ ^5 H$ b
  26.     # mysql 锁 0 L9 L. [9 Z* v% ?, r" i
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    % s. h9 |8 f( n% B* f
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 5 N% y' Y0 B" {5 F9 C- y
  29.     $id = mysqli_result($rs, 0, 0); & X2 l7 n6 g- n3 \1 M
  30.     if($id > 0)
    & }+ e* d, r+ l, N( F* o
  31.     { ' O6 W4 V4 d% I* Y2 Z+ X
  32.         --$id; * s7 b8 @0 L) z% t  n' J- }
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
      ]# M5 o8 a. j8 [4 c. }9 U4 {
  34.     } & T# e' _0 }6 t; i' x; r2 X
  35. $ J$ {- z2 U; c
  36.     # mysql 解锁
    ) c2 U$ n" S/ W6 m3 {/ H
  37.     mysqli_query($conn , 'UNLOCK TABLES');. Y. C% D- V& u
  38.     //查询解锁后的id值$ S( P6 V9 w5 X
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    + p0 k3 h7 F6 P7 C$ E- T1 u% x3 a
  40.     // while($row = mysqli_fetch_assoc($res))
    7 m# c2 x" \  R: ^) a  O
  41.     // {$ n* }# {: B% W+ O; B- X1 |( E5 P9 f5 [
  42.     //     $id = $row['id'];/ r/ q0 R* i- ^% N/ k( E
  43.     // }, M7 q, B4 g3 {
  44.     // echo $id;
复制代码
; v" S* E2 ]8 j2 Y5 x& p
6 ]) I" L5 o$ c: n; [* H) u

( N; h( s0 P& g, @! s7 \6 L
PHP文件锁示例:
  1. /*: W; c. V; ?6 z
  2.     模拟秒杀活动-- 商品100件) e3 V' b( C3 w! g2 ?/ G0 C
  3.     CREATE TABLE ta) \; `  l: F* v! V' b5 Q9 [: w
  4.     (/ t7 |4 U  r4 e3 o0 w! w
  5.         id int comment '模拟100件活动商品的数量'
    ; \. w1 h) d% I9 s3 }1 p
  6.     );
    3 ~  x/ c/ H1 [5 g  w
  7.     INSERT INTO ta VALUES(100);
    & G- @  O  W* B& |$ ^
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    6 |  u+ z; p3 L6 Y$ L  m
  9.      */ / A  `" |0 _' M5 s7 M: F
  10.     * i5 k/ j( S; M- G& K6 U. I$ d
  11.     // 关闭错误报告% O$ B' q3 T# P- O$ D
  12.      error_reporting(0);
    , Q- \9 k& _- N

  13. 2 E* x( I4 M* F9 j0 Q% G  i  @% W
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址+ m6 \& s9 L$ A* B- l; p
  15.     $dbuser = 'root';            // mysql用户名
    : D: Q5 ]5 G" V' t+ g# ^" g
  16.     $dbpass = 'root';          // mysql用户名密码
    ' g$ k5 u5 o) Z% J- A0 l
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    9 T; a9 s+ A$ Y/ z  q* r! H# s6 m
  18.     if(! $conn )
    ' ?+ ~0 H* j! K9 D
  19.     {- O/ F7 R; p0 D0 K8 D8 [" F
  20.         die('连接失败: ' . mysqli_error($conn));
    ( g2 j! c3 }, h
  21.     }
    # l) f' R7 C' t  f" z! i' K' f
  22.     // 设置编码,防止中文乱码
    9 m; F, [' {" `
  23.     mysqli_query($conn , "set names utf8");# M% h4 F$ q4 K" s
  24.     mysqli_select_db( $conn, 'temp' ); " V1 W: f0 A& J' t# {( x9 N# ~

  25. - ?& y0 O1 p% \2 F
  26.     # php中的文件锁 ; F2 [2 l: H9 L0 U
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 * t9 s* ~0 N0 K% T1 Z8 I' u) }
  28.     flock($fp, LOCK_EX);// 排他锁
    - _! R% q0 v, q' K7 y  h/ J  @
  29. 6 H- T* V# Y- H5 ^4 [3 f. Y
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    ; L  f1 O7 S1 l+ P' T- E' S
  31.     while($row = mysqli_fetch_assoc($retval))
    * Z: [/ R# q* D. j  W1 l- S
  32.     {5 `! Z; k% A6 w- {1 ^( ^$ d
  33.         $id =  $row['id'];
    , l1 }! Q. x5 S9 f! D) I  {
  34.     }( c& K6 G6 }9 O
  35.     5 d9 g" o( l, p' U9 r( e% N
  36.     if($id > 0)
    ( ^. ]) W- C$ a
  37.     {
    1 n! t% E) s6 L) B
  38.         --$id;
    : W  L  R1 m+ c9 @
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    , x" x) j/ @/ F' a! r  r
  40.     } 8 K* D3 _6 b& |: D# C
  41.     # php的文件锁,释放锁 # W4 z6 p( C% B9 Y* W0 `
  42.     flock($fp, LOCK_UN);
    ( H/ @7 t! @# S8 @5 y
  43.     fclose($fp);
    ; i+ e  u# \) K
  44. 4 F; J6 `# q6 d
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    2 b; P% _3 q/ ~" z; T- g) m3 i/ Y
  46.     // while($row = mysqli_fetch_assoc($res))+ i* c: O# L0 d5 Y4 J
  47.     // {
    $ E7 [; L1 R5 k" }$ Q# Q5 G# U
  48.     //     $id = $row['id'];: f$ \, \8 c; B) o1 j
  49.     // }
    ' y/ L2 u0 w7 |5 ^# p% f3 j  {
  50.     // echo $id;
复制代码
4 g7 W) S! W" j! {& z
. {- p# N, j: k, ?3 T
抢券活动实例:
  1. public function envelopeSnatching(){
    " q7 M5 n* X; ]! C
  2.         $lingqu = $_POST['type'];
    $ b  v% ?4 ?1 w- b2 J8 a4 k' @' t
  3.         $uid=session('u_id');//用户id
    ) _! {& n1 f) V) V1 }$ a  ?$ Y
  4.         if(!$uid){- X; o7 W* H8 T5 G
  5.             $data['msg']='您没登录,请先登录!';7 [% c/ Y+ T- `3 }% s8 c
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    6 F6 q9 [: ^. t4 I6 b1 b
  7.             $data['msg']='不在活动时间内!';9 v5 Z& i# x3 k- c9 R. E4 c# R: P' @
  8.         }else{4 m/ T, d" p! }6 s: j6 w
  9.             $hours=date('H');//当前小时数- G1 }6 |, n" ^3 X6 v) }& `) @
  10.             if($hours > '09' || $hours > '17'){
    # d% U- O% D9 h$ o. Z
  11. 3 x: j0 l, S( U% ]
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    ) i8 n  a9 Y7 X. m) R& Q1 ~+ G
  13.                     if($lingqu == 1){. D6 }. H& T: e) ]+ F
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过. I& ]# r" s8 z  w6 Q6 W) H5 k; m: }
  15.                         if($hours > '09'){
    . T, ^$ E. ~; w$ a8 z: Z
  16.                             $num=mt_rand(25,28);//优惠券金额" |0 n: q3 m& P) i! Z1 P
  17.                             $id=1;
    . b9 p. @, J" M( t6 [) u9 j
  18.                         }* R! f9 L; V2 `* i+ A4 i4 W- {; Q
  19.                     }else if($lingqu == 2){
    8 n4 q' ^1 v' M+ \+ m7 {) F) Y
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    - [4 Z6 [. J4 R* |
  21.                         if($hours > '17'){
    0 G# _$ j1 A: I) i" Y5 m6 D
  22.                             $num=mt_rand(50,55);//优惠券金额1 @. [/ x2 O. Y% p; _3 v. Z
  23.                             $id=2;8 G; B' u1 V, ?9 o
  24.                         }
    + a9 G( V) `5 \7 ]' w$ N/ k
  25.                     }! u) f. r6 E% c# [6 {) B' c+ T( h
  26.                     if(!$id){
    ( s' Q! w  Q1 \* [: B- v' k
  27.                         $data['msg']='时间还没到,晚点再来吧。';) C% n9 _3 @$ a. K) v
  28.                     }else{
    . L. ~1 i; z7 F) q$ u, z: W
  29.                         if($is_lingqu){% N* V- p: p1 Z; R1 G
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';! }) g/ ~$ @& d( b
  31.                         }else{
    7 z! P3 }9 c; M: H5 ~4 n
  32.                             //锁表1 P% m1 \0 B4 h2 n
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');; R- i8 w6 E6 ~1 l1 S  V
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    6 J9 {# o" {- i$ m% c
  35.                             if($active > 0){
    . R: b9 r7 M! I3 Y5 }: F  P8 B5 l  b
  36.                                 //开启事务" f; B' @3 G2 l
  37.                                 M()->execute('start transaction');
    : w5 \' W7 N2 G# Q
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    5 s- y# H/ G" t! k" ~3 b5 S
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));; g& X. ?* ]' V' w* R5 x/ |
  40.                                 $members_preferential    =    M('members_preferential');5 i8 F+ I# b5 c0 R+ {9 q4 a  t+ }
  41.                                 //对应投资金额,+ V0 M9 K  M9 H. {
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));1 G% c6 E( v0 }4 }
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');& {# F2 i% \0 s" }' n
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间/ R. y3 |) G, u& d
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    9 d% N& T2 }2 U5 _9 c6 R# |
  46.                                 if($save && $add && $add2){
    & a; Z0 q: e5 a1 E! ?% {8 P& j
  47.                                     //事务提交% l* }& i* a  h) t: e2 V
  48.                                     M()->execute('commit');
    ; l# y& ?- m  ^) F0 J
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';) s" Z1 }4 [0 a4 G7 u6 p
  50.                                 }else{( x! E$ c' c1 ]
  51.                                     //回滚; E/ C3 L. _  @: w% h0 I: h5 u
  52.                                     M()->execute('rollback');
      e# \, n0 q( g. Z) c5 ]9 H) j
  53.                                     $data['msg']='未知错误!';
    , e: ]: x. }' X& p/ Z( D
  54.                                 }
    " [$ d( _1 i$ d6 K- u% _
  55.                             }else{
    * r: N# @* I2 H" l8 P6 o) q
  56.                                 $data['msg']='红包已领完,你来晚了!';
    6 C  C; W: M& h  t+ ]
  57.                             }4 Y1 ^% ^% i5 ]& s0 B' W
  58.                             M()->execute('UNLOCK TABLES');
    4 a' m! k+ U4 b$ @' N/ q$ O8 B. a
  59.                         }  a8 U8 E# c5 j+ n* a0 J
  60.                     }8 Y- ?) a9 ]$ y8 N8 r
  61.                 }else{
    % n. Z3 u1 o+ r$ j5 H& g+ S
  62.                     $data['msg']='非法操作!';* D" X) C+ q% B# y2 ^+ g6 c
  63.                 }
    7 U9 t" A8 `  m* j& a4 f: f
  64.             }else{  K" g; H, j6 h1 x2 W4 c" Y
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';: Z5 v, L  ^! H, S3 ?' }& m
  66.             }" }+ ^4 g8 w6 i" c2 {& s
  67.         }
    4 v& V6 K7 ?  }5 n5 [( B
  68.         exit(json_encode($data));
    * V/ o( v8 _6 R0 t" N
  69.     }
复制代码
* P7 k, @7 T+ X: Y: f, ^$ `# b

  z0 O: O' k% D  a9 n* m8 F
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-6-19 22:43 , Processed in 0.057199 second(s), 20 queries .

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