侧边栏壁纸
博主头像
春潮带雨晚来急博主等级

行动起来,活在当下

  • 累计撰写 32 篇文章
  • 累计创建 1 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

重学mysql

Administrator
2023-12-26 / 0 评论 / 0 点赞 / 47 阅读 / 24598 字

#### 主键 超键 候选键 外键

###### 主 键:

数据库表中对储存数据对象予以唯一和完整标识的数据列或属性的组合。一个数据列只能有一个主键,且主键的取值不能缺失,即不能为空值(Null)。

###### 超 键:

在关系中能唯一标识元组的属性集称为关系模式的超键。一个属性可以为作为一个超键,多个属性组合在一起也可以作为一个超键。超键包含候选键和主键。

###### 候选键:

是最小超键,即没有冗余元素的超键。

###### 外 键:

在一个表中存在的另一个表的主键称此表的外键。

---

##### 数据库事务的四个特性及含义

数据库事务transanction正确执行的四个基本要素。ACID,原子性(Atomicity)、一致性(Correspondence)、隔离性(Isolation)、持久性(Durability)。

- 原子性: 整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

- 一致性: 在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。

- 隔离性: 隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行 相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请 求,使得在同一时间仅有一个请求用于同一数据。

- 持久性: 在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。

---

#### Mysql存储引擎

---

##### InnoDB存储引擎

- [x] InnoDB是事务型数据库的首选引擎,支持事务安全表(ACID),支持行锁定和外键,上图也看到了,InnoDB是默认的MySQL引擎。InnoDB主要特性有:

1、InnoDB给MySQL提供了具有提交、回滚和崩溃恢复能力的事物安全(ACID兼容)存储引擎。InnoDB锁定在行级并且也在SELECT语句中提供一个类似Oracle的非锁定读。这些功能增加了多用户部署和性能。在SQL查询中,可以自由地将InnoDB类型的表和其他MySQL的表类型混合起来,甚至在同一个查询中也可以混合

2、InnoDB是为处理巨大数据量的最大性能设计。它的CPU效率可能是任何其他基于磁盘的关系型数据库引擎锁不能匹敌的

3、InnoDB存储引擎完全与MySQL服务器整合,InnoDB存储引擎为在主内存中缓存数据和索引而维持它自己的缓冲池。InnoDB将它的表和索引在一个逻辑表空间中,表空间可以包含数个文件(或原始磁盘文件)。这与MyISAM表不同,比如在MyISAM表中每个表被存放在分离的文件中。InnoDB表可以是任何尺寸,即使在文件尺寸被限制为2GB的操作系统上

4、InnoDB支持外键完整性约束,存储表中的数据时,每张表的存储都按主键顺序存放,如果没有显示在表定义时指定主键,InnoDB会为每一行生成一个6字节的ROWID,并以此作为主键

5、InnoDB被用在众多需要高性能的大型数据库站点上

- [x] InnoDB不创建目录,使用InnoDB时,MySQL将在MySQL数据目录下创建一个名为ibdata1的10MB大小的自动扩展数据文件,以及两个名为ib_logfile0和ib_logfile1的5MB大小的日志文件

##### MyISAM存储引擎

- [x] MyISAM基于ISAM存储引擎,并对其进行扩展。它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM拥有较高的插入、查询速度,但不支持事物。MyISAM主要特性有:

1、大文件(达到63位文件长度)在支持大文件的文件系统和操作系统上被支持

2、当把删除和更新及插入操作混合使用的时候,动态尺寸的行产生更少碎片。这要通过合并相邻被删除的块,以及若下一个块被删除,就扩展到下一块自动完成

3、每个MyISAM表最大索引数是64,这可以通过重新编译来改变。每个索引最大的列数是16

4、最大的键长度是1000字节,这也可以通过编译来改变,对于键长度超过250字节的情况,一个超过1024字节的键将被用上

5、BLOB和TEXT列可以被索引

6、NULL被允许在索引的列中,这个值占每个键的0~1个字节

7、所有数字键值以高字节优先被存储以允许一个更高的索引压缩

