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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

! z  E) A& R: c# ^/ E
Mysql中的锁语法:
6 F' ]% x6 d. {- rLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】8 R* W* Q+ @9 w' r" y+ |2 L
UNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
0 E0 a2 A( a' Q$ `8 X3 c/ \Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
) w4 Q7 Q9 A, x0 o4 P注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :
" c5 F% e( t# B5 i& r- s' n文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
( @1 y/ [9 X0 t+ C& H, J测试时,有个文件就行,叫什么名无所谓
总结:
+ F" I2 ~$ W. N  K7 y/ A7 N( |项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:. F7 c4 y8 g0 g7 ^6 M8 l4 ]' n
1. 高并发下单时,减库存量时要加锁
  y9 B+ F/ m- S  N7 {: x$ z2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*$ b$ A" r9 Z, s2 O
  2.     模拟秒杀活动-- 商品100件
      K; h7 f- _" d+ f; M& C
  3.     CREATE TABLE ta
    - z4 V. t( e: W6 U. @( G0 O1 R
  4.     (
    . d, Q& h0 n4 r, C8 t
  5.         id int comment '模拟100件活动商品的数量'
    6 w' s9 d- a5 m. r$ L& Y6 ~
  6.     );
    % I( Q1 r; p9 i4 N# Z! d. d
  7.     INSERT INTO ta VALUES(100);
    + }/ l7 k1 q; c9 e& `1 j
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    1 g7 h* ~+ }/ p# j* O+ @
  9.      */ . b( E( x* ~) U5 Z% b0 m: M
  10.     9 k* @& F1 b" r+ Q& j
  11.     // 关闭错误报告
    $ l) G/ c9 O% d9 |9 R/ H1 l
  12.      error_reporting(0);
    8 L7 d% I/ E' A8 H" ]
  13. ; P) I/ H0 m) w4 ?/ S! y/ @' e: `
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址; o4 ]7 g' G) F5 d9 d& F
  15.     $dbuser = 'root';            // mysql用户名
    + c( x4 R8 P3 ]4 i, {5 \
  16.     $dbpass = 'root';          // mysql用户名密码
    1 `6 N5 t& A# b
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);' ~2 e3 L9 i' V; {1 m
  18.     if(! $conn )
      `' E' g# |& X; F) H* a9 w$ S, U1 [5 {
  19.     {" `8 |9 \3 b" K0 y5 a
  20.         die('连接失败: ' . mysqli_error($conn));
    / u6 m' c+ o* N* x
  21.     }$ [! M, u$ _) L8 \3 T
  22.     // 设置编码,防止中文乱码
    % N" k2 c# L0 k& A8 E
  23.     mysqli_query($conn , "set names utf8");
    ( V- X1 I0 \4 M
  24.     mysqli_select_db( $conn, 'temp' ); 8 P8 `3 x1 f$ w, x; e  D: v7 u& p4 S
  25. ! R( z4 a) h4 V& h+ s2 z
  26.     # mysql 锁
    - A# \& ~' o( W; R3 b; Y9 l. h7 A5 `
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    % D& I) L* P) D- a. [1 W- r' c( Y; s
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); $ m/ b6 g  C9 N; K. x" }' V7 O. J
  29.     $id = mysqli_result($rs, 0, 0);
    ' ~/ O, o4 x  [! A5 S  S8 ?
  30.     if($id > 0) / {/ [* I" s: O
  31.     {
    ( V: I' j) q2 n: C
  32.         --$id; 6 T+ J$ \# p3 Y0 n) P; y, g
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); 8 q+ [2 S2 U( E" _3 M
  34.     } ! \  a( ^, t: Y$ q

  35. - b. H8 ~" b; N0 Z% y
  36.     # mysql 解锁
    / X5 ^& A1 f4 j' n' W
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    - B! k  B6 U  C. W3 E
  38.     //查询解锁后的id值
    0 m7 ?6 f. A1 S0 w
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');: \- d2 a7 q; S  A8 F2 Q6 f
  40.     // while($row = mysqli_fetch_assoc($res))
    ; ]# y( f  K+ u) V: w9 k
  41.     // {6 A3 B- q# t6 {# `" a0 J& D
  42.     //     $id = $row['id'];
    ( M: g. ]! K# T% F$ j: P
  43.     // }
    : _0 s6 ^) K8 w5 z! N, S9 Q- u
  44.     // echo $id;
复制代码

2 m8 H% ]& P, Z( n
. M, D- S; }8 }5 X
0 _1 W3 A/ u" ^6 a# H
PHP文件锁示例:
  1. /*
    ; T: T! ^2 N6 s# o8 C
  2.     模拟秒杀活动-- 商品100件/ S1 e& X7 j" x9 }
  3.     CREATE TABLE ta/ j, y. q# P. O
  4.     (9 h/ T$ ^3 A' W: _, N
  5.         id int comment '模拟100件活动商品的数量'
    % y8 u5 f( ]4 _; }: B, @2 |
  6.     );* o! c. G4 G0 C* Z0 p
  7.     INSERT INTO ta VALUES(100);
    9 T' n3 q3 Z9 J6 b4 h! f) ^) K
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件: F: i5 ?0 }. B0 h& C
  9.      */ 9 m! Z" h5 ]! \- w( `. q0 }: h
  10.    
    4 i9 l* E3 X. `5 {- \
  11.     // 关闭错误报告7 ^& w( r% q4 j$ R0 j* [
  12.      error_reporting(0); , i9 e6 X% s: o
  13. * X. I0 Q6 v7 l9 L0 C! G; H
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址( t) [7 q" ^- U
  15.     $dbuser = 'root';            // mysql用户名% L/ z3 x; Q1 |" C
  16.     $dbpass = 'root';          // mysql用户名密码0 G/ G7 L6 P* g8 V
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);5 r' Y# J* s- w7 g8 M
  18.     if(! $conn )
    ( z7 d% e" U) M, N4 [
  19.     {' K; G) `- V7 S3 u& B
  20.         die('连接失败: ' . mysqli_error($conn));+ I7 N* m/ j1 o8 ^
  21.     }
    # U0 a8 C2 n& m
  22.     // 设置编码,防止中文乱码
    " |5 G8 e1 A! L* z- d9 [: w/ S
  23.     mysqli_query($conn , "set names utf8");) q- |. L& n; N/ P: N
  24.     mysqli_select_db( $conn, 'temp' );
    7 k, d+ N2 ?) i8 @' k

  25. 6 Q; V% G# h! u% g% `: L& W
  26.     # php中的文件锁 ( ?- a, u( g+ q2 J
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 + o3 [$ \/ X) n
  28.     flock($fp, LOCK_EX);// 排他锁
    6 j* a! d8 t' Z1 {
  29. * a1 T& k* {. }2 D; G0 z
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta'); 4 t. C$ m8 G  J$ {
  31.     while($row = mysqli_fetch_assoc($retval))
    3 q: }$ B7 Y9 V1 U$ ]  u  y
  32.     {# t6 t" N3 V; F& l: F' `
  33.         $id =  $row['id'];
    " @3 f' c+ H6 P3 ?8 s; B- V3 F& G, K' O
  34.     }: @8 i, U; c/ z$ q
  35.     ' l% ^- C5 d1 ^5 S1 s& z
  36.     if($id > 0)
    0 F8 M+ [; W1 T/ v7 p: G
  37.     { 8 d, z% s; d6 s* D4 Q
  38.         --$id;
    3 `: |0 D! D# B6 `! S/ W
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id);
    $ a( f" b# o5 f% C+ \
  40.     }
    # O" B1 L# ?( D$ Z+ V; W4 }% ?( i
  41.     # php的文件锁,释放锁
    ; `$ |7 ^& U$ `3 h, M' k
  42.     flock($fp, LOCK_UN);
    , W. j; y9 _3 z, Q2 I* [/ @1 D$ F0 [
  43.     fclose($fp);0 `4 j# x! Q# O( h# s
  44. # d! o: l; t0 R6 g) _
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');5 n  e9 Z# K- c7 p* m
  46.     // while($row = mysqli_fetch_assoc($res))- d# K7 z* m2 ?# t$ V
  47.     // {* I7 z" u3 W' n1 h& J# i0 C
  48.     //     $id = $row['id'];+ K$ C$ t' J" d5 i8 j6 v
  49.     // }
    ! h5 C% [" r" U- M3 g4 g
  50.     // echo $id;
复制代码
- H* p  Y( Z6 |
! z- I, B4 f& |. e/ e: o
抢券活动实例:
  1. public function envelopeSnatching(){2 Z! P/ L4 A0 \; z3 ?4 h
  2.         $lingqu = $_POST['type'];
    9 J5 ~0 x0 g$ J' h- o- g
  3.         $uid=session('u_id');//用户id8 H. h1 N! ]9 Y; F% q- Z( o0 H9 Y
  4.         if(!$uid){- N; q, R: W% A0 f$ S
  5.             $data['msg']='您没登录,请先登录!';
    ) O* p$ m& W: |9 c, q" k# J
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    % o3 Q4 h$ l$ B( C
  7.             $data['msg']='不在活动时间内!';
    7 r2 J  B1 T  k  ~
  8.         }else{
    ; m8 N2 v, w3 G5 o2 E3 H
  9.             $hours=date('H');//当前小时数4 J, ^$ Q2 z' A$ Q2 N) @9 S) ~- B4 ?, Z
  10.             if($hours > '09' || $hours > '17'){
    % I6 Y1 n* B& @& r' Z  P' D8 f

  11. 2 J! v' d" u+ K6 F* I* }# {
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的, {5 o5 g) w0 z7 c- G( m5 l% _
  13.                     if($lingqu == 1){. D# g; c+ @3 f. o" X7 Q
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过9 u. I; L0 Y+ V2 o1 b
  15.                         if($hours > '09'){3 w8 O3 @0 U8 f/ ^4 j$ h
  16.                             $num=mt_rand(25,28);//优惠券金额
    9 K; e; M. C- g: w9 F; L/ I
  17.                             $id=1;
    9 b% t4 D- I" Y8 N* e$ |# p% N6 V
  18.                         }3 E4 _% m! ?1 M9 S+ d# u
  19.                     }else if($lingqu == 2){
    4 K( g0 Q3 c% S. p
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();7 q9 ]/ y6 `1 L! Z
  21.                         if($hours > '17'){' e7 m) Y/ n" p
  22.                             $num=mt_rand(50,55);//优惠券金额
    , ?2 l( Y* _3 l; J6 Q
  23.                             $id=2;
    3 l. C8 i: B' }+ J9 K
  24.                         }
    ( n) P3 h  G- C9 b3 z3 q
  25.                     }
    * v7 R5 |: S5 g
  26.                     if(!$id){! W. u) Y  p# c( Q
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    ) U9 R) |( ?) y0 r
  28.                     }else{$ K- ?: C7 k9 C9 r; O
  29.                         if($is_lingqu){
    , w7 a$ w' P! s0 k
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';* P$ H( I" I% K
  31.                         }else{( ~3 ?" c' K: d/ k, [
  32.                             //锁表
    $ K- P: y4 \, G( d7 T3 V( H
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');; S$ V. f, K5 h* y: u/ {5 d+ Q4 H
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();# ~3 s. M/ {1 `9 I+ c  v" h
  35.                             if($active > 0){+ _% g8 u1 w# E" w1 B/ w2 J& }6 ?7 P
  36.                                 //开启事务- C4 p8 X; i3 r. L
  37.                                 M()->execute('start transaction');5 e5 f" }# x. A
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));( Y% [: q+ p. `6 s/ e- A/ n
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));6 d* _8 j% \7 r/ P* [. k0 f$ k
  40.                                 $members_preferential    =    M('members_preferential');$ _1 K. M6 c4 B7 W& g$ O
  41.                                 //对应投资金额," M7 @$ [6 B. ]! r7 {8 Y/ _! g
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    : }9 \+ f, I/ y; ?5 h* J( C
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');' Q* T& g2 B, B% C+ T
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    ! f7 a7 V. A' u& m- o' ?6 u
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    * e% U; w2 Y) \* m+ [0 y; z8 s& ]9 d
  46.                                 if($save && $add && $add2){1 S  B& X5 f' k5 E( F% v1 i8 L
  47.                                     //事务提交( h  G) b" S, Z9 ?  _" H$ O# E
  48.                                     M()->execute('commit');
    # z$ D+ R+ ?( b- z! U$ Q& o
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';  x& p2 {# i# ?+ T' B" Z
  50.                                 }else{
    * F8 ~4 v+ A# E) ]+ }
  51.                                     //回滚" c( V5 E0 Q7 T$ \6 X
  52.                                     M()->execute('rollback');
    - A; g4 ~6 i/ |# w+ {
  53.                                     $data['msg']='未知错误!';
    7 N7 _/ K% P, v: D9 S2 p
  54.                                 }" \, D0 T1 Z" H, w
  55.                             }else{
    # u7 b: x3 X1 ]9 S
  56.                                 $data['msg']='红包已领完,你来晚了!';
    ; ]+ [) g" z& X8 t5 O9 t
  57.                             }5 [& B# R4 p) `& j9 Q
  58.                             M()->execute('UNLOCK TABLES');. \0 I& e$ L, e& C& }/ m
  59.                         }8 \- \0 a7 P4 Q$ K
  60.                     }9 ^8 h. L' o) y5 `- c1 m2 [( k
  61.                 }else{
    6 e  r; ]$ P6 I9 L9 Y
  62.                     $data['msg']='非法操作!';
    . l8 P5 {2 [7 P' j. i  x
  63.                 }
    " D( G  `7 U# @' }3 h
  64.             }else{
    1 K* q1 X+ s& y6 V8 F7 Q0 B# i) m
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    # f+ _- w7 v, L: V. m; {
  66.             }) x! |. u, c9 \
  67.         }
    $ j; u/ F; N# n, b: g% C* B
  68.         exit(json_encode($data));
    2 N7 o: m: ^; l9 Y$ r" e
  69.     }
复制代码
+ Y1 K( o$ D& w8 m

* W4 W/ B0 ^5 T( F+ T6 |( p
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2024-5-19 18:58 , Processed in 0.141565 second(s), 19 queries .

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