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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 5725|回复: 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://请求的脚本
复制代码
4 F2 O: ]) v7 w4 H" m; o( r
Mysql中的锁语法:* x" H, }  {! ^: l0 {0 f  p
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
: o$ ?, v; r) k+ A9 }UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表8 F$ D9 @( ^3 v2 ]' d
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞4 U- z- J' P3 L5 V: X
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
* n. k- R9 r2 Q' y  N, _. b文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
8 z" s) N* P+ c. v* R测试时,有个文件就行,叫什么名无所谓
总结:9 y% n4 b1 Q! x  _0 q
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:0 {7 m2 e# [5 y; A- T: i
1. 高并发下单时,减库存量时要加锁
0 z) v( p. o! i/ [& ~# v$ O7 j2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    + w( F. t  s. E4 f  j; j+ z
  2.     模拟秒杀活动-- 商品100件& F# R. [- C+ p) O! o
  3.     CREATE TABLE ta" c3 t% B0 M0 x/ v4 z
  4.     (
    7 y* L; B6 m* q0 I8 k
  5.         id int comment '模拟100件活动商品的数量'7 ~+ x* O9 z  U0 ]$ E  a9 y* t
  6.     );) W8 [+ x! _- Z  q- M+ q
  7.     INSERT INTO ta VALUES(100);! p- u. \1 ?0 O
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件0 s$ k2 M2 j3 Q0 v, F* W$ m
  9.      */   s6 ]) {9 ~* V  s1 I2 o% v
  10.     / u* n9 x" z3 N4 a  n4 e6 t: ]
  11.     // 关闭错误报告2 B7 N$ b4 S' h* G9 [
  12.      error_reporting(0);
    , f' {) B3 }5 }# g: H- K
  13. 5 \- a. t) H+ t; x! E# C
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    # j5 y/ [/ O: l2 V* p+ a
  15.     $dbuser = 'root';            // mysql用户名
    0 f+ x" @4 f* F- \
  16.     $dbpass = 'root';          // mysql用户名密码; s! G* q; c# r! q% }
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);% w7 o/ e) i) V; u
  18.     if(! $conn )
    " M# P2 U/ C0 J! `% m0 P0 U+ R
  19.     {
    " }. p$ k2 I' J4 v) m( A( ~
  20.         die('连接失败: ' . mysqli_error($conn));
    2 }, c- K' _* s
  21.     }
    ! |, p0 P6 ]0 ~0 y) V  J6 X6 `; {
  22.     // 设置编码,防止中文乱码
    - Y0 q6 T( {5 O$ f. ?
  23.     mysqli_query($conn , "set names utf8");! f+ s$ f  U& f( L% v6 h6 {
  24.     mysqli_select_db( $conn, 'temp' ); 1 ^0 r3 a% O! O3 M, p
  25. - y1 ~+ F" E4 s! f" y0 C
  26.     # mysql 锁
    * m1 g% p, P: @* o8 `
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    5 F$ e6 E5 E# F) W1 T0 @
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); / i# u* @. j5 Z+ X( f! k6 p
  29.     $id = mysqli_result($rs, 0, 0);
    2 ~/ j. I( A: u
  30.     if($id > 0)
    ) W8 Y" _. Z) O) k8 ?
  31.     { : e5 M; |+ |. T
  32.         --$id; 2 h. U$ g! S/ P+ R
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    5 x1 n  f5 r; i, D- l
  34.     }
    . J. y" x8 r9 g7 A6 N
  35. * \3 P# ]3 Z7 K" w2 R7 B
  36.     # mysql 解锁
    % A1 L, B  j4 \( y' }# m1 Z& p
  37.     mysqli_query($conn , 'UNLOCK TABLES');7 z4 a3 q5 R! e# A6 u' T+ _
  38.     //查询解锁后的id值
    ! }2 o- \7 v$ c0 `
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');; u- _9 y' n8 ~
  40.     // while($row = mysqli_fetch_assoc($res))2 z  E" J( Q  c% B, r3 O# |
  41.     // {
    * l6 m6 b3 e1 h6 ^( X
  42.     //     $id = $row['id'];9 `1 \- P( g5 U8 {
  43.     // }- ?! {' o! z) z4 E4 i
  44.     // echo $id;
复制代码

9 L! T% A( Q5 x2 Q( m% d0 s, Z# x- ]6 k. [1 ~, I: q4 {
- |7 b% i+ _6 U1 X" m( X
PHP文件锁示例:
  1. /*/ T# g! m, b* x; ~, H) R
  2.     模拟秒杀活动-- 商品100件
    7 \6 _4 F: A) `
  3.     CREATE TABLE ta
    $ V% x" P/ _8 r3 D
  4.     (
    % F: R6 _$ F# W
  5.         id int comment '模拟100件活动商品的数量'9 l" p' T$ {+ _. I+ t
  6.     );0 j) N0 ~0 a# k3 d
  7.     INSERT INTO ta VALUES(100);
    4 q. h" x, h. \
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    " g) n0 v& u2 A+ O( `$ c8 Q  ]
  9.      */   g) x' N$ I- S1 _5 C
  10.    
    : @9 g8 O* o. d
  11.     // 关闭错误报告
    ! Z& W) [- Q4 o
  12.      error_reporting(0);
    + X; W) |. V) v$ b0 M; H% l4 o$ c
  13. - Q0 c0 ~& U  M5 o- @
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    0 w# Y, K7 i- S5 s- d
  15.     $dbuser = 'root';            // mysql用户名# {8 \. o0 Q" l, D
  16.     $dbpass = 'root';          // mysql用户名密码
    : n% }2 `$ S! Q  l
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);& _# q% u7 s- V' |$ ]& L
  18.     if(! $conn )& V" V* R  o4 _% m6 }: ^
  19.     {! b  h; _6 G5 s+ D$ K# u2 d
  20.         die('连接失败: ' . mysqli_error($conn));
      n+ O8 z5 r5 A: B/ A  Y
  21.     }9 U, y$ v- Q* u
  22.     // 设置编码,防止中文乱码0 _5 Q' }/ i9 Y1 L: [
  23.     mysqli_query($conn , "set names utf8");
    9 `5 y5 n7 L$ D$ ?
  24.     mysqli_select_db( $conn, 'temp' );
    * n# a" `0 Y; l' X
  25. 0 P' F7 K2 N( f" ?1 ^
  26.     # php中的文件锁
    9 n9 j$ z2 q+ a( z4 u4 P# {
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 $ G% W) O/ Z- z* q/ N- R
  28.     flock($fp, LOCK_EX);// 排他锁 5 y6 v6 J7 B& R2 ?  ~

  29. 5 C5 ?1 `3 O* _5 H
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); 9 y$ L7 l$ [$ E# O0 E  H
  31.     while($row = mysqli_fetch_assoc($retval))
    . E7 j/ P3 f$ ^+ p& ~0 Z
  32.     {
    ' ^8 R" o+ N5 n" ?
  33.         $id =  $row['id'];" j& j$ r1 c" r  o0 C
  34.     }
    8 u2 J. L" W. z8 F2 X" r
  35.     * ?  P- E: v- S$ }3 q
  36.     if($id > 0)
    , `  b, _7 p# n# y4 W1 G
  37.     {
    + ~" C8 ]" N& m, i) H& w
  38.         --$id;
    / h' ^5 Z2 w* g, F# x: [
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); 8 v$ W3 ?2 B. ^+ I5 }# q. {
  40.     }
    4 B. a" T- v6 c2 d
  41.     # php的文件锁,释放锁
    # w" x8 V& n% U) C- |8 P6 T; {) {4 [
  42.     flock($fp, LOCK_UN); 9 _& ]4 Y% h' J- P# x9 a
  43.     fclose($fp);/ p) \3 F! L/ g: A! g

  44. % U$ E3 {1 y% I6 L; w% z
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    + e' X9 r, ~7 x& S; o7 c
  46.     // while($row = mysqli_fetch_assoc($res))
    , Q/ R  E' S5 {/ ^, U9 w
  47.     // {
    5 P0 y% Q! {2 H+ `
  48.     //     $id = $row['id'];
      S$ v  y1 O, G3 }, R: D; ?
  49.     // }6 c" A$ t! f6 ^$ F
  50.     // echo $id;
复制代码

/ J" Z6 f" Z8 G  _* U! A7 m- Z8 t
抢券活动实例:
  1. public function envelopeSnatching(){
    4 i+ B5 y; W: J& I
  2.         $lingqu = $_POST['type'];+ b/ Z" b" E1 w7 j+ z
  3.         $uid=session('u_id');//用户id
    5 O. e/ r& |% T" W! q% P* f
  4.         if(!$uid){
    3 o5 h8 U% y9 |  j' v
  5.             $data['msg']='您没登录,请先登录!';
    $ f* Q/ c- L0 b2 @9 ?8 u- A  G0 ^
  6.         }else if(date('Y-m-d') != '2017-12-12'){" J: a/ x1 c2 @* s! A
  7.             $data['msg']='不在活动时间内!';! T/ A6 d: {6 F
  8.         }else{; f4 D/ ?4 t" _0 C
  9.             $hours=date('H');//当前小时数
    9 {2 K; X8 I( B4 G9 M1 {4 m
  10.             if($hours > '09' || $hours > '17'){8 ?$ h! c( Z8 B* U; ^

  11. / G$ z( e# v' {4 j7 ^* l, K
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的2 u7 W1 ?+ S" d- x% u8 L
  13.                     if($lingqu == 1){
    # e7 I5 W5 y( s# a& S! k
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过( |9 A4 Z+ F, q+ z. \/ e" x% `, @
  15.                         if($hours > '09'){6 O7 u2 y' H* l3 C# A- T( Y; J' m
  16.                             $num=mt_rand(25,28);//优惠券金额
    0 ^# }. a/ N" x2 y5 z
  17.                             $id=1;. Z+ Q' n$ ]7 L$ l
  18.                         }
    5 L* U$ f& I. g/ Q7 G9 U& ]+ y+ a$ m
  19.                     }else if($lingqu == 2){8 ~/ D1 x6 B5 w  t. p% l
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    9 W9 E) F' k" ^+ U* l7 j
  21.                         if($hours > '17'){! `3 ~4 y3 Y4 L( h- |2 U) L
  22.                             $num=mt_rand(50,55);//优惠券金额$ {- D2 V7 I* N3 v
  23.                             $id=2;, p9 O% y: i& K- Y
  24.                         }6 Y6 v9 U1 T; v% N: B+ @0 L
  25.                     }
    " _) ^  }, [  m; t) |
  26.                     if(!$id){
    / U, _  E, c7 d: c2 N
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    5 V7 D) J3 ]4 s  q+ D% c
  28.                     }else{
    . G% G8 C" M9 K! Y! z1 S
  29.                         if($is_lingqu){1 m2 E- B" {& ~8 u0 e8 ?4 M2 y0 j
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';
    6 U# e1 u# o  c& j" X) H
  31.                         }else{5 z9 M. `- O1 k6 c) ?. b7 J
  32.                             //锁表) s' U7 a- X. A, p
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');1 k% a3 F/ ^* }* D
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    + q& C, l! T& Q6 g
  35.                             if($active > 0){
    3 I% [# G! V: z
  36.                                 //开启事务/ a/ |+ O% D$ W  P4 l
  37.                                 M()->execute('start transaction');3 u" {. g8 g3 S. X+ y
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));: }) P# v1 h/ W& [. t+ K
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));% B- n2 {6 z5 `* `8 y' k
  40.                                 $members_preferential    =    M('members_preferential');
    : w; ^' S( C; m+ j% L0 B
  41.                                 //对应投资金额,, D! ?- r: z( _4 K9 l
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));; c1 N5 [0 u% o$ o9 t% ?# D3 b$ R
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    0 J4 n" m1 E, B" r8 c. B
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    . j3 H9 H% E8 ]5 I
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券% u& Z/ r0 {; t, \# ~( B- G3 n
  46.                                 if($save && $add && $add2){
    3 K5 m4 ]& j4 o  [7 ?
  47.                                     //事务提交
    8 L4 ^& p7 B2 e2 d8 Q
  48.                                     M()->execute('commit');
    2 ?$ e3 `5 W# q4 u+ o! ?
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';
    6 `: w  a% o+ X4 e3 a' u. R: W: q6 e" ^
  50.                                 }else{* V+ D2 Z* Q- w& ~4 g) p
  51.                                     //回滚/ x5 q! r9 @" s+ K. |$ q8 w
  52.                                     M()->execute('rollback');
    * `0 d* q- w! b7 Z' e
  53.                                     $data['msg']='未知错误!';' G1 G" `3 F, ~$ Q) n
  54.                                 }
    % ?/ [" c- T9 n' ?8 \& w& A% E# W0 u! G
  55.                             }else{' J. t' a0 D; B( s8 p8 @
  56.                                 $data['msg']='红包已领完,你来晚了!';: D; b$ _) K9 r
  57.                             }; [/ |& K5 r& F2 [- S" z- d8 k
  58.                             M()->execute('UNLOCK TABLES');) L& w% `0 F: P3 e3 n' c4 |
  59.                         }, l( Q, F: Q5 i0 g: j
  60.                     }9 `- j: P! v) q) O: ]5 d
  61.                 }else{" L/ {  A' h/ Z  f  w3 @+ v
  62.                     $data['msg']='非法操作!';' b9 G7 H1 I7 a. e! x/ f
  63.                 }
    2 r$ y" A. q9 m  S3 _0 X/ e8 q3 K6 I
  64.             }else{
    ) D/ S8 J  I* b6 e! r
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    . ]0 a/ `8 H" ^: K3 [% E# u9 E) X
  66.             }2 F4 a1 e$ [. z1 P
  67.         }
    + ^& p( L2 O/ q8 g; p& t
  68.         exit(json_encode($data));+ y/ C3 O) y9 [* q1 q/ y1 o/ f8 q
  69.     }
复制代码
" F/ h0 l" t- v

/ P% R. z5 c) v6 F) y; f+ ~
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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