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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

& K' f: S: o3 ~4 l* g
Mysql中的锁语法:3 C# C2 q# [& F3 z$ q7 v
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
# L; g( G8 b  U9 C& ^8 fUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
& i  L0 X" g9 v# O! [6 QWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞) a; l# X; ~/ E# G! Q% x
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :/ |! m9 ]* a& i: Z% f( z9 {
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。' U+ M. }3 |4 t
测试时,有个文件就行,叫什么名无所谓
总结:
: I$ A# m+ X, a" ^, ^8 n* U项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:" g4 R5 X4 F) V& \) H9 F3 g
1. 高并发下单时,减库存量时要加锁
5 B/ f2 q) V; S+ x( }0 ?% g2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*; ~* Z, p* O) U& `4 y5 v8 S
  2.     模拟秒杀活动-- 商品100件" p8 U/ G  v( _8 O( }0 i
  3.     CREATE TABLE ta( u: Z( @" ?: q, ~' ~
  4.     (
    ( G; u. [3 C' J  M$ j8 Y9 F4 c
  5.         id int comment '模拟100件活动商品的数量'. x: g5 m+ j% b, H& Y& ^' M
  6.     );
    & n9 K$ H  O5 @. V! I
  7.     INSERT INTO ta VALUES(100);
    * }# {" W+ M$ f- U& S( I6 ?8 K
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件/ M/ Z5 l, o: \
  9.      */ 8 x4 J( G5 O3 Q2 H7 H
  10.     ; }# }- V% U7 @: M9 J) {
  11.     // 关闭错误报告8 C/ Y0 H' r+ L9 [# D) B7 u
  12.      error_reporting(0);
    3 S) L2 c$ v; e. P$ o
  13. + O5 }8 s/ d* u% a
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址% C7 h* j9 N9 w  R) c
  15.     $dbuser = 'root';            // mysql用户名/ `, c- @% B# }' s
  16.     $dbpass = 'root';          // mysql用户名密码* ]2 I; p4 L0 X2 d6 b% w& V
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);4 B; X; o: Z1 I; a9 M5 p8 Y
  18.     if(! $conn )# X# i0 S% b0 Z6 D, B+ c: V
  19.     {
    6 [1 G; J: U3 p# \. J# P
  20.         die('连接失败: ' . mysqli_error($conn));
    8 N/ ?4 L. _. T3 L
  21.     }
    8 [% p2 [( F+ x, T9 r
  22.     // 设置编码,防止中文乱码
    ! ]$ D" n/ J. n! l
  23.     mysqli_query($conn , "set names utf8");& o  ]6 s  ~  J2 [
  24.     mysqli_select_db( $conn, 'temp' );
    7 E  t: I, M9 v5 I- C0 m# u$ L

  25. ! y' H% p# y2 I9 |9 q3 M$ n
  26.     # mysql 锁 2 K1 ~% y# n7 F- ?4 S
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 + o! l6 F' N1 L4 j; x
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); 6 E. U" O, K* o+ Z
  29.     $id = mysqli_result($rs, 0, 0);
    # E% s, L( e8 U3 f3 F; ~5 e4 [
  30.     if($id > 0) 6 m% `4 K+ ^% L: ^: M! d
  31.     {
    ' N3 t* z$ A* S4 |2 d
  32.         --$id; ) ]6 m0 s+ L/ k' l5 I6 L, N
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id); , {1 g( z7 K" i& \: h8 O( u6 ?
  34.     } 6 Z. u7 ^" i0 u+ }

  35. 0 ]0 N+ P( o9 Q
  36.     # mysql 解锁
    ) T' v8 M5 l+ j6 ~$ s  J0 U) g3 W
  37.     mysqli_query($conn , 'UNLOCK TABLES');
    6 R# @* M# @& Q4 v
  38.     //查询解锁后的id值8 K# c( O# U" Q; b
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');: D8 S4 P" U0 W5 \/ U0 @2 \
  40.     // while($row = mysqli_fetch_assoc($res))7 l4 E  Q0 m/ {, _) b9 V
  41.     // {; D1 d: g, {* r/ {, p
  42.     //     $id = $row['id'];' X; U# t! I- p+ k, u
  43.     // }
      f9 A9 Z+ s2 `' D8 G4 u
  44.     // echo $id;
复制代码

. r- Q/ Q/ y6 o. }
( M  W5 `% z8 f2 V
- ^% [5 Y) G% Y7 b
PHP文件锁示例:
  1. /*; P; U0 ]$ O! Y$ X6 D
  2.     模拟秒杀活动-- 商品100件0 z0 k6 H0 ?+ t. |5 G5 o
  3.     CREATE TABLE ta
    ! T$ L7 L- c& r8 ~, ~4 M) D7 W; x; u- y
  4.     (
    6 ~$ [' g2 u; B  Y
  5.         id int comment '模拟100件活动商品的数量'
    6 Q2 n& r; w. e( a
  6.     );
    % f  G  D# u  {$ Y* i6 E- ~7 `( f, d
  7.     INSERT INTO ta VALUES(100);& R' Y$ v& v  _& ?
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件
    # h1 [: p0 H- Q6 N  G$ ?7 R5 A
  9.      */ ! K9 r* B8 Y5 [0 z, m; J$ {* e
  10.    
    . B# N5 G, G0 Q- }! h* a6 `+ B
  11.     // 关闭错误报告! b! P' ?7 k& u9 B. n6 T; o$ k
  12.      error_reporting(0);
    9 E; ^( G! ?0 z1 ^* X% |
  13. / T4 l, X) {' y4 a2 _9 L9 O
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    " r' a$ @6 }4 B; _, ~4 r
  15.     $dbuser = 'root';            // mysql用户名& c. B+ ?3 Q. ?1 N% U; |& |
  16.     $dbpass = 'root';          // mysql用户名密码4 C7 l  e( Z) b6 \$ ~! ^& u8 C
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);( N2 g* O% K+ D( s& E  e7 a: M
  18.     if(! $conn )
    4 }% S1 D0 G7 X) @
  19.     {- i& u) l4 u. |* N- o6 L1 J* h4 M
  20.         die('连接失败: ' . mysqli_error($conn));$ o' E  b2 w3 h" Q. ~  R. ?* X
  21.     }8 j. C/ J% T- d) m+ @* Z
  22.     // 设置编码,防止中文乱码
    : k- }+ u& Z# ^# v! `+ |2 S  ?+ r
  23.     mysqli_query($conn , "set names utf8");
    $ C* B- i, }8 D4 W4 u  c  {
  24.     mysqli_select_db( $conn, 'temp' );
    7 o0 ^& x; G, n4 F, b+ }
  25. + K# B, K: ], ?4 \  K
  26.     # php中的文件锁
    : b/ [/ w# \, Q# B5 p
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 1 Z) E2 ?) \3 ~' N
  28.     flock($fp, LOCK_EX);// 排他锁
    % X% w$ i; ~3 G: r; g" y
  29. 8 z6 @) U7 ^7 f; e1 t' h
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    % V" D8 f  y, B& s5 d2 ^" {
  31.     while($row = mysqli_fetch_assoc($retval))# h( _. K8 r! s+ w+ y' w, ]9 ?. L
  32.     {; y" C) c1 f6 {  q# M9 `+ H' I  [
  33.         $id =  $row['id'];
    2 n" u& N2 M; {
  34.     }1 v# X9 Q' Y* w+ X
  35.    
    0 B8 O" r& z( [
  36.     if($id > 0) ( E  J' @/ A' j
  37.     {
    5 c4 d6 K0 U9 D8 j7 w) f$ ]$ u* p
  38.         --$id;
    + J  R6 d5 c# r
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); & T( I$ k, t% I- ~
  40.     }
      H$ u  H9 m& C1 T& }  W) K  P
  41.     # php的文件锁,释放锁
    9 e% a+ h. p# F! M$ G* F% w. z
  42.     flock($fp, LOCK_UN); 4 C& v0 |- v) N7 b, l& T
  43.     fclose($fp);
    + j# [+ Z# f% v) o, K4 D" E
  44. 3 x5 B; t7 s8 W0 X& o* f
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
      E, X: k  r1 E: Z' U0 a
  46.     // while($row = mysqli_fetch_assoc($res))
    ) x& A. u; G, ]* z# N0 D* M
  47.     // {
    4 Z9 z% A( l& ]$ v
  48.     //     $id = $row['id'];
    , }# W/ O& t8 n! U; l# ~8 ]& T
  49.     // }
    # G: E6 K5 X: x% S: ^9 T, z
  50.     // echo $id;
