Mysql InnoDB存储引擎的锁相关

Mysql InnoDB存储引擎的锁相关

  • InnoDB下,mysql四个级别隔离下加锁操作
    • 四个级别隔离的写操作都加X锁
    • 串行化下读加S锁
    • select … for update, select … lock in share mode 分别加x锁,s锁
    • 在需要加锁的场景下,会根据情况使用三种加锁策略(算法)
      • Record Lock
      • Gap Lock
      • Next-Key Lock
    • mysql RR 为啥能隔离幻读
      • 快照读 select
      • 当前读 select for update, select lock in share mode, delete,insert,update
    • InnoDB提供了一致性的非锁定读、行级锁支持
    • Lock 与Latch
      • Lock 主要用于锁定数据库中的对象,如表、页、行,而Latch主要是线程并发上的资源锁定。
      • Latch的实现采用了乐观spin-wait,所以在竞争比较激烈的并发环境下,性能不是很好,是一种轻量锁。
      • Latch
        • mutex(互斥liang)
        • rwlock(读写锁)
      • Lock
        • 行锁、表锁、页锁
        • 在没有索引的情况下,一般是锁全表的所有行,然后逐行判断解锁
        • 没有实现锁升级
    • 行级锁
      • 共享锁(S Lock)
      • 排他锁 (X Lock)
      • S与S兼容,而X与什么都不兼容
    • 意向锁(事务在更细的粒度上加锁)
      • 意向共享锁(IS Lock) ,事务想要获得一张表中某几行的共享锁
      • 意向排他锁(IX Lock),事务想要获得一张表中某几行的排他锁
      • InnoDB的意向锁是表级别的锁
    • 一致性的非锁定读
      • 通过行多版本控制的方式来读取当前执行时间数据中行的数据。
      • 如果当前行的X锁已经被获得,那么通过undo 段,来获得X锁被获得前的快照,返回该快照的数据
      • 非锁定读,不需要X锁的释放就可以进行操作。可以等同于在事务开始时获得全局快照,在事务运行期间,无论其他事务是否对数据进行提交,都不影响。
    • 一致性锁定读
      • SELECT…FOR UPDATE (加X锁)
      • SELECT… LOCK IN SHARE MODE (加S锁)
    • 自增长与锁
      • SELECT MAX(auto_inc_col) FROM t FOR UPDATE;
    • 外键和锁
      • 对外键值的插入和更新的时候,需要读父表,这时不能采用一致的非锁定读,否则会出现子表与父表不一致的现象。所以需要采用一致性读,也就是给父表加S锁。
    • 行锁的三种算法
      • Record Lock: 单个行记录上的锁
        • 锁的是索引,如果没有设置索引,那么锁的是主键
      • Gap Lock: 间隙锁,锁定一个范围,不包含记录本身
        *
      • Next-Key Lock: Gap Lock + Record Lock, 锁定一个范围,并且锁定记录本身
        • 唯一索引情况下,降级为Record Lock
    • InnoDB通过Next-key Lock避免了幻读问题
      • 通过加两个间隙锁,来保证对于insert,delete操作不会造成幻读
    • 所有隔离级别都实现了写写互斥
    • 四种隔离级别
      • 读未提交
        • 读读不互斥、读写不互斥、写写互斥(不是没有加锁!!!!)
      • 读已提交(一致性的非锁定读)
        • 读读不互斥、读写不互斥、写写互斥
        • 每次读都是读的最新快照 (避免了脏读,通过undo log实现)
      • 可重复读(一致性的非锁定读)
        • 读读不互斥、读写不互斥、写写互斥
        • 每次读都是事务开始时的最新快照 (避免了脏读,不可重复读, 通过undo log实现)
      • 串行化
        • 读读不互斥、读写互斥、写写互斥
        • 读读加的是S锁
        • 容易发生死锁
    • 死锁
      • 发生死锁时,会自动回滚事务

Mysql Innodb 中的锁

先列出我本地的运行环境

img