8、每个MyISAM类型的表都有一个AUTO_INCREMENT的内部列,当INSERT和UPDATE操作的时候该列被更新,同时AUTO_INCREMENT列将被刷新。所以说,MyISAM类型表的AUTO_INCREMENT列更新比InnoDB类型的AUTO_INCREMENT更快

9、可以把数据文件和索引文件放在不同目录

10、每个字符列可以有不同的字符集

11、有VARCHAR的表可以固定或动态记录长度

12、VARCHAR和CHAR列可以多达64KB

- [x] 使用MyISAM引擎创建数据库,将产生3个文件。文件的名字以表名字开始,扩展名之处文件类型:frm文件存储表定义、数据文件的扩展名为.MYD(MYData)、索引文件的扩展名时.MYI(MYIndex)

##### MEMORY存储引擎

- [x] MEMORY存储引擎将表中的数据存储到内存中,未查询和引用其他表数据提供快速访问。MEMORY主要特性有:

1、MEMORY表的每个表可以有多达32个索引,每个索引16列,以及500字节的最大键长度

2、MEMORY存储引擎执行HASH和BTREE缩影

3、可以在一个MEMORY表中有非唯一键值

4、MEMORY表使用一个固定的记录长度格式

5、MEMORY不支持BLOB或TEXT列

6、MEMORY支持AUTO_INCREMENT列和对可包含NULL值的列的索引

7、MEMORY表在所由客户端之间共享(就像其他任何非TEMPORARY表)

8、MEMORY表内存被存储在内存中,内存是MEMORY表和服务器在查询处理时的空闲中,创建的内部表共享

9、当不再需要MEMORY表的内容时,要释放被MEMORY表使用的内存,应该执行DELETE FROM或TRUNCATE TABLE,或者删除整个表(使用DROP TABLE)

##### 存储引擎的选择

功 能 | MYISAM | Memory | InnoDB | Archive

---|---|---|---|---

存储限制 | 256TB | RAM | 64TB | None

支持事物 | NO | NO | YES | NO

支持全文索引 | YES | NO | NO | NO

支持数索引 | YES | YES | YES | NO

支持哈希索引| NO | YES | NO | NO

支持数据缓存 | NO | NO |YES | NO

支持外键 | NO | NO | YES | NO

---

#### MySQL的复制原理以及流程

###### (1)、复制基本原理流程

- 1 . 主:binlog线程——记录下所有改变了数据库数据的语句,放进master上的binlog中;

- 2 . 从:io线程——在使用start slave 之后,负责从master上拉取 binlog 内容,放进 自己的relay log中;

- 3 . 从:sql执行线程——执行relay log中的语句;

##### (2)、MySQL复制的线程有几个及之间的关联

MySQL 的复制是基于如下 3 个线程的交互( 多线程复制里面应该是 4 类线程):

- 1 . Master 上面的 binlog dump 线程,该线程负责将 master 的 binlog event 传到slave;

- 2 . Slave 上面的 IO 线程,该线程负责接收 Master 传过来的 binlog,并写入 relay log;

- 3 . Slave 上面的 SQL 线程,该线程负责读取 relay log 并执行;

- 4 . 如果是多线程复制,无论是 5.6 库级别的假多线程还是 MariaDB 或者 5.7 的真正的多线程复制, SQL 线程只做 coordinator,只负责把 relay log 中的 binlog读出来然后交给 worker 线程, woker 线程负责具体 binlog event 的执行;

##### (3)、MySQL如何保证复制过程中数据一致性及减少数据同步延时

###### 一致性主要有以下几个方面:

- 1 . 在 MySQL5.5 以及之前, slave 的 SQL 线程执行的 relay log 的位置只能保存在文件( relay-log.info)里面,并且该文件默认每执行 10000 次事务做一次同步到磁盘, 这意味着 slave 意外 crash 重启时, SQL 线程执行到的位置和数据库的数据是不一致的,将导致复制报错,如果不重搭复制,则有可能会

导致数据不一致。 MySQL 5.6 引入参数 relay_log_info_repository,将该参数设置为 TABLE 时, MySQL 将 SQL 线程执行到的位置存到mysql.slave_relay_log_info 表,这样更新该表的位置和 SQL 线程执行的用户事务绑定成一个事务,这样 slave 意外宕机后, slave 通过 innodb 的崩溃

