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

QQ登录

只需一步,快速开始

 找回密码
 立即注册

QQ登录

只需一步,快速开始

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

1 [1 T' ^# D- u1 @& F: {
Mysql中的锁语法:
- ?/ ?" u% d4 oLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
  Q; b5 n3 o: ZUNLOCK TABLES  【释放表】
Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
3 l9 V+ j( t0 F. M0 K% uWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞$ K/ y8 C. i2 T" ^
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来!
PHP中的文件锁 :0 O  s- R0 ^' }/ V( U7 Y
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。5 Q9 C: Q; Z+ O9 \; T
测试时,有个文件就行,叫什么名无所谓
总结:
" e% U, P9 ~/ s1 l1 Y$ C8 g- A: y5 Z项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。
比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。
应用场景:
: z0 ]  W# Y6 k) w* c1. 高并发下单时,减库存量时要加锁, U+ m/ x! a# \& D' L5 B3 Y4 R
2. 高并发抢单、抢票时要使用
Mysql锁示例:
  1.    /*
    " t# J/ r! h1 G* A9 R0 C) J" S
  2.     模拟秒杀活动-- 商品100件
    3 i7 B( S3 P+ F
  3.     CREATE TABLE ta8 @. G* j, k- C* }4 j
  4.     (
    8 x9 h5 c) G4 L; N6 x6 F
  5.         id int comment '模拟100件活动商品的数量'
    % H" F1 M$ t3 q1 }1 @% p
  6.     );
    * P& F8 \: c; K! `; C
  7.     INSERT INTO ta VALUES(100);! B9 b) K3 Y8 h; j1 {! J: W) G  }
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件! g+ U/ z) A$ h  _2 e$ d
  9.      */ $ N2 v$ `5 \8 t2 y' ~& ~3 h
  10.    
    4 p3 O( m( P8 q6 z# d
  11.     // 关闭错误报告0 e9 O4 U4 X: h. g3 m
  12.      error_reporting(0);
    . z) z' R$ N# @- [
  13.   J% F  {  k. a1 n3 v/ A
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址
    : G- H! Z  n# Y/ s
  15.     $dbuser = 'root';            // mysql用户名! h% a/ C5 E1 N$ B7 S
  16.     $dbpass = 'root';          // mysql用户名密码
    / z5 T5 o9 N% M+ N* e0 ~
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
    " U) [  t1 H; N
  18.     if(! $conn )
    8 k( M- {( \/ _- c+ L
  19.     {
    * `, r8 K( t7 G, k' H
  20.         die('连接失败: ' . mysqli_error($conn));  Z6 g/ A/ n( r* j! z5 H" Q
  21.     }, q( h$ z/ e# h! A) O* i3 G# A
  22.     // 设置编码,防止中文乱码3 [% Z* f4 W# ^% d9 @
  23.     mysqli_query($conn , "set names utf8");
    9 q/ C  p$ R3 g: ~8 y
  24.     mysqli_select_db( $conn, 'temp' ); ! a6 |' Z9 S3 p# r  B; n4 P5 ^) p0 ?
  25. 6 N* M, N8 @5 c& a- t* T) e
  26.     # mysql 锁
    6 v* @2 ^8 I4 u( t
  27.     mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
    - C% Q; n. a% F% Q! {) E  j
  28.     $rs = mysqli_query($conn , 'SELECT id FROM a'); - L% G) e, k/ N: b- `
  29.     $id = mysqli_result($rs, 0, 0); 9 U! `: r3 }& Y0 {3 j5 k
  30.     if($id > 0) 2 j' |  t6 p7 Q1 {! a- S' P
  31.     {
    , V/ m' O; a/ z2 s
  32.         --$id; % b& q  C0 h9 s& D) X9 S
  33.         mysqli_query($conn , 'UPDATE a SET id='.$id);
    " O& ?0 s: D- _0 O- G
  34.     }
    4 C! g4 v8 `* Q/ e( |# c3 k% D# \

  35.   |5 s' _1 Y+ Y% s
  36.     # mysql 解锁
    & K- ~# M' L7 u9 F, `$ G
  37.     mysqli_query($conn , 'UNLOCK TABLES');) t! A# |5 b# G- b& ^4 _5 q) Y! k& ]
  38.     //查询解锁后的id值
    2 T6 u/ G: P- J
  39.     // $res = mysqli_query($conn , 'SELECT id FROM ta');
    ' H  a9 g, g" H
  40.     // while($row = mysqli_fetch_assoc($res))9 _  g$ E3 ~9 T9 @# M
  41.     // {3 x$ Y/ {0 Z" f5 e) b4 y. e9 {4 U( F
  42.     //     $id = $row['id'];
    3 v5 ^* x* Y* P- x
  43.     // }
    5 |4 h1 g0 s& C: Y5 D1 L
  44.     // echo $id;