数据库版本是5.7,隔离级别是Repeatable-Read(可重复读),不同的数据库版本和隔离级别对语句的执行结果影响很大。讨论锁的时候不指明版本和隔离级别,都是耍流氓。

一、为什么要加锁

数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。

锁是用于管理对公共资源的并发控制。也就是说并发的情况下,会出现资源竞争,所以需要加锁。

举个例子,转账操作。简单来说,张三给李四转账x元,可以分为三步:

1,先查询张三的账户余额y是否大于x2,张三的余额 y = y - x元3,李四的余额 x = z + x元

假设张三账户余额有1000元,李四余额也有1000元,如果不加锁的话,同时有两个请求,A要求转500元,B要求转600元,第一步查询余额都是足够的,第2步和第3步也能执行成功,但是最终结果却是错误,第二个请求可能会覆盖掉第一个请求。

这种问题叫做 丢失更新: 多个事务操作同一行,后面的更新覆盖了前面的更新值。需要在应用级别加锁来避免。

数据库有ACID原则,其中I是隔离性,标准SQL规范中定义了四种隔离级别:

img

越往下,隔离级别越高,问题越少,同时并发度也越低。隔离级别和并发度成反比的。

  1. 脏读:事务A读取了事务B未提交的数据
  2. 不可重复读:对于一条记录,事务A两次读取的数据变了
  3. 幻读:事务A按照相同的查询条件,读取到了新增的数据

MySQL中的隔离级别如下:

img

和标准SQL规范相比,MySQL中可重复读解决了幻读,实现了串行化隔离级别的功能,同时没有严重影响并发。是通过加锁、阻止插入新数据,来解决幻读的。

二、锁的分类

img

我们听说过读锁、写锁、共享锁、互斥锁、行锁等等各种名词,根据自己的理解,简单对这些锁进行了分类。

img

加锁机制:

1、乐观锁:先修改,保存时判断是够被更新过,应用级别

2、悲观锁:先获取锁,再操作修改,数据库级别

锁粒度:

表级锁:开销小,加锁快,粒度大,锁冲突概率大,并发度低,适用于读多写少的情况。

页级锁:BDB存储引擎

行级锁:Innodb存储引擎,默认选项

兼容性:

S锁,也叫做读锁、共享锁,对应于我们常用的 select * from users where id =1 lock in share mode

X锁,也叫做写锁、排它锁、独占锁、互斥锁,对应对于select * from users where id =1 for update

下面这个表格是锁冲突矩阵,可以看到只有读锁和读锁之间兼容的,写锁和读锁、写锁都是冲突的。

img

冲突的时候会阻塞当前会话,直到拿到锁或者超时

这里要提到的一点是,S锁 和 X锁是可以是表锁,也可以是行锁

索引组织表

先理解下索引组织表。

img辅助索引

img聚集索引

Innodb中的索引数据结构是 B+ 树,数据是有序排列的,从根节点到叶子节点一层层找到对应的数据。普通索引,也叫做辅助索引,叶子节点存放的是主键值。主键上的索引叫做聚集索引,表里的每一条记录都存放在主键的叶子节点上。当通过辅助索引select 查询数据的时候,会先在辅助索引中找到对应的主键值,然后用主键值在聚集索引中找到该条记录。举个例子,用name=Alice来查询的时候,会先找到对应的主键值是18 ,然后用18在下面的聚集索引中找到name=Alice的记录内容是 77 和 Alice。

表中每一行的数据,是组织存放在聚集索引中的,所以叫做索引组织表。

了解索引数据结构的目的是为了说明,行锁是加在索引上的。

1.select * from user where id=10 for update

img

一条简单的SQL。在user表中查找id为10的记录,并用for update加X锁。

这里User表中,有3个字段, 主键id 和 另外一个字段name。下面的表格是B+树索引的简化表达。第一行id是索引的节点,第二行和第三行是这行记录,包含了姓名和性别。

如图所示,通过锁住聚集索引中的节点来锁住这条记录。

聚集索引上的锁,比较好理解,锁住id=10的索引,即锁住了这条记录。