恢复可以把 SQL 线程执行到的位置和用户事务恢复到一致性的状态。

- 2 . MySQL 5.6 引入 GTID 复制,每个 GTID 对应的事务在每个实例上面最多执行一次, 这极大地提高了复制的数据一致性;

- 3 . MySQL 5.5 引入半同步复制, 用户安装半同步复制插件并且开启参数后,设置超时时间,可保证在超时时间内如果 binlog 不传到 slave 上面,那么用户提交事务时不会返回,直到超时后切成异步复制,但是如果切成异步之前用户线程提交时在 master 上面等待的时候,事务已经提交,该事务对 master

上面的其他 session 是可见的,如果这时 master 宕机,那么到 slave 上面该事务又不可见了,该问题直到 5.7 才解决;

- 4 . MySQL 5.7 引入无损半同步复制,引入参 rpl_semi_sync_master_wait_point,该参数默认为 after_sync,指的是在切成半同步之前,事务不提交,而是接收到 slave 的 ACK 确认之后才提交该事务,从此,复制真正可以做到无损的了。

- 5 . 可以再说一下 5.7 的无损复制情况下, master 意外宕机,重启后发现有 binlog没传到 slave 上面,这部分 binlog 怎么办???分 2 种情况讨论, 1 宕机时已经切成异步了, 2 是宕机时还没切成异步??? 这个怎么判断宕机时有没有切成异步呢??? 分别怎么处理???

###### 延时性:

- [x] 5.5 是单线程复制, 5.6 是多库复制(对于单库或者单表的并发操作是没用的), 5.7 是真正意义的多线程复制,它的原理是基于 group commit, 只要

master 上面的事务是 group commit 的,那 slave 上面也可以通过多个 worker线程去并发执行。 和 MairaDB10.0.0.5 引入多线程复制的原理基本一样。

#### MySQL中myisam与innodb的区别,至少5点

- 1.InnoDB支持事物,而MyISAM不支持事物

- 2.InnoDB支持行级锁,而MyISAM支持表级锁

- 3.InnoDB支持MVCC, 而MyISAM不支持

- 4.InnoDB支持外键,而MyISAM不支持

- 5.InnoDB不支持全文索引,而MyISAM支持。

- 6.InnoDB不能通过直接拷贝表文件的方法拷贝表到另外一台机器, myisam 支持

- 7.InnoDB表支持多种行格式, myisam 不支持

- 8.InnoDB是索引组织表, myisam 是堆表

###### innodb引擎的4大特性

- 1.插入缓冲(insert buffer)

- 2.二次写(double write)

- 3.自适应哈希索引(ahi)

- 4.预读(read ahead)

###### 各种不同 mysql 版本的Innodb的改进

```

MySQL5.6 下 Innodb 引擎的主要改进:

( 1) online DDL

( 2) memcached NoSQL 接口

( 3) transportable tablespace( alter table discard/import tablespace)

( 4) MySQL 正常关闭时,可以 dump 出 buffer pool 的( space, page_no),重启时 reload,加快预热速度

( 5) 索引和表的统计信息持久化到 mysql.innodb_table_stats 和mysql.innodb_index_stats,可提供稳定的执行计划

( 6) Compressed row format 支持压缩表

MySQL 5.7 innodb 引擎主要改进

( 1) 修改 varchar 字段长度有时可以使用 online DDL

( 2) Buffer pool 支持在线改变大小

( 3) Buffer pool 支持导出部分比例

( 4) 支持新建 innodb tablespace,并可以在其中创建多张表

( 5) 磁盘临时表采用 innodb 存储,并且存储在 innodb temp tablespace 里面,以前是 myisam 存储

( 6) 透明表空间压缩功能

```

###### 2者select count(*)哪个更快,为什么

- myisam更快,因为myisam内部维护了一个计数器,可以直接调取。

###### 2 者的索引的实现方式

- 都是 B+树索引, Innodb 是索引组织表, myisam 是堆表, 索引组织表和堆表的区别要熟悉

##### innodb的事务与日志的实现方式

###### 有多少种日志

- redo和undo

###### 日志的存放形式

