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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

, C, h) s! [- l1 P) g
Mysql中的锁语法:
5 j( ^% t( d3 p: JLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
. ]% ^  K0 n4 X# _& ]) k, bUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表& y7 K" _! a" Z; d+ y
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
, j. K% Y$ t0 [/ I8 R. O注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :' M& }% o" Z: A0 U4 N4 s
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
  U% P6 E% ]4 T1 g" m" B测试时,有个文件就行,叫什么名无所谓
总结:
& w) p0 p0 D2 d$ a3 O% B; ?2 b) t项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
# H* o: w6 l$ `% `1. 高并发下单时,减库存量时要加锁- D. o, M9 m3 \7 g
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    , n3 W" a: |$ ~% ^3 Z, x8 K& i
  2.     模拟秒杀活动-- 商品100件# D! T$ f. e4 m" C7 c! i( `
  3.     CREATE TABLE ta& t/ I" g: J! V+ L. ]
  4.     (
    : c  V4 P: [+ U
  5.         id int comment '模拟100件活动商品的数量'
    # V/ K% S- N: W
  6.     );
      P) k5 {0 V  m
  7.     INSERT INTO ta VALUES(100);2 v  ~+ z0 L( A& S; o/ Y% o) }
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    ) ^. L9 X% B5 ~. j- K
  9.      */ 6 a. {9 Z: O; b! A( k8 z
  10.     * W4 A& }" q' y
  11.     // 关闭错误报告. R9 ?: j8 f5 t
  12.      error_reporting(0);
    % b& y4 J3 B  P$ G& v0 V/ O

  13. + X0 T8 C" t! [+ h6 `5 R: Z+ S
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址' _" ]- h' f- r( W. W1 ?
  15.     $dbuser = 'root';            // mysql用户名" H8 s1 M3 B0 ^5 {
  16.     $dbpass = 'root';          // mysql用户名密码% d" T) M, V+ J" n
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    % i7 l  U9 Y# Y, {% k6 X, E
  18.     if(! $conn )
    / V6 G8 b" X  Y/ g
  19.     {
    - l( i! {- r2 Z1 V+ [$ g
  20.         die('连接失败: ' . mysqli_error($conn));
    . m) S0 I( B7 N: ~9 f
  21.     }7 i2 L2 \' {- E. Z2 H/ r( Z
  22.     // 设置编码,防止中文乱码# @" n. V" L- @2 U- \( O
  23.     mysqli_query($conn , "set names utf8");9 a2 _. R9 z. }7 y7 o
  24.     mysqli_select_db( $conn, 'temp' ); 2 l1 l) j# J' y+ P) L, e' e
  25. " l" S) K! x6 r5 T7 b* {/ b
  26.     # mysql 锁
    9 ~3 W6 t8 U6 W8 h8 s7 E
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    ) B/ }* O5 c1 o+ D+ h/ y
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a');
    6 M5 O; d  y7 B6 M1 w( j7 N
  29.     $id = mysqli_result($rs, 0, 0);
    3 ]  w; s/ k* v2 I2 X, k# ~
  30.     if($id > 0)
    0 O, {) V# Z- D1 X
  31.     { 7 Z; O6 W& s% `3 x* c- }, |7 n
  32.         --$id; ( Q( H2 [& t: u# J
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    4 s; M8 q2 ~# L% W2 C+ `
  34.     } & I# q4 b" L1 `

  35. 8 U0 y9 }, W& B3 |
  36.     # mysql 解锁 . y) q6 n  O) C# b8 m  H% `2 M
  37.     mysqli_query($conn , 'UNLOCK TABLES');; Z  g# S1 C/ ?2 |
  38.     //查询解锁后的id值, D" T6 D1 [" v' w0 e) K! m5 i6 E
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    8 u; J# v, |( x; `" w
  40.     // while($row = mysqli_fetch_assoc($res))5 f2 g; Y* p! T  L  e6 N" E
  41.     // {
    $ h* ]2 F5 Q; Y
  42.     //     $id = $row['id'];
    # m" {" a; y) a  N* W9 \
  43.     // }
    6 Q3 k9 ]( L9 O; v5 X. k/ {
  44.     // echo $id;
复制代码
8 a% P3 g1 z5 ~9 w

3 s, s2 p& ], t7 S" K" l" P* }! x

0 }( s9 P6 U9 d. l
PHP文件锁示例:
  1. /*5 z- H9 w5 Z& n
  2.     模拟秒杀活动-- 商品100件
    & V$ A6 T  I* R/ m( L7 V/ l4 A+ l
  3.     CREATE TABLE ta5 _/ z8 O4 c# C% d3 S5 N+ t2 m
  4.     (
    * m8 R& d, x  A! }) L  n* q6 y7 y
  5.         id int comment '模拟100件活动商品的数量'
    * Z9 q+ l) ?3 w# T; U+ \" i% O% W
  6.     );- r2 A( ^; ?! k
  7.     INSERT INTO ta VALUES(100);
    % Z7 D  c( l2 w( i0 f+ t% [. k
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    & n: ?% F. h, ?. H6 R
  9.      */
    : @/ N: i6 d# N, A; C3 }
  10.     ' m4 t) ], J4 \6 A. r# Z
  11.     // 关闭错误报告
    + k7 q- j1 t0 V# O+ I; ?
  12.      error_reporting(0); - K$ K! @6 }& V1 z

  13. ; i% C$ X" f: d9 h+ P
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址$ K$ G0 t4 K+ ]
  15.     $dbuser = 'root';            // mysql用户名
    $ x; `4 D6 Q# u( }9 e6 [$ l6 G
  16.     $dbpass = 'root';          // mysql用户名密码
    / k8 u- Y# e, A% a3 x
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    : i, J, F1 }6 S- n1 R3 Y
  18.     if(! $conn )
      t, F: p- x$ d# c; p' [- X
  19.     {
    8 w( S' \4 M$ G% Z$ N% L- p
  20.         die('连接失败: ' . mysqli_error($conn));
    7 W  a! x  c6 R1 g5 J! [$ h; W' A
  21.     }+ i' y- |# ]; H( ~8 [9 F- @
  22.     // 设置编码,防止中文乱码
    / q: h3 y, t8 _# E, t# p
  23.     mysqli_query($conn , "set names utf8");
    + T' P. q2 f" b+ @+ g
  24.     mysqli_select_db( $conn, 'temp' );
    ' T2 u. p1 m7 [2 J4 q& `
  25. 6 W) \) b. s  [$ {8 ]5 [" B
  26.     # php中的文件锁 7 Y0 Z# K! _) I
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    + e6 v5 G" Q) e
  28.     flock($fp, LOCK_EX);// 排他锁
    - B0 s7 W% L3 x0 H
  29. " @0 k) y+ [$ v3 {* M* l
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    6 e7 t1 C6 i) _  l
  31.     while($row = mysqli_fetch_assoc($retval))
    * e) \* ]) l5 x' ?
  32.     {) n5 }! S  V! N
  33.         $id =  $row['id'];; W: N( c# D: z8 q1 M
  34.     }
    . d6 T6 N% |7 I: d7 ~1 W' x6 o6 a7 R
  35.     ( f' o/ V% b( g7 ]
  36.     if($id > 0)
    - N( w" }9 Y- y+ y" a0 d
  37.     {
      B; a6 E$ q: q; d& `
  38.         --$id;
    # X8 ?. P( w! u" _. d
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); * J1 \2 P* x( }! @0 s
  40.     } % ^, K( S5 s8 y& P
  41.     # php的文件锁,释放锁
    * k. P1 y) T) ^1 W* e8 H
  42.     flock($fp, LOCK_UN);
    + o; H0 f6 ^( ^5 ~# `
  43.     fclose($fp);
    8 ~* G( a7 l; E

  44. * Y" t6 U* I! E* n6 [* C
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');  M; _0 R5 L$ k) D
  46.     // while($row = mysqli_fetch_assoc($res)): `6 G: @7 P- h
  47.     // {) \; B" F9 h$ y$ x: t, g
  48.     //     $id = $row['id'];2 M: r) M. l# r4 R
  49.     // }
    , Z; F8 X5 H$ N3 J6 o% X$ I
  50.     // echo $id;
复制代码

) o+ Z2 s( w* {3 ~
5 Z( E  C( K" _% ?
抢券活动实例:
  1. public function envelopeSnatching(){  _. `: L! Q7 |+ j
  2.         $lingqu = $_POST['type'];
    6 a/ f0 R) r$ ^1 N
  3.         $uid=session('u_id');//用户id1 s5 u) `+ t4 r8 u" x: Q( h
  4.         if(!$uid){
    # S) i. n5 D& k( h' O7 [
  5.             $data['msg']='您没登录,请先登录!';5 a+ Y1 ~! ]3 j
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    ( a& x8 C, d6 e: `
  7.             $data['msg']='不在活动时间内!';3 T% t: p! s* Y$ g
  8.         }else{
    - O" o8 u- [5 q2 ~0 z3 t8 x: w: p  N
  9.             $hours=date('H');//当前小时数
    - l# ]% ^- s% [' J) V1 L3 N
  10.             if($hours > '09' || $hours > '17'){
    * ~5 Z. n* X, ]

  11. : i& t) S) Q& M% \+ z) v
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的, n& g5 M) v# h9 T9 R7 S0 S, q2 u
  13.                     if($lingqu == 1){+ ]4 L+ }" U, N
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过' B  S: y! E( l9 t* o5 r" }. ?
  15.                         if($hours > '09'){7 j) V/ K( y% K" O( W. |
  16.                             $num=mt_rand(25,28);//优惠券金额
    ! _  n1 @% }! v* r7 q6 B
  17.                             $id=1;
    8 I8 R4 r- ^" e% v# J6 P" n
  18.                         }
    & @# [/ _7 @0 ~
  19.                     }else if($lingqu == 2){
    + _; F: [' ]5 e0 E5 M% G
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    6 ]0 d+ B* e) B; m
  21.                         if($hours > '17'){
    ! x9 K, G5 J! k& J
  22.                             $num=mt_rand(50,55);//优惠券金额! E2 y0 H7 R! B+ Z9 Z" p1 g
  23.                             $id=2;% m$ D4 E! k+ \) e! z/ p
  24.                         }
    $ ?2 T+ x! V! |$ c
  25.                     }
    % j  j9 ^( f; O; B: l" {7 u6 P
  26.                     if(!$id){
    ' t% I* Z: P' v7 e* Q7 p
  27.                         $data['msg']='时间还没到,晚点再来吧。';6 j- L8 |: O8 M! S
  28.                     }else{
    - E1 _) q! g0 S( N
  29.                         if($is_lingqu){& D' k( r4 S& [
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    . X" G; r) p1 Y* X
  31.                         }else{+ s/ K4 L% |! o. l6 {
  32.                             //锁表& K3 ]8 T4 V- ?. L1 k7 e- T
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    1 }7 W' P- A+ Y; d' G
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();7 p! @: u4 E4 u4 a% Z# e
  35.                             if($active > 0){; K! c. i# C. \, D' j& i1 |+ _; w
  36.                                 //开启事务
    1 }1 n  N/ J5 H  F( m0 @4 W$ j
  37.                                 M()->execute('start transaction');6 L* L$ |3 s' W# j5 s- \# ?# }
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));2 T; X% P$ Q; U/ c& Z
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));/ U8 Z+ f% U6 G0 q1 P
  40.                                 $members_preferential    =    M('members_preferential');7 f3 p. R( {4 W* _
  41.                                 //对应投资金额,: e3 ~5 X1 Q8 n: C# h
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));7 ~+ \" J" \1 b
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');" J/ V: U% `+ v. C8 }7 P" ?% B
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    $ i0 a7 J( D7 t% R9 ~( E& q
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券( J: x$ L2 ]" F) a, \1 [+ R
  46.                                 if($save && $add && $add2){
    4 V" x) ^; W2 g9 G$ B0 b
  47.                                     //事务提交6 Q# m; T1 ~( [6 W. D7 ]  e  a
  48.                                     M()->execute('commit');3 a6 B1 i9 |' M
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    9 G  w7 V* ~, v* E
  50.                                 }else{" M9 Q0 E+ c1 P! o7 x4 s
  51.                                     //回滚& ?% r3 t0 U8 s: K4 N. a" |" y# T
  52.                                     M()->execute('rollback');6 N3 l- S, u; c( [
  53.                                     $data['msg']='未知错误!';
    4 p% X( H) t5 ?( C
  54.                                 }
    8 g4 {- |! U/ J6 V( }& i
  55.                             }else{
    ! Q/ o& Z5 b$ g
  56.                                 $data['msg']='红包已领完,你来晚了!';
    " A5 A$ z2 u) k$ R4 u  g
  57.                             }
    # g' v2 G6 ?' \4 {, e2 m* ^' H
  58.                             M()->execute('UNLOCK TABLES');5 D) G9 V9 a( {( X- }0 W
  59.                         }
    ! w' N2 M' c7 c
  60.                     }
    ( u/ ]7 Q# V, a! z
  61.                 }else{
    " W" T+ k0 M+ O1 ~- Q/ K
  62.                     $data['msg']='非法操作!';
    ; f; _" M$ a1 O7 w2 o. d
  63.                 }- K' I) `7 B+ c0 Z4 G- @, v' c2 h
  64.             }else{
    7 T4 ~7 F1 a; {3 c. H
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    ) c2 m" `. F( r* O. f6 U- B) l
  66.             }: w6 r( [6 F7 W& s0 u1 D, i% z
  67.         }
    # N3 g( k( ?0 `6 @0 C: i
  68.         exit(json_encode($data));
    ; x1 J% X$ M! \' F/ ^. E
  69.     }
复制代码
" m! t, a$ z0 D/ H$ G; e4 w

- W8 ^% x6 U0 a
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-12-22 11:10 , Processed in 0.113001 second(s), 19 queries .

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