2. select * from user where name=‘b’ for update

img

查询user表中name为d的记录,并用for update加X锁

这里的name上加了唯一索引,唯一索引本质上是辅助索引,加了唯一约束。所以会先在辅助索引上找到name为d的索引记录,在辅助索引中加锁,然后查找聚集索引,锁住对应索引记录。

为什么聚簇索引上的记录也要加锁?试想一下,如果有并发的另外一个SQL,是直接通过主键索引id=30来更新,会先在聚集索引中请求加锁。如果只在辅助索引中加锁的话,两个并发SQL之间是互相感知不到的。

3. select * from user where name=‘b’ for update

img

查询user表中name为b的记录,并用for update加X锁。这里name上加了普通的索引,不是唯一索引。普通索引的值是可以重复的。会先在辅助索引中找到name为b的两条记录,加X锁,然后得到主键值7和30,到聚集索引中加X锁。

事情并没有那么简单,如果这时有另一个事务,插入了name=b,id=40的记录,却发现是可以插入的。

img

位置在途中红色线条标注的间隙内,这样就会出现幻读,两次查询得到的结果是不一致的,第一次查到两条数据,插入之后得到三条数据。

为了防止这种情况,出现了另一种锁,gap lcok 间隙锁。锁住的是索引的间隙。

img

即图中,红色线条标识的空隙。因为新插入name=b的记录,可能出现在这三个间隙内。

这张图里出现了三种锁

记录锁:单行记录上的锁

间隙锁:锁定记录之间的范围,但不包含记录本身。

Next Key Lock: 记录锁+ 间隙锁,锁定一个范围,包含记录本身。

4. 意向锁( Intention Locks )

InnoDB为了支持多粒度(表锁与行锁)的锁并存,引入意向锁。意向锁是表级锁,

IS: 意向共享锁
IX: 意向排他锁

事务在请求某一行的S锁和X锁前,需要先获得对应表的IS、IX锁。

意向锁产生的主要目的是为了处理行锁和表锁之间的冲突,用于表明“某个事务正在某一行上持有了锁,或者准备去持有锁”。比如,表中的某一行上加了X锁,就不能对这张表加X锁。

如果不在表上加意向锁,对表加锁的时候,都要去检查表中的某一行上是否加有行锁,多麻烦。

img意向锁的兼容性矩阵

5. 插入意向锁(Insert Intention Lock)

Gap Lock中存在一种插入意向锁,在insert操作时产生。

有两个作用:

  • 和next-key互斥,阻塞next-key 锁,防止插入数据,这样就不会幻读。
  • 插入意向锁互相是兼容的,允许相同间隙、不同数据的并发插入

三、常见语句的加锁分析

后面会有多个SQL语句,先说明一下表结构