- redo:在页修改的时候,先写到 redo log buffer 里面, 然后写到 redo log 的文件系统缓存里面(fwrite),然后再同步到磁盘文件( fsync)。

- Undo:在 MySQL5.5 之前, undo 只能存放在 ibdata*文件里面, 5.6 之后,可以通过设置 innodb_undo_tablespaces 参数把 undo log 存放在 ibdata*之外。

###### 事务是如何通过日志来实现的

- [x] 因为事务在修改页时,要先记 undo,在记 undo 之前要记 undo 的 redo, 然后修改数据页,再记数据页修改的 redo。 Redo(里面包括 undo 的修改) 一定要比数据页先持久化到磁盘。 当事务需要回滚时,因为有 undo,可以把数据页回滚到前镜像的

状态,崩溃恢复时,如果 redo log 中事务没有对应的 commit 记录,那么需要用 undo把该事务的修改回滚到事务开始之前。 如果有 commit 记录,就用 redo 前滚到该事务完成时并提交掉。

##### MySQL binlog的几种日志录入格式以及区别

```

1.Statement:每一条会修改数据的sql都会记录在binlog中。

优点:不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能。(相比row能节约多少性能 与日志量,这个取决于应用的SQL情况,正常同一条记录修改或者插入row格式所产生的日志量还小于Statement产生的日志量,

但是考虑到如果带条 件的update操作,以及整表删除,alter表等操作,ROW格式会产生大量日志,因此在考虑是否使用ROW格式日志时应该跟据应用的实际情况,其所 产生的日志量会增加多少,以及带来的IO性能问题。)

缺点:由于记录的只是执行语句,为了这些语句能在slave上正确运行,因此还必须记录每条语句在执行的时候的 一些相关信息,以保证所有语句能在slave得到和在master端执行时候相同 的结果。另外mysql 的复制,

像一些特定函数功能,slave可与master上要保持一致会有很多相关问题(如sleep()函数, last_insert_id(),以及user-defined functions(udf)会出现问题).

使用以下函数的语句也无法被复制:

* LOAD_FILE()

* UUID()

* USER()

* FOUND_ROWS()

* SYSDATE() (除非启动时启用了 --sysdate-is-now 选项)

同时在INSERT ...SELECT 会产生比 RBR 更多的行级锁

2.Row:不记录sql语句上下文相关信息,仅保存哪条记录被修改。

优点: binlog中可以不记录执行的sql语句的上下文相关的信息,仅需要记录那一条记录被修改成什么了。所以rowlevel的日志内容会非常清楚的记录下 每一行数据修改的细节。而且不会出现某些特定情况下的存储过程,或function,以及trigger的调用和触发无法被正确复制的问题

缺点:所有的执行的语句当记录到日志中的时候,都将以每行记录的修改来记录,这样可能会产生大量的日志内容,比 如一条update语句,修改多条记录,则binlog中每一条修改都会有记录,这样造成binlog日志量会很大,特别是当执行alter table之类的语句的时候,

由于表结构修改,每条记录都发生改变,那么该表每一条记录都会记录到日志中。

3.Mixedlevel: 是以上两种level的混合使用,一般的语句修改使用statment格式保存binlog,如一些函数,statement无法完成主从复制的操作,则 采用row格式保存binlog,MySQL会根据执行的每一条具体的sql语句来区分对待记录的日志形式,

也就是在Statement和Row之间选择 一种.新版本的MySQL中队row level模式也被做了优化,并不是所有的修改都会以row level来记录,像遇到表结构变更的时候就会以statement模式来记录。至于update或者delete等修改数据的语句,还是会记录所有行的变更。

```

#### sql优化

##### (1)、explain出来的各种item的意义

```

id:每个被独立执行的操作的标志,表示对象被操作的顺序。一般来说, id 值大,先被执行;如果 id 值相同,则顺序从上到下。

select_type:查询中每个 select 子句的类型。

table:名字,被操作的对象名称,通常的表名(或者别名),但是也有其他格式。

partitions:匹配的分区信息。

type:join 类型。

possible_keys:列出可能会用到的索引。

key:实际用到的索引。

key_len:用到的索引键的平均长度,单位为字节。

ref:表示本行被操作的对象的参照对象,可能是一个常量用 const 表示,也可能是其他表的

key 指向的对象,比如说驱动表的连接列。

rows:估计每次需要扫描的行数。

filtered:rows*filtered/100 表示该步骤最后得到的行数(估计值)。

extra:重要的补充信息。

```