复制代码
$ k1 K; O0 t. X4 V
5 D# S- f" P2 t$ p9 N2 m' w
抢券活动实例:
  1. public function envelopeSnatching(){5 A% L+ C- S% ~$ K
  2.         $lingqu = $_POST['type'];9 G* {1 Y" v7 L$ U
  3.         $uid=session('u_id');//用户id! H9 }% U5 T: W
  4.         if(!$uid){
    3 x* b5 }# K$ e/ M! L4 D  t
  5.             $data['msg']='您没登录,请先登录!';
    1 B' F* d8 Y  B+ I  e7 H& l
  6.         }else if(date('Y-m-d') != '2017-12-12'){$ U% I1 ^# @, ~  w5 W# O0 |+ n
  7.             $data['msg']='不在活动时间内!';
    7 B  r1 B+ L: h2 y% Y9 P4 ~% F. g' L
  8.         }else{& u4 ^. _+ y4 }! {
  9.             $hours=date('H');//当前小时数
    ' Q6 M9 v  A5 `9 `& o- e/ J
  10.             if($hours > '09' || $hours > '17'){
    ) q% s9 }, B& I! t

  11. " O* F/ y$ c0 _2 x7 X) I# f
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的
    $ Q' ~" p+ Z8 ~8 N
  13.                     if($lingqu == 1){' E5 P3 |7 \" I& h
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过( E4 L3 n$ F% w9 r: ^6 C
  15.                         if($hours > '09'){
    / E2 i! v/ K3 i0 Z2 r2 U4 P
  16.                             $num=mt_rand(25,28);//优惠券金额
    ! Y; i+ i) g# _: c# [6 ~% R
  17.                             $id=1;
    $ `. u7 v2 _5 Z
  18.                         }+ N2 u& K8 U& ]
  19.                     }else if($lingqu == 2){  z- X3 e$ m) S& p' a# J0 _2 K
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();9 {4 K5 z2 B; o" h8 o0 O
  21.                         if($hours > '17'){% C$ @; e) I( F* _% W
  22.                             $num=mt_rand(50,55);//优惠券金额
    # h' u. w/ j/ [4 K4 H
  23.                             $id=2;
    * p6 j. ^6 O/ ~2 @7 T7 X6 G; z+ C
  24.                         }8 ]+ o3 s! z+ Y+ V0 |
  25.                     }9 }$ L7 I  x' {
  26.                     if(!$id){
    2 n! @* ?% \9 A) m2 U8 q
  27.                         $data['msg']='时间还没到,晚点再来吧。';
    * p* v; }4 |7 q3 J6 T1 G. T/ W' Q  ?
  28.                     }else{
    / I. f- x' }" D5 j: l9 @6 N" ]
  29.                         if($is_lingqu){0 v' R' d% }4 i, ]8 l
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';7 R: U# r" B9 b* A4 \$ y
  31.                         }else{
    4 d5 N/ W4 T' V( `' G* o
  32.                             //锁表, D; m$ P% K" R$ L5 ^% p4 w7 F; @
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    $ |. T* R2 d' V: P2 }
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    + ~' A  B& H9 M& N$ Z( m( _
  35.                             if($active > 0){
    ! v+ J/ c3 w4 I4 Q
  36.                                 //开启事务7 i% l+ z( Y( ]# T3 o
  37.                                 M()->execute('start transaction');4 f% d5 Z4 w, Q  l% Y4 @
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    ( f& E* O' ?4 G/ L0 f
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));' W6 f. l6 l! Y" v0 q: t7 y$ j- x
  40.                                 $members_preferential    =    M('members_preferential');+ a8 q" _$ x  C' I4 U; f
  41.                                 //对应投资金额,' A; J8 a3 ^5 M! L3 B
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
    7 \* n, `6 x9 }' o8 s3 C
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
    2 L$ r% R6 u9 t: `" O3 p9 C
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
    9 [' c/ i5 j3 `4 @, ^3 V
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    + z( O1 Y$ B* v- \
  46.                                 if($save && $add && $add2){( B/ L% F* Y' v/ L  K, z. v
  47.                                     //事务提交1 `1 n9 q- F! _) p6 D
  48.                                     M()->execute('commit');0 h+ V- \( N. A) Z) U+ S" O7 B
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';4 B% x1 c% W1 m# N1 T
  50.                                 }else{
    3 u6 g8 ?9 A$ {2 _; W  t
  51.                                     //回滚( i) d% |" R- z5 M
  52.                                     M()->execute('rollback');
    0 R) C9 Y' q! j& Z1 h8 F, ?- A3 O) s
  53.                                     $data['msg']='未知错误!';' ]5 _# d# b3 E* p$ s: v
  54.                                 }
    / V# _; I" t  B0 V' S  F9 |/ z% ?: l
  55.                             }else{& {/ b- J9 }( g; J4 n( r- Z
  56.                                 $data['msg']='红包已领完,你来晚了!';
    8 {" g7 m! q- V  X3 w# ~
  57.                             }( M. I# M9 ?' K# P, D& `" {+ D3 m
  58.                             M()->execute('UNLOCK TABLES');, M4 i0 i' D4 z5 q# u3 R# i* A# Z  j
  59.                         }
    % L8 _% N# @5 Y
  60.                     }* d& D2 j- B- {+ C( V
  61.                 }else{7 i& w+ N9 Z4 i5 v6 M- p5 e
  62.                     $data['msg']='非法操作!';
    8 K0 [4 t4 K# U8 O
  63.                 }" x0 h4 a! F3 {& s# G
  64.             }else{5 U% T, a/ h% G
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';
    % @" L  V6 Y" P- Z1 b8 c
  66.             }6 X5 A! q, G# E, |
  67.         }
    0 U# T$ Q+ n, \% u, M7 h3 _( X; A
  68.         exit(json_encode($data));
    ! v% U' ^: P9 d, r6 U6 Z% F
  69.     }
复制代码
6 c, b% X7 e7 W$ J
# l& a( s4 L1 k# {0 P: s0 r+ q+ m! W% X' G
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-3-17 16:07 , Processed in 0.063771 second(s), 19 queries .

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