CREATE TABLE `user` (`id` int(11) unsigned NOT NULL AUTO_INCREMENT,`id_no` varchar(255) DEFAULT NULL COMMENT '身份证号',`name` varchar(255) DEFAULT NULL COMMENT '姓名',`mobile` varchar(255) DEFAULT NULL COMMENT '手机号',`age` int(11) DEFAULT NULL COMMENT '年龄',`address` varchar(255) DEFAULT NULL COMMENT '地址',PRIMARY KEY (`id`),UNIQUE KEY `uniq_id_no` (`id_no`),KEY `idx_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=10002 DEFAULT CHARSET=utf8 COMMENT='用户表';

这里有一个user表,5个字段,其中id是主键,id_no是身份证号,加了唯一索引,name是用户姓名,可以重复的,加了普通索引,手机号、年龄、地址都没有索引。

1. 普通select

select  * from user where id =1;begin;
select  * from user where id =1;
commit:

普通的select 语句是不加锁的。select包裹在事务中,同样也是不加锁的。where后面的条件不管多少,普通的select是不加锁的。

2. 显式加锁

select  * from user where id =1 lock in share mode;select  * from user where id =1 for update;

显式指出要加什么样的锁。上面一个加的是共享锁,下面的是互斥锁。

这里需要强调的一点,需要明确在事务中是用这些锁,不在事务中是没有意义的。

3. 隐式加锁

update user set address '北京' where id=1;
delete from user where id=1;

update和delete也会对查询出的记录加X锁,隐式加互斥锁。加锁类型和for update 类似

后面只按照显式加锁的select for update 举例子,更新和删除的加锁方式是一样的。

4. 按索引类型

elect  * from user where id =1 for update;select  * from user where id_no ='a22' for update;select  * from user where name ='王二' for update;select  * from user where address ='杭州' for update;

四条SQL,区别在于where条件的过滤列,分别是主键、唯一索引、普通索引、无索引。

img

主键:之前提到过索引组织表,这里会在聚集索引上对查询出的记录,加X锁

唯一索引:会在辅助索引上,把在对应的id_no=a22的索引加X锁,因为是唯一的,所以不是next-key锁。然后在主键上,也会在这条记录上加X锁。

普通索引:因为不是唯一的,会在辅助索引上,把对应的id_no=a22的索引加next-key锁。然后在主键加X锁。

无索引:首先,是不推荐这种写法,没有索引的话,因为会全表扫描,数据量大的话查询会很慢。这里讨论的是,这种情况下,会加什么锁? 答案: 首先,聚簇索引上的所有记录,都被加上了X锁。其次,聚簇索引每条记录间的间隙(GAP),也同时被加上了GAP锁。在这种情况下,这个表上,除了不加锁的快照度,其他任何加锁的并发SQL,均不能执行,不能更新,不能删除,不能插入,全表被锁死。这是一个很恐怖的事情,请注意。

5. 记录不存在的情况

前面几个例子中,都是可以查到结果的。如果对应记录不存在会怎样?答案是锁住间隙,不允许插入。mysql要保证没有其他人可以插入,所以锁住间隙。

6. 普通 insert 语句

在插入之前,会先在插入记录所在的间隙加上一个插入意向锁。

insert会对插入成功的行加上排它锁,这个排它锁是个记录锁,而非next-key锁(当然更不是gap锁了),不会阻止其他并发的事务往这条记录之前插入 。

7. 先查询后插入

类似于这样的insert

insert into target_table select * from source_table ...
create target_table select * from source_table ...

将select查询的结果集,插入到另一张表中,或者使用结果集,创建一个新表。

和之前简单插入的情况类似,已插入成功的数据加X锁,间隙加上一个插入意向锁。

对于select的源表中的记录,会加共享的 next-key 锁。这是为了防止主从同步出问题。

举个例子:

img

session1 先开启事务,然后查询user2表的结果集,插入到user表中,session2开启事务,在插入user2中插入数据,所插入的数据刚好是session1能查询到的数据,如果不加锁的话,session2可以插入成功,然后session2提交事务,接着session1提交数据。这样看起来是没问题的,但是session2先提交的,所以bin log中会这样记录,先在user2表中插入数据,然后在user中插入数据,这样的bin log在从库执行的时候,就会出问题。

主库: user2插入一条数据,user 插入一条数据

从库: user2插入一条数据,user 插入两条数据

user表会比主库多一条数据。所以需要锁住select查询表中加next-key锁,不允许user2表中新增数据。

四、分析当前锁的情况

先说一下死锁的定义,死锁是指两个或两个以上的事务在执行过程中,因争夺资源而造成的一种互相等待的现象。这个定义适用于数据库,有几个重点,两个或两个以上的事务,一个事务是不会出现死锁的。争夺的资源一般都是表或者记录。

出现死锁了会怎样,正常情况下,mysql会检查出死锁,并回滚某一个事务,让另一个事务正常运行。

Mysql 会回滚副作用小的事务,判定的标准是执行的时间以及影响的范围。

1.如何知道系统有没有发生过死锁,如何去查看发生过的锁

img

show status like ‘innodb_row_lock%'; 从系统启动到现在的数据

Innodb_row_lock_current_waits:当前正在等待锁的数量;

Innodb_row_lock_time :锁定的总时间长度,单位ms;

Innodb_row_lock_time_avg :每次等待所花平均时间;

Innodb_row_lock_time_max:从系统启动到现在等待最长的一次所花的时间;

Innodb_row_lock_waits :从系统启动到现在总共等待的次数。

平均时间和锁等待次数比较大的话,说明可能会存在锁争用情况

2. show engine innodb status

img

展示innodb存储引擎的运行状态

通过这个命令显示的内容比较多,其中有一项lasted detected deadlock 显示最近发生的死锁。

图中红色线条标注的是执行的SQL,以及加了什么锁,可以看出是在这行记录上加了X锁,没有gap锁。

3. 错误日志中查看历史发生过的死锁

set global innodb_print_all_deadlocks=1;

上一个命令,只能看到最近发生的锁,如果我想看历史发生的锁怎么办? 执行这一句,更改innodb 的一个配置,innodb_print_all_deadlocks,打印所有的死锁。会将死锁的信息输出到mysql的错误日志中,默认是不输出,格式和show engine innodb status 是差不多的。

4. information_schema.innodb_locks

img

information_schema 数据库是mysql自带的,保存着关于MySQL服务器所维护的所有其他数据库的信息。其中innodb_locks表,记录了事务请求但是还没获得的锁,即等待获得的锁。

lock_id:锁的id,由锁住的空间id编号、页编号、行编号组成

lock_trx_id:锁的事务id。

lock_mode:锁的模式。S[,GAP], X[,GAP], IS[,GAP], IX[,GAP]

lock_type:锁的类型,表锁还是行锁

lock_table:要加锁的表。

lock_index:锁住的索引。

lock_space:innodb存储引擎表空间的id号码

lock_page:被锁住的页的数量,如果是表锁,则为null值。

lock_rec:被锁住的行的数量,如果表锁,则为null值。

lock_data:被锁住的行的主键值,如果表锁,则为null值。

5. information_schema.innodb_lock_waits

img

查看等待中的锁

requesting_trx_id:申请锁资源的事务id。

requested_lock_id:申请的锁的id。

blocking_trx_id:阻塞的事务id,当前拥有锁的事务ID。

blocking_lock_id:阻塞的锁的id,当前拥有锁的锁ID

6. information_schema.innodb_trx

img

查看已开启的事务

trx_id:innodb存储引擎内部事务唯一的事务id。

trx_state:当前事务的状态。

trx_started:事务开始的时间。

trx_requested_lock_id:等待事务的锁id,如trx_state的状态为LOCK WAIT,那么该值代表当前事务之前占用锁资源的id,如果trx_state不是LOCK WAIT的话,这个值为null。

trx_wait_started:事务等待开始的时间。

trx_weight:事务的权重,反映了一个事务修改和锁住的行数。在innodb的存储引擎中,当发生死锁需要回滚时,innodb存储引擎会选择该值最小的事务进行回滚。

trx_mysql_thread_id:正在运行的mysql中的线程id,show full processlist显示的记录中的thread_id。

trx_query:事务运行的sql语句

五、预防死锁

  1. 以相同的顺序更新不同的表

这样执行的话,会出现锁等待,但不容易出现死锁。

假设有这么两个接口,增加老师和学生的幸运值、减少老师和学生的幸运值,这个需求是我造出来的,先别管需求是不是合理。

img

现在有两个请求,一个增加幸运值,一个降低幸运值,如果更新顺序不同的话,就是这样,第一个事务先给老师加幸运值,第二个接口给学生减幸运值,然后第一个事务给学生加幸运值,因为锁已经被第二个事务持有了,所以第一个事务等待。然后第二个事务给老师幸运值,这时就互相等待锁,出现了死锁。

  1. 预先对数据进行排序

img

比如一个接口批量操作数据,如果乱序的话,并发的情况下,也是有可能出现死锁的。给学生批量加分的接口,按照表格中的执行顺序的话,第一个事务,持有A的锁,请求B的锁,第二个事务持有B的锁,请求A的锁,出现死锁。

  1. 直接申请足够级别的锁,而非先共享锁,再申请排他锁。

img

比如这种情况,两个事务,先申请共享锁,共享锁是兼容的,然后申请互斥锁的时候,需要互相等待,就出现了死锁。

  1. 事务的粒度及时间尽量保持小,这样锁冲突的概率就小了,也就不容易出现死锁。不建议在数据库的事务中执行API调用。

  2. 正确加索引。没有索引会引起全表扫描,类似于锁表。

六:总结:

1,正确的加索引,尽量先查询,然后使用主键去加锁,等于操作来加锁,而尽量避免辅助索引,或者不是范围比较来加锁。

2,出现了锁的问题,根据数据库已有的信息,分析死锁。

3,举了几个例子,可能很多都是上线之后才发现的,最好能在开发阶段就避免死锁。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/555057.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

显示器尺寸对照表_电脑显示器尺寸对照表一览,教你怎么选择最适合自己的显示器尺寸...

显示小课堂:显示器买大买小谁说了算? [本文来自:www.ii77.com]今天,笔者想和大家讨论一下关于显示器尺寸选择方面的问题。通过这两年显示器行业的发展我们不难看出,现在显示器的尺寸越来越大,三十几吋、四十…

MySQL事务隔离级别理解_解读MYSQL的可重复读、幻读及实现原理

前言 提到事务,你肯定不会陌生,最经典的例子就是转账,甲转账给乙100块,当乙的账户中到账100块的时候,甲的账户就应该减去100块,事务可以有效的做到这一点。 在MySQL中,事务支持实在引擎层实现的…

MySQL 是如何实现四大隔离级别的?

MySQL 是如何实现四大隔离级别的? 在mvcc下,mysql中用到的锁还是共享锁和排他锁么?如果是的话,那么是怎样结合锁和mvcc来实现rc和rr隔离级别的呢?还有mysql中在ru隔离级别下,两个事务同时读取数据对象A&am…

Linux命令 移动/复制文件/目录到指定目录下

1、同一个服务器下复制文件或文件夹 1.1 复制文件 复制文件:把1.txt 复制到根目录下的sbin目录 cp 文件名(可带路径)目标路径(带路径)如:cp 1.txt ~/sbin/1,2 复制目录 复制目录:把relea…

c mysql web开发实例教程_Web开发(六)MySql

数据库简介数据库(DB)数据库(database,DB)是指长期存储在计算机内的,有组织,可共享的数据的集合。数据库中的数据按一定的数学模型组织、描述和存储,具有较小的冗余,较高的数据独立性和易扩展性,并可为各种…

Git——工作中使用命令详解

1、Linux常用命令 cd:改变目录cd…:返回上级目录pwd:显示当前目录clear:清屏ls:显示当前目录所有文件touch:添加文件rm:删除文件mkdir:新建文件夹rm -r:删除文件夹mv&am…

Java中常见null简析

对于每一个Java程序员来说,null肯定是一个让人头痛的东西,今天就来总结一下Java中关于null的知识。 1.null不属于任何类型,可以被转换成任何类型,但是用instanceof永远返回false. 2.null永远不能和八大基本数据类型进行赋值运算等,否则不是编译出错,就是运行出错. 3.null可以…

Chrome浏览器F5和ctrl+F5的区别

一、正常重新加载(F5,Ctrl R,在地址栏回车,点击链接) 本节中的操作:根据缓存的缓存策略,进行处理。如果缓存没过期,就不向浏览器发请求,而是直接使用缓存。 F5或Contr…

mysql 自动生成mapper_自动生成实体类、Mapper、Mapper.xml文件

自动生成实体类、Mapper、Mapper.xml文件搭建Spring Boot Mysql MyBatis 项目核心配置pom.xml创建表配置文件生成文件结果项目结构搭建Spring Boot Mysql MyBatis 项目idea 可直接创建相应的项目及配置核心配置pom.xmlmysqlmysql-connector-java5.1.38org.springframework.…

使用Postman进行简单压力测试

使用Postman可以对服务端接口进行简单的压力测试,步骤如下: 1.配置好一个请求接口,保存在一个collection中; 2.点击Tests,添加断言检查点; 3.点击Runner按钮,打开Collection Runner界面&#…

mysql取消主从配置_mysql主从配置

搭建环境:master 192.168.127.131slave 192.168.127.128主从配置的前提:两个数据库的数据需要一模一样所以我们:在主上面建立一个数据库 在这里我们用mysql备份一下mysqldump db1 >123.sql (备份)在主上面建立一个数据库db1需要登录数据…

利用Java zip进行对文件的压缩和解压

利用Java JDK自带 进行对文件的压缩和解压 实现一个文件的zip压缩,过程可以简单地表示为: ZipEntry:表示 ZIP 文件条目 构造方法: public ZipEntry(String name) 可以用文件的相对路径来构造ZipEntry对象 ZipOutputStream: ZIP 文件格式…

mysql数据库设计教材_mySQL教程 第1章 数据库设计

E-R设计很多同学在学SQL语句时,觉得非常困难,那是因为你在学一个你根本不了解的数据库,数据库中的表不是你设计的,表与表之间的关系你不明白。因此在学SQL语句之前,先介绍一下数据库设计。下面举例说明数据库设计&…

谷歌浏览器Network详解

Network用F12打开后,出现以下页面。5个部分分别讲解。 控制器过滤器时间轴资源内容资源概况 1.控制器 Preserve log:页面刷新也不会清空请求 Disable cache:停用浏览器缓存 Online:有网 Fast 3G、Slow 3G:自定义网速 Offline:离线模拟 2.过滤器 2.1按字符串过…

mysql5.7.14安装版_MySql5.7.14安装教程详解(解压版)_MySQL

下面进入正式的教程:第一步:下载最近的MySQL文件并且解压:下载最新版的MySQL–mysql-5.7.12下载地址将下载到的文件解压缩到自己喜欢的位置,例如我自己的位置是D:\MySQL\mysql-5.7.12-winx64第二步:配置环境变量这里不…

Java main方法_解释Java中的main方法,及其作用_一个java文件中可包含多个main方法

public static void main(String[] args) {}或者 public static void main(String args[]) {}main方法是我们学习Java语言学习的第一个方法,也是每个java使用者最熟悉的方法,每个Java应用程序都必须有且仅有一个main方法。在eclipse里可以使用输入main,…

端口号被占用:Disconnected from the target VM, address: ‘127.0.0.1:XXXX‘, transport: ‘socket‘

debug启动Spring boot项目的时候,项目没有启动起来。log最后一行,显示Disconnected from the target VM, address: ‘127.0.0.1:XXXX’, transport: ‘socket’。 解决方式!!! 1、看看是谁占用了我的端口号&#xff…

Linux系统tab自动补全快捷键的时候显示cannot create temp file for here-document: No space left on device解决方案

登陆linux系统之后,使用tab自动补全快捷键的时候显示:cannot create temp file for here-document: No space left on device。 原因:磁盘满了,不能创建临时文件。 解决方法:(逐级查看占用空间过多的目录…

python画二维数组散点图_2个numpy二维数组的散点图

IIUC,你不需要zip步骤:s (arr1.ravel(), arr2.ravel())plt.scatter(*s)plt.show()或者,你也可以通过策划arr1和arr2:plt.scatter(arr1, arr2)plt.show()原因是,通过压缩,可以创建许多坐标元组:>>> list(zip(*s))[(0.5233576831070681, 0.3622905772322086), (0.67714…

双表联查mysql_MySQL的双表多表联查

最近在做EC-Mall的二次开发,遇到这么一个需求,将挂件单独显示成一个页面。由于EC-Mall的挂件是用数据模块模块类库的方式进行的,就是使用类似smarty的形式。而单独一个页面的话,数据读取需要自己写SQL语句。 现在的问题是&#xf…