##### (2)、profile的意义以及使用场景

```

Profile 用来分析 sql 性能的消耗分布情况。当用 explain 无法解决慢 SQL 的时候,需要用profile 来对 sql 进行更细致的分析,找出 sql 所花的时间大部分消耗在哪个部分,确认 sql的性能瓶颈。

```

##### (3)、explain 中的索引问题

- Explain 结果中,一般来说,要看到尽量用 index(type 为 const、 ref 等, key 列有值),避免使用全表扫描(type 显式为 ALL)。比如说有 where 条件且选择性不错的列,需要建立索引。

- 被驱动表的连接列,也需要建立索引。被驱动表的连接列也可能会跟 where 条件列一起建立联合索引。当有排序或者 group by 的需求时,也可以考虑建立索引来达到直接排序和汇总的需求。

##### mysqldump和xtrabackup实现原理

- mysqldump

- [x] mysqldump 属于逻辑备份。加入--single-transaction 选项可以进行一致性备份。后台进程会先设置 session 的事务隔离级别为 RR(SET SESSION TRANSACTION ISOLATION LEVELREPEATABLE READ),

之后显式开启一个事务(START TRANSACTION /*!40100 WITH CONSISTENTSNAPSHOT */),这样就保证了该事务里读到的数据都是事务事务时候的快照。之后再把表的数据读取出来。 如果加上--master-data=1 的话,在刚开始的时候还会加一个数据库的读锁

(FLUSH TABLES WITH READ LOCK),等开启事务后,再记录下数据库此时 binlog 的位置(showmaster status),马上解锁,再读取表的数据。等所有的数据都已经导完,就可以结束事务

- Xtrabackup

- [x] xtrabackup 属于物理备份,直接拷贝表空间文件,同时不断扫描产生的 redo 日志并保存下来。最后完成 innodb 的备份后,会做一个 flush engine logs 的操作(老版本在有 bug,在5.6 上不做此操作会丢数据),确保所有的 redo log 都已经落盘(涉及到事务的两阶段提交

概念,因为 xtrabackup 并不拷贝 binlog,所以必须保证所有的 redo log 都落盘,否则可能会丢最后一组提交事务的数据)。这个时间点就是 innodb 完成备份的时间点,数据文件虽然不是一致性的,但是有这段时间的 redo 就可以让数据文件达到一致性(恢复的时候做的事

情)。然后还需要 flush tables with read lock,把 myisam 等其他引擎的表给备份出来,备份完后解锁。 这样就做到了完美的热备。

#### innodb的读写参数优化

##### (1)、读取参数

```

global buffer 以及 local buffer;

Global buffer:

Innodb_buffer_pool_size

innodb_log_buffer_size

innodb_additional_mem_pool_size

local buffer(下面的都是 server 层的 session 变量,不是 innodb 的):

Read_buffer_size

Join_buffer_size

Sort_buffer_size

Key_buffer_size

Binlog_cache_size

```

##### (2)、写入参数

```

innodb_flush_log_at_trx_commit

innodb_buffer_pool_size

insert_buffer_size

innodb_double_write

innodb_write_io_thread

innodb_flush_method

```

##### (3)、与IO相关的参数

```

innodb_write_io_threads = 8

innodb_read_io_threads = 8

innodb_thread_concurrency = 0

Sync_binlog

Innodb_flush_log_at_trx_commit

Innodb_lru_scan_depth

Innodb_io_capacity

Innodb_io_capacity_max

innodb_log_buffer_size

innodb_max_dirty_pages_pct

```

---

---

---

#### 数据库范式

##### 1 第一范式(1NF)

- [x] 在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库。

所谓第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多关系。在第一范式(1NF)中表的每一行只包含一个实例的信息。简而言之,**第一范式就是无重复的列。**

##### 2 第二范式(2NF)

- [x] 第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或行必须可以被惟一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。这个惟一属性列被称为主关键字或主键、主码。