复制代码
- b1 Z3 g5 b9 c
8 B% ^: M+ Z$ c; a

: D2 s8 m- y- A" [
PHP文件锁示例:
  1. /*, `6 D: d2 z/ J) ?) k
  2.     模拟秒杀活动-- 商品100件  D0 N" X4 ]/ E" j6 p
  3.     CREATE TABLE ta# S' a1 h1 {4 A& ~( I
  4.     (
    ' z1 O' \+ z0 O! j  f5 K8 E
  5.         id int comment '模拟100件活动商品的数量'. U8 T7 a% J: Q9 `6 o$ q
  6.     );
    + i4 W+ T( T* x
  7.     INSERT INTO ta VALUES(100);
    1 S/ w7 J$ \* Y" r  o# r- d
  8.     模仿:以10的并发量访问这个脚本!    使用apache自带的ab.exe软件5 }; g  V3 A8 v; n. s8 F( `
  9.      */
    2 ~' `2 r$ W1 p0 p7 T
  10.     7 S6 _5 z) L: n
  11.     // 关闭错误报告. M- b, r" J) e5 o# Y3 V/ J
  12.      error_reporting(0);
    1 `+ V) e4 L8 f% I" r' a( j
  13. 2 K: y0 k; d3 Y4 O& z3 _6 ?$ p- B( U
  14.      $dbhost = 'localhost:3306';  // mysql服务器主机地址4 X: p$ Q( U7 i( e) i  |0 |
  15.     $dbuser = 'root';            // mysql用户名1 I- J6 B( a. p. A" X3 L
  16.     $dbpass = 'root';          // mysql用户名密码
    2 z% |: M& H  J' K
  17.     $conn = mysqli_connect($dbhost, $dbuser, $dbpass);! J$ x4 u) `& ?2 k9 K8 L
  18.     if(! $conn )
    + [2 c3 N' v) d: ]
  19.     {0 S4 J! c% T% K$ \% I3 T% J
  20.         die('连接失败: ' . mysqli_error($conn));  V* n8 x! s3 T; ?5 {2 |0 b$ `, y
  21.     }' P! L8 v- X  y& s: f3 F
  22.     // 设置编码,防止中文乱码: b+ Y% v/ D  z2 Y2 Y- u0 o; W
  23.     mysqli_query($conn , "set names utf8");
    ! k5 {3 O  w* l- |/ S6 E% K8 a3 v& m
  24.     mysqli_select_db( $conn, 'temp' ); 4 m  X* \; F- v8 j6 _
  25. 7 C5 `% @! O4 p5 W3 s
  26.     # php中的文件锁 : ~/ _! t( R. S- {$ `" r
  27.     $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
    . C" \  q* R& B% G* S1 F
  28.     flock($fp, LOCK_EX);// 排他锁 " p, G- O0 Y/ D: I4 J, H5 l6 T1 i
  29. $ j; s; A+ s8 @
  30.     $retval = mysqli_query($conn ,'SELECT id FROM ta');
    % J/ Q: n2 D# A6 X6 E8 x
  31.     while($row = mysqli_fetch_assoc($retval))
    ! n8 Z5 v3 s' a' p4 @1 Z
  32.     {
    5 e$ |' j' j' ]- a$ X, w
  33.         $id =  $row['id'];4 ^# ]+ a# X8 c9 r$ N
  34.     }. L1 H8 c$ |+ G1 l
  35.     0 o. P4 c* m+ |& r9 m
  36.     if($id > 0)
    : H, W3 T+ A# U- Y* a# q
  37.     { 8 }. m' ?( d' p' }3 g
  38.         --$id; * o8 L; ^+ u/ f5 \* h1 e
  39.         mysqli_query($conn ,'UPDATE ta SET id='.$id); & O% {: o4 T6 W, c
  40.     }
    0 ~4 ~. W; v: v0 u
  41.     # php的文件锁,释放锁 8 N; b; |2 W. ^8 P3 J+ u5 \- b
  42.     flock($fp, LOCK_UN); " N. Z# K8 ~5 q) d" S' v# d2 w
  43.     fclose($fp);
    # e2 e* B2 a2 R8 u9 S1 W
  44. 1 o: j+ s1 J$ @3 z  [8 [7 ~3 i1 ^
  45.     // $res = mysqli_query($conn , 'SELECT id FROM ta');& N9 A. J& b& ~* @! J& s8 |
  46.     // while($row = mysqli_fetch_assoc($res))
    4 `* H. C; [$ |: L3 ^6 M
  47.     // {  u! ^; `1 ^3 G. c. n
  48.     //     $id = $row['id'];
    7 M4 Y8 u) T7 x/ M' l
  49.     // }  _  J; W4 z& k2 [+ s9 n' N
  50.     // echo $id;
复制代码

5 I* B# [6 x; ~9 U3 w. r( C. R$ ], M, I: E
抢券活动实例:
  1. public function envelopeSnatching(){
    * d6 M/ S6 P! ~0 w8 P8 j' z
  2.         $lingqu = $_POST['type'];
    $ _% ]. E+ E- J2 j
  3.         $uid=session('u_id');//用户id
    - p" ?2 d& k* H8 m0 S% q  y& Z; W
  4.         if(!$uid){
    3 V1 P. `( m! e
  5.             $data['msg']='您没登录,请先登录!';; ^  O: i& S6 ^
  6.         }else if(date('Y-m-d') != '2017-12-12'){
    % g6 [; ?9 u4 j1 c! P
  7.             $data['msg']='不在活动时间内!';
    % w5 r. O4 ^4 a9 x, F( d% e
  8.         }else{) o+ g2 d  j* J4 P: s. b
  9.             $hours=date('H');//当前小时数' u6 L2 d; I6 P  Y
  10.             if($hours > '09' || $hours > '17'){
    5 A+ i: g3 S& G* H9 S
  11. 0 y  _; c6 V5 E8 O% x
  12.                 if($lingqu == 1 || $lingqu ==2){//点击10点的' n: y% {8 m! i0 T" m! i2 R- f
  13.                     if($lingqu == 1){
    + _/ k! t3 [( V- @" s) ~
  14.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过, Q3 z9 S# D8 C7 `
  15.                         if($hours > '09'){5 |8 c4 D: f' G5 E+ C8 P% t' W- a4 B
  16.                             $num=mt_rand(25,28);//优惠券金额- @  T3 L6 U5 M+ T: e3 {6 f4 L
  17.                             $id=1;
    ' a( J. `' H' F7 o: R" \# @
  18.                         }
    4 B2 i; q7 n* Z) L+ z3 @% k
  19.                     }else if($lingqu == 2){
    7 L0 _$ O- _8 {- u: ~; ]7 G; O1 H$ d
  20.                         $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
    + d1 ]% k% H: ?% _- t4 {
  21.                         if($hours > '17'){
    6 S4 \" `$ U2 j0 e" k8 m
  22.                             $num=mt_rand(50,55);//优惠券金额
    2 K$ m5 ^6 j( ?2 U: A$ X
  23.                             $id=2;. A+ E( s5 @5 |( c$ y. u
  24.                         }
    ! I% ]8 x) H" ~3 d3 J# f  [
  25.                     }; `, K9 [0 O6 _- s
  26.                     if(!$id){
    # u" \. V2 P/ {6 e
  27.                         $data['msg']='时间还没到,晚点再来吧。';* n  D7 {% |1 i2 G" J
  28.                     }else{
    " k' z4 [) e8 f* d1 r
  29.                         if($is_lingqu){) j. M: Q9 S& Q: v1 n
  30.                             $data['msg']='你已经领取过了,留点给别人吧!';  q' Z  Z. L2 _
  31.                         }else{
    ) \7 r. n* _% A( M8 B
  32.                             //锁表
    ) K8 P% _! m4 A! J
  33.                             M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
    / D8 A# `* S9 I- h+ S  F1 m
  34.                             $active=M('active_num')->where(array('id'=>$id))->find();
    % [+ U$ }4 z$ Y5 m: P" H
  35.                             if($active > 0){/ {4 s6 A) M* L0 g% A
  36.                                 //开启事务
    1 @5 B+ X# f: }( e6 \* N
  37.                                 M()->execute('start transaction');
    + n7 @' X9 w+ M8 b) X1 E
  38.                                 $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
    ! }: \* a9 N% m8 \( Q1 I
  39.                                 $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));! }' d# e  S  a/ b
  40.                                 $members_preferential    =    M('members_preferential');
    ' |: a' o( ^* i" X1 u* f4 K
  41.                                 //对应投资金额,& {  g; A4 L& o2 j" p& T
  42.                                 $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));. E1 b9 F3 R! s# d- Y) N
  43.                                 $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');2 K1 i, h! Q" s" m" T2 Y
  44.                                 $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间* b7 m1 i% w' m! h7 y- n. r6 W
  45.                                 $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
    8 M6 c6 b, }$ f6 c2 m' u
  46.                                 if($save && $add && $add2){
    ' n1 p/ v# i4 d3 V% b
  47.                                     //事务提交
    * W% g6 X3 `. [9 O% P
  48.                                     M()->execute('commit');% k: q$ M! G# S- F: y( R
  49.                                     $data['msg']='恭喜你领取了'.$num.'元优惠券';& @2 n* z" ]* l
  50.                                 }else{
    ; u( }1 b7 y$ [& }% c
  51.                                     //回滚
    5 ^0 Y5 Z0 J3 c0 [; s5 q0 s& e
  52.                                     M()->execute('rollback');
    8 q! w  K8 d2 B) Y+ V( c3 p+ @3 e
  53.                                     $data['msg']='未知错误!';4 K3 X! p4 Q7 P, q
  54.                                 }) m9 G% K; L4 C1 ], U) |2 q
  55.                             }else{, g  H% r; ?, B: R& z' P7 u& @
  56.                                 $data['msg']='红包已领完,你来晚了!';
    7 E! k  N! ~- i- X& t- d
  57.                             }
    : Y! G5 P, c" G
  58.                             M()->execute('UNLOCK TABLES');
    ( `, Z" }0 ~9 {/ G( b8 c) z
  59.                         }
    7 P9 c: u1 G( q' ]% Q
  60.                     }3 \$ X- J! Y2 e$ L( c3 Z: n
  61.                 }else{
    " N: J9 w; |0 H9 Y. b
  62.                     $data['msg']='非法操作!';  k4 a, P/ p% m, D" Q% s; y
  63.                 }( [7 J& f+ H2 G' _
  64.             }else{/ \2 L, ~7 S2 `: u" s1 K6 p
  65.                 $data['msg']='还没有到活动时间,请晚点再来哟!!';, B0 E* u7 G. j! t
  66.             }3 A+ J  O2 {, o8 \/ a* ]: i
  67.         }+ n, _" g$ j7 Y  B
  68.         exit(json_encode($data));+ n% k! Z$ ^* W( F) ^9 f$ A
  69.     }
复制代码
2 s1 E+ q* G6 m* m! ^9 i" Q0 a

7 ^4 V$ i1 x& Y/ G
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

GMT+8, 2026-8-4 10:54 , Processed in 0.060583 second(s), 20 queries .

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