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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 8208|回复: 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://请求的脚本
复制代码

+ R8 i% f! w  X. ]4 j
Mysql中的锁语法:
, _5 q' R, V+ C7 k" o$ s# PLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】' }! w' ^  ]8 R+ N
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
! L; R3 Z# L6 k# ?; P9 T' tWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞7 d" z5 V% n7 k- I
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
+ w$ U. q3 D7 F# x0 d9 v文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
7 z! m$ U& k# N# [9 w4 v- i测试时,有个文件就行,叫什么名无所谓
总结:
6 @! f+ g2 B: ?- g" b- r5 W项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
& B# H0 l( r; }4 \8 E+ i1. 高并发下单时,减库存量时要加锁
3 j- g2 U. |! C2 z/ O2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*4 q$ D( S: j, w  C- ^, d% _+ w
  2.     模拟秒杀活动-- 商品100件3 g% R* D7 v+ i$ M
  3.     CREATE TABLE ta+ N1 c. P. B. i; G0 D( A2 o
  4.     (
    ! }) [* J$ }3 Q6 h) b" ^7 }
  5.         id int comment '模拟100件活动商品的数量'/ g6 s$ }, v+ N8 [8 o
  6.     );+ _. j5 Y8 K% n' c$ H
  7.     INSERT INTO ta VALUES(100);4 }" ?: I6 p4 H# t5 U% q" U
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    ' l4 E- _2 \' Q: Z
  9.      */ * A  |" A, B; J' X
  10.     ' R& P5 X" p+ ~/ ^* N8 s
  11.     // 关闭错误报告( G) P! D0 \1 v$ Y( g8 @/ `2 O' n
  12.      error_reporting(0); 4 Y7 \$ T1 a3 c/ p* J$ r5 X
  13. 9 f6 v5 F! K- A6 |9 u
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    & t  C; F$ Y# {: l( g
  15.     $dbuser = 'root';            // mysql用户名
    ! e0 H* m2 H' r8 ^
  16.     $dbpass = 'root';          // mysql用户名密码
    7 [' @0 h; h% d1 v" ?% E* e( ~; x
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    $ t% Q( Z: s4 j: g! M0 P
  18.     if(! $conn )
    * b) P4 S3 V' g8 ]( v& z( V
  19.     {: x9 z% o* Q" }2 u
  20.         die('连接失败: ' . mysqli_error($conn));0 `. s1 b6 D) H; e$ w9 t
  21.     }
    & R( ^3 A% W: k2 m- e$ b" c, J
  22.     // 设置编码,防止中文乱码
    $ F4 v1 j& [5 z  a' ?
  23.     mysqli_query($conn , "set names utf8");! s# m* Y' W6 N5 d/ L7 F
  24.     mysqli_select_db( $conn, 'temp' ); $ P6 T- E- D5 A# O7 ~  R$ m
  25. ( \* D( j7 S# c6 R
  26.     # mysql 锁
    ) f6 t; G  f) @% q5 P! F2 b! d
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    , T( U0 j( ]) x
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); ( u8 H. x- r2 g, w
  29.     $id = mysqli_result($rs, 0, 0);
    5 g1 s4 v6 N( n
  30.     if($id > 0) & w8 m7 c# m; C0 ]) D3 i* |. O& W
  31.     { * a$ V# [1 V& o& d
  32.         --$id; $ j) q. t8 i! \7 n2 u2 P6 d
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); " {) I0 N# e: A, g5 U" K5 `
  34.     }
    3 P& L( u9 g) s. I
  35. 3 w- M- b! j: h% A4 ~
  36.     # mysql 解锁
    5 P" f4 b8 ]; w* M
  37.     mysqli_query($conn , 'UNLOCK TABLES');- A$ N% U7 A6 C/ ~
  38.     //查询解锁后的id值7 o( f# F# u! I% X, f+ R! e7 t7 u
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    6 S( z3 a4 O8 M# b
  40.     // while($row = mysqli_fetch_assoc($res))( n- Y3 I( I8 l0 w  ?9 l& ?
  41.     // {0 j3 d4 P8 C; c/ j6 Y2 K
  42.     //     $id = $row['id'];
    * }. y% q+ G- R: f/ u/ N
  43.     // }, }7 `% _' @6 k: a, `
  44.     // echo $id;
复制代码

; U+ a. {, F  h2 z5 H* m
& V4 x0 a- u: ?1 k/ V$ b
! S* W8 B' _4 J4 i0 v4 _
PHP文件锁示例:
  1. /*
    ) Y8 g4 Z+ H1 i& \0 a2 k( X
  2.     模拟秒杀活动-- 商品100件
    ) J* H' P0 e2 x$ |
  3.     CREATE TABLE ta
    % ]3 r$ e0 C3 y# [; A* ^) C
  4.     (
    . {+ p* U& J; t) Y! u( Y) r
  5.         id int comment '模拟100件活动商品的数量'
    - k- r, w* I/ L# R3 v. i4 H
  6.     );- `0 [% i' u1 Q7 n7 d
  7.     INSERT INTO ta VALUES(100);
    $ _" R( s1 \3 D1 r3 S5 {& F
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    5 v5 t0 R( g0 r
  9.      */
    . C* p& N  y1 ?1 C5 u- P, Y5 b
  10.     * F8 b* G7 ]5 y7 ^4 Q& h* m9 i- i
  11.     // 关闭错误报告3 R- n1 `0 I  [/ i% `7 ]
  12.      error_reporting(0); $ v. F' F  T5 o, _% C! v3 d% R

  13. 4 r# ?" O9 G; m$ J" U
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址( L) L: l2 _2 d
  15.     $dbuser = 'root';            // mysql用户名* u) H2 j* o4 w" x: t2 n
  16.     $dbpass = 'root';          // mysql用户名密码& h) v5 C3 L) @2 Y# @& _2 J0 T$ e
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);+ y, Q7 e! r# y
  18.     if(! $conn )
    # Q- D+ \+ A5 z: ^4 f  h
  19.     {# {9 V) q8 t6 [" o0 E5 A8 J. O! v
  20.         die('连接失败: ' . mysqli_error($conn));
    . m- m6 T1 w4 ^5 r  n7 ]
  21.     }* q: U$ l. X4 ?, c
  22.     // 设置编码,防止中文乱码
    0 q/ J/ N3 N0 Y, Y! d$ F# k
  23.     mysqli_query($conn , "set names utf8");
    - n. r/ U0 X- b# E: V$ D; s
  24.     mysqli_select_db( $conn, 'temp' ); 0 ~: B8 E' E% a. L0 {
  25. & T4 y) z& I7 J5 R+ R" p
  26.     # php中的文件锁 8 \3 s4 r: Z7 P# Q. G, y  W, L
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 ' y3 O( z9 B. x, V
  28.     flock($fp, LOCK_EX);// 排他锁 - N4 k. M* H( d

  29. 9 W. w2 d. c! T
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    + f: a( r9 z3 {
  31.     while($row = mysqli_fetch_assoc($retval))
    9 ^& W) W- ^3 Z8 ]( P) V0 Q' Z! P
  32.     {1 }, Q1 T- U! l4 b" o, |2 y. @# d
  33.         $id =  $row['id'];" r7 e, r2 Y* D) J: p6 J. z' y1 Y
  34.     }' K+ j5 a$ h% R9 x8 H
  35.     & a# s$ ^' l9 v
  36.     if($id > 0)
    8 b6 a* L& E: P1 _- i
  37.     { * l, U& j" b# e" ?4 O1 a  }  M' t3 B( F
  38.         --$id; 5 i0 c/ r7 P6 B) ~4 `
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    - ~% g6 e5 j( i
  40.     } - h( G0 q0 M( u! m& f* E) p
  41.     # php的文件锁,释放锁 ' k3 ^% N" c# O6 M% B
  42.     flock($fp, LOCK_UN);
    / f; Z; I: q8 i  Q! S
  43.     fclose($fp);& l" D. [  E2 D* d
  44. 0 n8 k) V6 V: K- Z6 n
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');; l, K* e: @- u& I- ?. u
  46.     // while($row = mysqli_fetch_assoc($res))* h3 J" a2 r' y' J; q) y6 d% Y
  47.     // {
    0 q, D+ `* J$ p" W% K; d1 W: O; m
  48.     //     $id = $row['id'];5 U* {3 t5 t9 {% ]. I9 y
  49.     // }
    $ r! m: G' X' ]( J0 s
  50.     // echo $id;
复制代码
5 l+ C( t7 R( b& a
1 u( l' m$ h- v/ `
抢券活动实例:
  1. public function envelopeSnatching(){
    ) D, Z' H  v- e- ]0 K" }( F1 {
  2.         $lingqu = $_POST['type'];- T8 r7 H- [; x" H0 ^% y
  3.         $uid=session('u_id');//用户id
    ! ]1 a2 G# H+ _
  4.         if(!$uid){) _4 g, ?4 t. e1 _; {" e
  5.             $data['msg']='您没登录,请先登录!';
    8 {4 W0 c% X; f
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    . ]5 n7 ~1 J* b, [( |3 t6 i) M. T+ @
  7.             $data['msg']='不在活动时间内!';
    3 |% c3 @$ f: o7 I& H
  8.         }else{
    & [; P! ~" G, r. ]
  9.             $hours=date('H');//当前小时数9 ]; r9 C2 p8 M# }7 L* ]5 x
  10.             if($hours > '09' || $hours > '17'){
    1 i7 i" _6 X4 Z, _/ e
  11. " \4 G* G) t; Z% q
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的- ^$ @  ]/ L" ~2 I7 r) ^7 x
  13.                     if($lingqu == 1){
    . b) P1 _% Z8 i, l/ J, W
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
    4 l2 T  j9 \6 ]% N. L
  15.                         if($hours > '09'){* u. s  P, o4 d4 c3 X' r; e& }, Z
  16.                             $num=mt_rand(25,28);//优惠券金额
    ( m; }* F0 I9 z* W8 O/ B5 a/ b
  17.                             $id=1;3 p6 |+ \* t, Y* S0 f! T: N
  18.                         }
    , d' K7 V, k0 l, o6 @. ^0 F
  19.                     }else if($lingqu == 2){  x$ N% \! @& \4 m% k! S
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();5 n' T8 r. y, T2 t. i8 W3 p
  21.                         if($hours > '17'){
    0 `+ {( _: T! Q; V( I2 C0 Z* P
  22.                             $num=mt_rand(50,55);//优惠券金额
    " q  w' H' b8 T- k2 L3 T
  23.                             $id=2;( o/ ]2 {3 O- k0 @/ {
  24.                         }
    # J) E/ i4 B# C
  25.                     }4 }. T0 a" F1 q3 M
  26.                     if(!$id){
    ! ]+ }9 Q; \) {% Y) Q2 T7 }
  27.                         $data['msg']='时间还没到,晚点再来吧。';1 c- S* {3 m2 M$ n
  28.                     }else{
    * C5 Z4 r0 l7 u, v
  29.                         if($is_lingqu){. `1 k5 l% S; x3 K' l1 J5 o
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';* f4 r+ Z) X# ~. c: n
  31.                         }else{( O4 N. E; {- h' B
  32.                             //锁表) a8 T# f" D) [( G
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    1 N1 x0 F# E; N( G
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();. Y9 d7 p$ x$ i( |
  35.                             if($active > 0){
    0 D; q4 W8 r0 J
  36.                                 //开启事务* j  t. O9 E5 f6 i/ P- L( z. Y
  37.                                 M()->execute('start transaction');  q$ a1 i% i' a: h- n, O
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    , r5 l( {, X* G  n; o
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));( b$ U; \2 Y& d8 {- X
  40.                                 $members_preferential    =    M('members_preferential');
    ) x0 }6 U8 Z' [( k& r
  41.                                 //对应投资金额,
    " k* Q; d0 [' Z; K$ h
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));2 ?. b# ?- i* ^* X1 ~( S
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    3 ~/ r5 v" Q7 B, F$ R: M
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    1 h* {2 @6 F4 J2 [" i/ \
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    & N* k5 c' V9 Z3 K, @  a
  46.                                 if($save && $add && $add2){
    2 l  J1 b" c; Q' w/ n) h% z/ N# ]! ?
  47.                                     //事务提交; @- _% ?" b' L. P. M' ^# I
  48.                                     M()->execute('commit');
    1 H' I( u5 N/ l
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';) B, m& O" w& E% S
  50.                                 }else{
    6 B) \+ ~8 X- `7 f! w; N1 U
  51.                                     //回滚
    1 t  z/ {% J  o' M+ n" P
  52.                                     M()->execute('rollback');
    . i9 p9 s, q8 e* ?9 m. k: U
  53.                                     $data['msg']='未知错误!';+ ~/ o8 |8 ^7 P3 u- x  ~
  54.                                 }
    ( b, ?! p5 f4 e9 A, i# u7 r; p
  55.                             }else{
    ( \& Q7 H, @0 F+ ~% Y+ C! y
  56.                                 $data['msg']='红包已领完,你来晚了!';
    6 R$ H: Y) Q' ?. s6 t2 i
  57.                             }1 F# H7 }/ K. A& X6 Z2 G
  58.                             M()->execute('UNLOCK TABLES');
    ; t9 R3 a* T% ~$ Z% n4 Y
  59.                         }
    ( \* `' G' @9 S
  60.                     }1 H& L4 Q$ Q( n) E* Q# c7 X
  61.                 }else{- j2 M# H3 w! p6 n# S, i
  62.                     $data['msg']='非法操作!';0 r$ c! c1 Z" [' N: V  Q
  63.                 }: _! N% b/ u1 c$ f9 m2 Q* e
  64.             }else{% E) }2 _) X& x9 M6 Y9 Q/ r2 \4 ]7 r
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';3 y! M7 S3 X) j; u2 U. n
  66.             }% h- N/ ~. j2 P5 F6 E, ?
  67.         }1 b4 O, B  T% N+ I; X6 k. u* g
  68.         exit(json_encode($data));
      E& J7 a: @+ B
  69.     }
复制代码
7 _9 I/ ^5 a% X+ a6 }+ C) ?* R
* k- R- |+ N: x; b' V! _
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-1-30 13:03 , Processed in 0.048452 second(s), 19 queries .

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