第二范式(2NF)要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。简而言之,**第二范式就是非主属性非部分依赖于主关键字。**

##### 3 第三范式(3NF)

- [x] 满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。例如,存在一个部门信息表,其中每个部门有部门编号(dept_id)、部门名称、部门简介等信息。那么在员工信息表中列出部门编号后就不能再将部门名称、部门简介等与部门有关的信息再加入员工信息表中。如果不存在部门信息表,则根据第三范式(3NF)也应该构建它,否则就会有大量的数据冗余。简而言之,第三范式就是属性不依赖于其它非主属性。**(我的理解是消除冗余)**

---

---

---

##### 事务的并发问题

1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

  2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。

  3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

##### 事务的隔离性(ISOLATION):

SQL标准中定义的四种隔离级别

- 未提交读 (READ UNCOMMITED)

- 已提交读 (READ COMMITED)

- 可重复读 (REPEATABLE READ)

- 可串行化 (SERIALIZABLE) (会在执行的每一行上面加锁)

隔离性:由低到高 并发性:由高到低

事务隔离级别 | 脏读 | 不可重复读 | 幻读

---|---|---|---

读未提交(read-uncommitted) | Y | Y | Y

不可重复读(read-committed) | N | Y | Y

可重复读(repeatable-read) | N | N | Y

串行化(serializable) | N | N | N

---

### ++spring事物++

##### spring支持编程式事务管理和声明式事务管理两种方式

- 编程式事务

```

编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。对于编程式事务管理,spring推荐使用TransactionTemplate。

```

- 声明式事务

```

声明式事务管理建立在AOP之上的。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。声明式事务最大的优点就是不需要通过编程的方式管理事务,这样就不需要在业务逻辑代码中掺杂事务管理的代码,只需在配置文件中做相关的事务规则声明(或通过基于@Transactional注解的方式),便可以将事务规则应用到业务逻辑中。

```

- [x] 显然声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式。声明式事务管理使业务代码不受污染,一个普通的POJO对象,只要加上注解就可以获得完全的事务支持。和编程式事务相比,声明式事务唯一不足地方是,后者的最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。但是即便有这样的需求,也存在很多变通的方法,比如,可以将需要进行事务管理的代码块独立为方法等等。

- 声明式事务管理也有两种常用的方式,一种是基于tx和aop名字空间的xml配置文件,另一种就是基于@Transactional注解。显然基于注解的方式更简单易用,更清爽。

##### spring事务特性

- spring所有的事务管理策略类都继承自org.springframework.transaction.PlatformTransactionManager接口

- 其中TransactionDefinition接口定义以下特性:

###### 事务隔离级别

隔离级别是指若干个并发的事务之间的隔离程度。TransactionDefinition 接口中定义了五个表示隔离级别的常量:

- TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。

- TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别。

- TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。

- TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。

- TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

###### 事务传播行为

所谓事务的传播行为是指,如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:

- TransactionDefinition.PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。

- TransactionDefinition.PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则把当前事务挂起。

- TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。

- TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。

- TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。

- TransactionDefinition.PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

- TransactionDefinition.PROPAGATION_NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

###### 事务超时

所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒。

###### 事务只读属性

只读事务用于客户代码只读但不修改数据的情形,只读事务用于特定情景下的优化,比如使用Hibernate的时候。

默认为读写事务。

- [x] “只读事务”并不是一个强制选项,它只是一个“暗示”,提示数据库驱动程序和数据库系统,这个事务并不包含更改数据的操作,那么JDBC驱动程序和数据库就有可能根据这种情况对该事务进行一些特定的优化,比方说不安排相应的数据库锁,以减轻事务对数据库的压力,毕竟事务也是要消耗数据库的资源的。

- [x] 但是你非要在“只读事务”里面修改数据,也并非不可以,只不过对于数据一致性的保护不像“读写事务”那样保险而已。

- [x] 因此,“只读事务”仅仅是一个性能优化的推荐配置而已,并非强制你要这样做不可

##### spring事务回滚规则

指示spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。

默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。可以明确的配置在抛出那些异常时回滚事务,**==包括checked异常==**。也可以明确定义那些异常抛出时不回滚事务。还可以编程性的通过setRollbackOnly()方法来指示一个事务必须回滚,在调用完setRollbackOnly()后你所能执行的唯一操作就是回滚。

