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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8667|回复: 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://请求的脚本
复制代码
' Q) U* f, T, T; a6 A- e! V) X
Mysql中的锁语法:
- e  e' x- b7 U" i( T% F" ULOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
$ K9 a5 \* ~3 ~' C% G4 A6 CUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表6 p$ U* \# t. ~; A. N
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞: k. m9 F! c5 @: C; Z
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
* w! W4 h4 S  @8 b文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。& x4 c5 _" K2 \; h+ h6 _
测试时,有个文件就行,叫什么名无所谓
总结:- P3 L" P' v$ e! E% f2 G9 B- M
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:1 z  I: j2 w! s  e0 V+ t2 k
1. 高并发下单时,减库存量时要加锁+ U  v! {  K# W' c9 v# `
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*; p/ @; C' R* M6 f% O* x8 L' j: k
  2.     模拟秒杀活动-- 商品100件4 c; x' i, x6 E' m$ ^
  3.     CREATE TABLE ta
    9 `- w! o! _% {& `. u, |& z
  4.     (
    ! W( h2 p' G, g8 Y9 e
  5.         id int comment '模拟100件活动商品的数量'
    4 _; L! B! G% {
  6.     );
    7 q, p6 i: O" x: X) b# Z, B
  7.     INSERT INTO ta VALUES(100);
    + a/ \6 r; \# h
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    , q4 x% c6 Q  U$ L
  9.      */ % U8 E3 n1 y7 f$ ?. b- O" f  `
  10.     6 @* y2 k$ ~: E
  11.     // 关闭错误报告' n2 ~$ v2 S8 E  [
  12.      error_reporting(0);
    ) M0 J; f' m$ C- ?1 F! d9 I

  13. 6 C. Y( l+ ~0 p
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    6 Y4 u8 y5 o. p& F+ @) q
  15.     $dbuser = 'root';            // mysql用户名: Z: S$ |9 i8 E5 M" N
  16.     $dbpass = 'root';          // mysql用户名密码; ?+ a! R( l- e$ O( H
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    & n( b; n. O! k; j8 U
  18.     if(! $conn )
    % e# ?0 a! E; W3 k9 Z
  19.     {7 j9 L$ ~% [2 r0 v& b
  20.         die('连接失败: ' . mysqli_error($conn));
    * |: |% E) J1 F
  21.     }% [) K& U  v6 L" L2 D4 O/ P
  22.     // 设置编码,防止中文乱码
    * \6 D  N0 ]8 c, p$ ~: @$ ~+ @3 }3 B
  23.     mysqli_query($conn , "set names utf8");
    4 d" \1 D% @' P, S7 I
  24.     mysqli_select_db( $conn, 'temp' );
    5 J  ~6 S" \% y: o% x' Q
  25. 1 q8 ?/ x; n3 ~, u
  26.     # mysql 锁
    5 i4 G- [& n+ B9 {. K
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    2 A6 u) N7 @4 x0 C* n: u$ U
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 2 J9 J9 M0 V5 g# T3 b* h  g- e
  29.     $id = mysqli_result($rs, 0, 0);
    ( X% D. @" r$ m) E; {
  30.     if($id > 0) & a+ x% a5 O+ C9 p, y
  31.     { # f' n3 Z. F9 y2 Z- ~, X) v
  32.         --$id; - j9 y' e! @' L# H
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    : d9 X# ~4 U2 j$ u; p
  34.     }
    7 R$ f- ?2 k& Q2 \$ I
  35. ( B/ ]0 K$ |% \% Y7 L
  36.     # mysql 解锁
    $ q0 i5 m- C' F, K
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    ; p: X  C) J! ^. m$ }3 s
  38.     //查询解锁后的id值
    : {5 m& O  z7 Y) A! L
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    7 _2 |9 Z/ F$ c% |7 I6 O2 {: B6 m
  40.     // while($row = mysqli_fetch_assoc($res)). z; n. I9 [) n# [) _# B" Y+ f
  41.     // {
    . l& v1 s/ W* ]; x
  42.     //     $id = $row['id'];& X1 n. i, H0 H% j4 r" Z
  43.     // }* o' @. a; i  v
  44.     // echo $id;
复制代码

# o4 m! z- y1 n* a/ d& K
* }1 [- k, o6 e8 W
/ n9 q$ Z' P' P% ~
PHP文件锁示例:
  1. /*/ V/ u8 O1 Q. k1 A7 k0 _3 x8 M# P
  2.     模拟秒杀活动-- 商品100件8 v, l5 e% S% }9 w( ?- ~. K
  3.     CREATE TABLE ta0 p# ~2 n! t. V% s
  4.     (
    / O, [3 y! N$ R& S' Z5 [. V9 {
  5.         id int comment '模拟100件活动商品的数量'. g0 U4 z# A6 x
  6.     );0 F7 |0 D5 U8 n5 K
  7.     INSERT INTO ta VALUES(100);
    + b. p5 \; J3 s' P- x
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    ! k. l! |$ A) T# P  y2 V
  9.      */
    0 F, M: D7 n. O! Q( J5 f
  10.     4 Y2 [4 z5 _$ i
  11.     // 关闭错误报告5 `8 R( C3 ^; @% z- \
  12.      error_reporting(0); # L) Q9 @" i, x/ X% t; |  n- c9 j7 z  U
  13. - s" b, i2 d- J/ a
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址# D3 R+ l4 X5 t6 R( O$ g/ O
  15.     $dbuser = 'root';            // mysql用户名* [' ^4 j1 E9 L" I7 Z
  16.     $dbpass = 'root';          // mysql用户名密码; w' E0 K+ D2 n2 u1 N( B
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);) R* l4 y' o! d/ _) j
  18.     if(! $conn )
    ! m1 g3 A4 H( R+ c) x  H* v
  19.     {
    $ I8 v0 W; W- j1 T
  20.         die('连接失败: ' . mysqli_error($conn));
    * E+ |$ {2 H/ ~
  21.     }; `6 e* }7 w# I- q
  22.     // 设置编码,防止中文乱码
    1 Z7 [  \5 u5 m; V5 E4 G4 P7 H' _
  23.     mysqli_query($conn , "set names utf8");
    + s6 d3 ]- ?( H7 Z% z
  24.     mysqli_select_db( $conn, 'temp' );
    2 L2 c; G  T' J6 V( Q" Z# i, {
  25. 6 u/ z- K3 j% d5 U3 w- e
  26.     # php中的文件锁 6 _, }( j! S: d: [" x. C
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 & _5 ~/ l* T4 x4 ~$ K
  28.     flock($fp, LOCK_EX);// 排他锁
    ! s: \/ J' _% t  \: P/ S( Y  N

  29. : Z5 v' P& H4 O8 u4 _. Z
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); * K& \* p+ l# }0 g! p, h
  31.     while($row = mysqli_fetch_assoc($retval))
    ( G9 [/ E9 K3 x! \7 V; A
  32.     {
    3 k- g7 ?( s/ e; ?( q+ l
  33.         $id =  $row['id'];' q! |# f: c/ y$ R' G
  34.     }
    6 F% O; }3 h. H" q7 p. W
  35.     " b. H1 H  u; N6 o( {4 D
  36.     if($id > 0)
    0 m% `% t1 }3 Z  p- \# v
  37.     { / k5 x; |- v/ N9 Y! d8 g! ?
  38.         --$id; 1 Q, l! c5 g) j9 V+ k
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); / D' W! E# S' Z+ H
  40.     } / _1 t1 m9 N/ r% L/ r5 z. c
  41.     # php的文件锁,释放锁
    7 W% g, h2 m6 H& X6 Z$ V0 c
  42.     flock($fp, LOCK_UN);
    7 r2 \5 e+ `* }$ B3 N( H- i
  43.     fclose($fp);' x* e( y: S: A- Q8 ?" S2 P1 E

  44. 6 T! z: Y; p; h
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    6 y5 |+ s5 c( \6 t+ q, b  L
  46.     // while($row = mysqli_fetch_assoc($res))4 A' g5 ?# u" ]% x4 d8 S$ d  Q
  47.     // {1 s9 Y7 h4 a& s! p& X2 T' r
  48.     //     $id = $row['id'];
    7 ?% c6 C$ J/ B+ N2 ~
  49.     // }3 S7 e+ Y1 _) ]4 [9 F9 Z
  50.     // echo $id;
复制代码

1 F" ?  h/ q6 Q  `% `! R$ g  d, d  U: ~. w2 _+ F& E
抢券活动实例:
  1. public function envelopeSnatching(){$ b2 J- M% n  ~/ V, }5 [: f
  2.         $lingqu = $_POST['type'];
    3 J" W1 ?$ w6 R' h  i! @% P* t
  3.         $uid=session('u_id');//用户id( n2 a' M! @% O
  4.         if(!$uid){
    # V3 x1 N# j- s% o; m% F
  5.             $data['msg']='您没登录,请先登录!';6 K7 Q; V/ s) b6 Y- z6 J5 ?
  6.         }else if(date('Y-m-d') != '2017-12-12'){2 W' a; D2 z) Z0 h* r
  7.             $data['msg']='不在活动时间内!';
    - N9 y6 `! Q5 q3 b* M
  8.         }else{) I$ X3 g- f. v' ^
  9.             $hours=date('H');//当前小时数
    3 ~* y, Y8 |% v8 I8 i
  10.             if($hours > '09' || $hours > '17'){) g( w6 q- L& l- k

  11. ! f* y+ L# v2 \2 p( U1 ]
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的* B" v- `; Q* M# S6 {  Y
  13.                     if($lingqu == 1){
    ) R/ C1 Q, o" _% T, U
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    $ `& D7 K' J* r7 D
  15.                         if($hours > '09'){: J& i' R8 ?9 Q, D" h' l. S( V
  16.                             $num=mt_rand(25,28);//优惠券金额
    $ c9 {6 ?5 a; S
  17.                             $id=1;5 K' c3 {8 _8 b) u% C/ O
  18.                         }
    ) v+ ~" b0 P+ }9 F3 w
  19.                     }else if($lingqu == 2){: G& F# s0 I9 l7 _3 d8 _
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    * ~5 I+ }$ [7 }6 I: u) M' |
  21.                         if($hours > '17'){
    ! O9 p# X5 F4 Y# R" u5 y5 K
  22.                             $num=mt_rand(50,55);//优惠券金额, \* X( ?- H' f+ v$ g% ^9 \5 E! }6 x
  23.                             $id=2;6 `& Y: x- ~- P9 L' s
  24.                         }5 N) E/ E8 M% X9 C- i+ L
  25.                     }- m0 Q& ?( H  P: V* V
  26.                     if(!$id){  j) u+ E3 ~* ~' x" P
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    - u2 K% b2 S) e3 f' F* K
  28.                     }else{( D4 i0 V( ^# F' J/ `5 W' b
  29.                         if($is_lingqu){0 r( W7 H4 B6 j! y
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    * l; a* p2 C5 N  L2 g# H' {6 d& f
  31.                         }else{
    " D' X/ h0 N  p5 V8 P
  32.                             //锁表
    : A! s1 Q0 C8 D- d3 t% C' V
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');0 y) k& w* m/ k# U1 E0 Z: K+ {
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();! i- f7 @- j& k! Y' n5 {
  35.                             if($active > 0){
    7 S: D+ E6 q1 m2 C4 b: T( n3 m
  36.                                 //开启事务
    2 O" i, C: z6 ]7 [1 P
  37.                                 M()->execute('start transaction');, K; [( T; m1 {# f
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));% V- j. w& F9 ~8 L# G( d
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));! q8 H  j, K0 i
  40.                                 $members_preferential    =    M('members_preferential');4 d+ t! i; t' n7 c
  41.                                 //对应投资金额,
    + d& _+ @; ?* U5 V
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    / T# ~, ~2 v9 G  ^8 ]' C
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    0 L3 z, Z, W. N7 C9 m: s+ A
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间! D% `2 \, M; D  I! `
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券5 O' {- u$ U0 W' H# A7 D
  46.                                 if($save && $add && $add2){
    . V5 [: i# \0 h. c
  47.                                     //事务提交2 n9 E. e: x, c8 M/ _
  48.                                     M()->execute('commit');; `; T# x: J' u
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    5 X& x* N4 E  N) H$ _3 Q+ t
  50.                                 }else{+ M3 y5 S: M' E: C2 }4 o
  51.                                     //回滚
    $ Q2 `. b4 Q8 x! N% f! @. y. M% o
  52.                                     M()->execute('rollback');4 V8 e; p5 x% D/ _' k& N7 d
  53.                                     $data['msg']='未知错误!';. d" N, z' v- @1 ~# k
  54.                                 }( ^0 D( c. d/ J
  55.                             }else{& w9 p: L% C' X$ o( h8 A
  56.                                 $data['msg']='红包已领完,你来晚了!';! E( i( e0 i. }& t
  57.                             }
    : m# `6 p/ K; D# V
  58.                             M()->execute('UNLOCK TABLES');' ^+ Q" q1 f& Z
  59.                         }/ X) ~2 _& T& c! _; m2 N
  60.                     }
    - d  N8 @( f9 v  Z
  61.                 }else{' \! X2 @: K4 w! ^( M# S' T
  62.                     $data['msg']='非法操作!';, z0 l3 c$ F. X4 b+ x
  63.                 }
    5 W8 P2 m7 L0 v7 f2 Y0 b
  64.             }else{
    ' p$ |8 ]- Z& D( f3 J' N
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';# c% `! o9 c/ {8 |# P% u" v# Q
  66.             }
    # J1 r" W( X. @$ [! C( o) _
  67.         }
    . C0 J# y; K& n# I
  68.         exit(json_encode($data));) s4 Q4 y! h2 d! r. I( K4 L
  69.     }
复制代码

7 _5 A. x( o3 v4 f- A
& Y2 P8 }" Z2 H8 h& o: e1 ?
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-5-2 13:38 , Processed in 0.074474 second(s), 20 queries .

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