- myBatis为例 基于注解的声明式事务管理配置@Transactional

- spring.xml:

```

<span style="background-color: rgb(255, 255, 255);"><span style="background-color: rgb(255, 204, 153);"><!-- mybatis config -->

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

<property name="dataSource" ref="dataSource" />

<property name="configLocation">

<value>classpath:mybatis-config.xml</value>

</property>

</bean>

<!-- mybatis mappers, scanned automatically -->

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

<property name="basePackage">

<value>

com.baobao.persistence.test

</value>

</property>

<property name="sqlSessionFactory" ref="sqlSessionFactory" />

</bean>

<!-- 配置spring的PlatformTransactionManager,名字为默认值 -->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSource" />

</bean>

<!-- 开启事务控制的注解支持 -->

<tx:annotation-driven transaction-manager="transactionManager"/></span></span>

```

MyBatis自动参与到spring事务管理中,无需额外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的数据源与DataSourceTransactionManager引用的数据源一致即可,否则事务管理会不起作用。

用法:

- @Transactional 可以作用于接口、接口方法、类以及类方法上。当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。

- 虽然 @Transactional 注解可以作用于接口、接口方法、类以及类方法上,但是 Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。另外, @Transactional 注解应该只被应用到 public 方法上,这是由 Spring AOP 的本质决定的。如果你在 protected、private 或者默认可见性的方法上使用 @Transactional 注解,这将被忽略,也不会抛出任何异常。

- 默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰。

++*myBatis为例 基于注解的声明式事务管理配置,xml配置*++

主要为aop切面配置,只看xml就可以了

```

<!-- 事物切面配置 -->

<tx:advice id="advice" transaction-manager="transactionManager">

<tx:attributes>

<tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>

<tx:method name="insert" propagation="REQUIRED" read-only="false"/>

</tx:attributes>

</tx:advice>

<aop:config>

<aop:pointcut id="testService" expression="execution (* com.baobao.service.MyBatisService.*(..))"/>

<aop:advisor advice-ref="advice" pointcut-ref="testService"/>

</aop:config>

```

---

<code>查询事务的隔离级别</code>:

```

show variables like '%iso%';

```

<code>设置事务的模式:</code>

```

set session tx_isolation = 'read-committed' ;

```

<code>查看数据库默认使用哪个引擎:</code>

```

SHOW VARIABLES LIKE 'storage_engine';

```

第一章:

###### 大表对DDL操作的影响:

- 修改表结构会长时间的锁表

- 会造成长时间的主从延迟

- 影响正常的数据操作

###### 处理方式:

- 分库分表

###### 打事务的影响

定义: 运行时间较长、操作的数据比较多的事务

风险:

- 锁定太多的数据,造成大量的阻塞和锁超时

- 回滚时所需时间较长

- 执行时间长,容易造成主从延迟

处理:

- 1.避免一次处理太多的数据

- 2.移除不必要在事务中的SELECT操作

---

第2章 什么影响了MySQL性能

- 1.硬件

- 2.服务器系统

- 3.存储引擎(MyISAM:不支持事务、表级锁;InnoDB:事务级存储引擎、完美支持行级锁、事务ACID特性)

- 4.数据库服务器的配置参数

- 5.数据库结构设计和SQL语句

header 1 | header 2 | header 3 | header 4 | header 5 | header 6

---|---|---|---|---|---

row 1 col 1 | row 1 col 2 | row 1 col 3 | row 1 col 4 | row 1 col 5 | row 1 col 6

row 2 col 1 | row 2 col 2 | row 2 col 3 | row 2 col 4 | row 2 col 5 | row 2 col 6

row 3 col 1 | row 3 col 2 | row 3 col 3 | row 3 col 4 | row 3 col 5 | row 2 col 6

row 4 col 1 | row 4 col 2 | row 4 col 3 | row 4 col 4 | row 4 col 5 | row 4 col 6

row 5 col 1 | row 5 col 2 | row 5 col 3 | row 5 col 4 | row 5 col 5 | row 5 col 6

0

评论区