湖州外贸网站建设,wordpress小吃模版,网络服务商不提供哪项服务,公司图标大全20岁的男生穷困潦倒#xff0c;20岁的女生风华正茂#xff0c;没有人会一直风华正茂#xff0c;也没有人会一直穷困潦倒… 文章目录 一、MySQL索引特性#xff08;重点#xff09;1.磁盘、OS、MySQL#xff0c;在进行数据IO时三者的关系2.索引的理解3.聚簇索引#xff0…20岁的男生穷困潦倒20岁的女生风华正茂没有人会一直风华正茂也没有人会一直穷困潦倒… 文章目录 一、MySQL索引特性重点1.磁盘、OS、MySQL在进行数据IO时三者的关系2.索引的理解3.聚簇索引索引和数据放在一起和非聚簇索引索引和数据分离存储4.索引的操作 二、MySQL事务管理重点1.什么是事务2.事务常见操作方式3.事务隔离级别4.MVCC提高读写并发时数据库的性能5.RR与RC的本质区别 三、MySQL视图特性四、MySQL用户管理五、API和图形化界面的客户端 一、MySQL索引特性重点
1.磁盘、OS、MySQL在进行数据IO时三者的关系
1. MySQL给用户提供存取数据的服务但数据在linux机器的磁盘外设上进行存储而磁盘的读取效率是比较低的MySQL如何进行数据存取以提高效率呢这是一个重要的话题。 在硬件层面上数据块的基本单位是一个512字节的扇区但OS在和磁盘进行IO时难道就直接以扇区为基本单位进行数据IO了吗当然不是如果系统直接以硬件提供的扇区大小进行交互则OS的IO代码就会和硬件强相关但我们并不希望耦合度的提升因为一旦耦合度较高硬件改变软件代码也得随之改变。同时单次IO大小为512字节还是太小了这会增加IO的次数从而导致效率降低而实际OS的文件系统的基本IO单位并不是扇区而是以块为单位基本大小是4KB也就是每次读写8个扇区的大小。 而MySQL在和磁盘进行交互时基本数据单元的大小为16KB在MySQL这里叫做page(注意和系统的page作区分系统的page页是4KB)虽然我们说的是MySQL和磁盘进行交互但能和磁盘进行交互的软件层肯定只有操作系统所以MySQL和磁盘每次进行16KB大小的page交互MySQL中的数据文件都是以page为单位保存在磁盘当中的。 MySQL服务器在内存中运行时服务器内部会申请一大块buffer pool的内存空间来进行各种数据文件page的缓存也就是通过OS来和磁盘进行IO交互而OS实际在和磁盘进行IO时的单位是4KB但MySQL不管这些事情MySQL只认为自己和磁盘进行交互时就是以16KB大小为单位进行交互的。 2.索引的理解
1. 下面是我创建的具有主键索引的一张表user在插入数据时实际我是对id进行乱序插入的但在查询时所有记录却变成有序的了。这个工作是谁做的呢这么做的原因又是什么呢 2. 为何MySQL与磁盘IO交互的基本单位是page呢用多少加载多少不行吗这样当然是不行的如果你要查询id为1的记录那就需要一次IO而查询整表的数据就需要进行5次IO这样的效率会非常低。如果将表中的多条记录保存在一个page里面实际IO时直接将一个page加载到buffer pool里面这样在后面查询的时候就不用再进行IO了直接在内存中的buffer pool进行读取就可以而且根据局部性原理下一次访问的数据大概率同样也在该page里面那下一次进行读取时大概率不用在进行IO了直接在当前buffer pool中的page内读取数据就可以了这样的效率就会高了因为我们知道导致IO效率低下的主要原因不是单次IO数据的大小而是IO的次数多少因为硬件与软件相比时间上要差别很多。
3. 我们在理解page时同样不能简单的的将page理解为一个存储数据的内存块page可以理解为一个结构体对象保存着表中的一部分数据每个page之间用数据结构连接起来统一进行管理。 单个page内部的数据存储是按照有序的方式来进行排序的其实就是用链表的方式将有序的数据一个个连接起来。 4. 我们知道了单个page内部的记录之间是按照链表进行连接的此时在查找某条记录的时候就需要逐条遍历进行查找比如先一个一个的遍历page在每个page的内部在逐个记录的进行遍历与每个记录进行比较直到比较查找出要搜索的记录这样的效率一定是非常低的。因为无论是page间还是page内部我们都需要线性遍历直到通过比较找到要查找的记录。 5. 所以为了提升查找的速度需要引入页目录的概念通过目录来快速定位记录的位置本身比如一本书有500页其中有50条目录每个目录分别管理10页的内容则50条目录就可以管理整本书以前查找某一页的内容最坏需要查找500次现在你最多需要查找60次先遍历目录然后再遍历目录所管理的10个页所以最坏也就是查找60次这样不就提升了查找的效率吗 6. 所以为了提升查找的效率我们可以在单个page内部引入页目录以提高在page内部查找记录时的效率。所以这也就可以解释为什么当我们创建具有主键索引的表的时候插入数据记录是默认有序的呢其实就是为了提高搜索效率因为只有当记录是有序的时候目录才有意义。 而当表存储的数据过多时单个page的大小固定是16KB则一定需要多个page来存储对应的数据多个page之间我们也用链表管理起来但page之间进行线性遍历的时候也会造成效率低下的问题因为page在线性遍历的时候是需要进行磁盘IO的磁盘IO更费时间那如何解决这个问题呢还是之前的思路引入页目录 我们可以在多个page的基础上再加入存储页目录的page而此时每个page内部不再存储数据而是只存储目录项每个目录项存储每个普通page的最小键值和目录页的地址所以原来普通页中存储的数据是用户数据而目录页中存储的数据是普通页中的最小键值和普通页的地址每个普通page之间的键值也必须是有序的因为目录页要对多个page进行管理。 如果顶层的目录页过多还需要进行遍历的话则我们还可以在目录页的基础上再次增加目录页对第二层的目录页进行管理。
一个page能够保存的数据大小是16KB一个page所占字节数其实也就是16字节也就是四个指针prev和next指向前后的page一个指针指向存储用户数据的链表的头结点另一个指针指向页目录的头结点所以一个目录页能够管理的page个数就是16×1024÷16也就是1024个page转换成数据的计量单位就是1024个16KB也就是16MB的数据最上层的目录页能够管理的第二层的目录页的个数是1024个页目录所以像上面的这样一棵B树最多管理的数据就是1024×16MB的数据也就是16GB的数据。
7. 真实的B树只有叶子结点之间用链表连接起来非叶子结点之间并无连接关系通常在查找时我们都会进行范围查找叶子节点之间连接起来的话是比较方便进行范围查找的如果不连接起来则如果当前查找的叶子结点不是目标叶子节点的话则还需要重新自顶向下进行查找直到找到正确的叶子结点这样的效率很低。 叶子结点负责保存用户数据非叶子结点只保存目录项每个目录项负责管理一个叶子结点。所以B树是一棵矮胖的树因为一层非叶子结点就可以管理很多的叶子结点矮胖对于B树来说是很大的优势因为查找目标叶子结点路上经过的结点数量越少就代表从磁盘进行IO的page就越少查找的效率就越高。同时我们还有页目录的设计这在遍历数据的层面上来看也可以大大提高查找的效率 8. 即使创建出来的表没有索引但对表的增删查改依旧是在表所对应的B树结构下进行的因为如果你没有指定表的索引值表也会有自己的默认主键只不过你在查询的时候是线性遍历叶子结点进行查询的并没有利用B树的结构进行查询因为你没有创建某一列字段为索引值这也就是为什么没有创建索引的表在查询时速度慢的原因因为时间复杂度是O(N) 同时每一个表都会有对应的B树数据结构。
9. B树在面临范围查找时优势就没有了同时B树由于每个结点都会有data值则每个非叶子结点管理的叶子节点会更少一些所以B树要比B更高自顶向下查找的时候IO的次数会更多效率会更低一些。 3.聚簇索引索引和数据放在一起和非聚簇索引索引和数据分离存储
1. MyISAM使用非聚簇索引即将index和data分离存储叶子节点不直接存储数据而是只存储数据的地址。 2. MySQL除了建立主键索引外还可以建立其他索引例如普通索引唯一键索引等等除主键外的索引一般叫做辅助索引MyISAM的辅助索引和主键索引没什么区别叶子节点同样存储的是记录的地址。 3. 对于InnoDB来说他的辅助索引和主键索引与MyISAM就不一样了InnoDB的辅助索引的叶子结点存储的不是记录而是记录所对应的主键值查找到对应的主键值之后再根据主键值回到主键索引表进行查询直到查找到完整的记录所以像innodb这样的聚簇索引在建立辅助索引后如果按照辅助索引的键值来进行查找的话则在获得主键之后还要进行回表查询。 4.索引的操作
1. 主键索引唯一索引对应的数据结构是B树普通索引对应的数据结构是B树。 2. 下面是实际在进行索引操作时常用的一些SQL语句比如删除索引alter table table_name drop XXX构建索引alter table table_name add 索引(column_name)查询索引show index from table_name创建普通索引create index index_name on table_name(column_name) 3. 除了给单个列字段创建索引之外我们还可以给多个列字段同时创建索引这样的索引称之为复合索引当我们频繁的用一个字段查找另一个字段的时候就可以给这两个字段创建复合索引。 4. 全文索引要求表的存储引擎必须是MyISAM而且默认的全文索引只支持英文不支持中文。 在下面的sql语句创建出来的表里面如果要查询有没有database数据可以通过select * from articles where body like ‘%database%’但这种查询的方式并没有使用到全文索引这一点我们可以在SQL语句的前面加上explain查看一下select * from articles where match(title, body) against (‘database’) 二、MySQL事务管理重点
1.什么是事务
1. 如果对一张表的CURD不加控制则在多客户端多sql语句提交的情况下则一定会出现各种逻辑问题一张票多卖了两次所以在mysqld服务器高并发的处理来自多个客户端的sql语句请求时如果不对sql语句加控制则一定会出现各种各样的问题因为每个客户端对MySQL服务器的操作都不是原子的。 2. 所以对表的CURD操作应该满足一些属性例如买票的过程应该是原子的买票之间不能互相影响应该隔离开买完票之后数据应该作持久化买前和买后应该都是确定的状态要么成功要么不成功要具有回滚的能力比如买票中途数据库出现了问题服务器断电数据库被攻击等等数据库应该将状态回滚到买票前的状态。 而事务是由一组DML语句组成多条DML语句就是为了完成一个任务这一组DML语句是一个整体要么全部执行成功要么全部执行不成功不会出现中间状态而MySQL中一定不止一个事务在运行所以多个事务之间也需要控制事务也不简单的只是一组DML语句的集合还需要满足四个属性。 原子性一个事务transaction中的所有操作要么全部完成要么全部不完成不会结束在中 间某个环节。事务在执行过程中发生错误会被回滚Rollback到事务开始前的状态就像这个 事务从来没有执行过一样。回滚有自动回滚和手动回滚两种方式当MySQL服务宕机时MySQL自己会自动回滚正在执行到一半的事务 隔离性数据库允许多个并发事务同时对其数据进行读写和修改的能力隔离性可以防止多个事务 并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别包括读未提交 Read uncommitted 、读提交 read committed 、可重复读 repeatable read 和串行化 Serializable 持久性事务处理结束后对数据的修改就是永久的即便系统故障也不会丢失其实就是将数据落盘对数据作持久化。 一致性在事务开始之前和事务结束以后数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。 上面的四个性质中一致性其实是由前面的三个性质共同实现的所以只要满足了前面的三个性质就满足了事务的一致性。
3. 只有InnoDB存储引擎支持事务。事务本质上是为了应用层提供服务的应用层不会关心具体事务实现的细节他们只会使用事务。
4. 事务的提交方式一般有两种自动提交和手动提交其实这个提交方式只会影响单条sql语句作为事务时的提交结果我们后面会验证这个结论。 2.事务常见操作方式
1. 读未提交是事务隔离级别中最低的在这样的隔离级别下可以很方便的演示事务的诸多性质。 2. begin之后事务就启动了begin之后的多条sql语句都属于该事务内的sql语句在事务内可以savepoint设置回滚点MySQL支持定向回滚和直接回滚到最开始如果没有设置回滚点直接rollback的话则会直接回滚到最开始此时事务也会结束所以事务的结束方式有两种一种是commit另一种就是直接rollback回滚到最开始此时事务默认结束所以回滚操作是事务结束的一种方式。 3. 只要事务commit之后事务的操作就会被持久化到磁盘上数据会落盘不会受到数据库宕机或客户端崩溃的影响。 begin之后也就是开启一个事务之后事务都是自己手动提交的并不会自动提交所以autocommit是ON还是OFF对begin之后事务的提交方式都没有影响。 单条语句在MySQL中会默认为一个事务autocommit影响的是单条语句作为事务时的提交方式平常我们在命令行上敲单个的sql语句时这一个语句会作为事务立马提交因为autocommit默认是ON打开的但如果将autocommit关闭之后可以看到只要没commit所有的sql语句操作右边的客户端是看不到的。
4. 所以autocommit影响的是单条sql语句作为事务时的提交情况。 3.事务隔离级别
1. 一个事务的执行结果反馈给用户的是原子性即用户只会感受到事务执行前和执行后的状态变化但实际事务在执行时一定是有过程的所以多个事务在执行时可能会互相干扰所以事务之间需要隔离而隔离程度的体现就是隔离级别像多个读事务之间并发执行时隔离级别就可以降到最低因为多个读事务之间并不会互相影响。 但对于读写并发时就需要其他的隔离级别来控制多个事务的执行其实最麻烦的并发场景就是读写并发了因为像读读并发就不需要太高隔离级别直接RU即可而写写并发必须用最高的隔离级别只能串行化执行但读写并发就比较麻烦可能会使用到RC和RR级别。 而隔离级别的实现主要都是通过加锁来实现的不同的隔离级别使用不同的锁 2. 设置事务隔离级别有两种设置的方式一种是设置全局的隔离级别一种是设置当前会话的隔离级别会话的隔离级别可以简写为tx_isolation每次新起一个MySQL会话时默认就会使用全局的隔离级别作为当前会话的配置。 3. 读未提交是隔离等级最低的隔离级别虽然并发度比较高但几乎没有加锁同时产生的问题也会比较多例如脏读幻读不可重复读等并发问题脏读是RU级别最典型的问题读取到一个事务还未提交的数据很容易影响到上层的决策所以这样的并发问题是不可容忍的。 4. 读提交隔离级别最典型的并发问题就是不可重复读因为重复读可能会读取到不一样的结果这也会影响上层决策。读提交就是当前事务可以读取到其他事务提交后的内容这本身并没有什么问题但A事务提交后的内容不应该让当前正在和A事务并发的其他事务看到应该让A事务执行完之后其他此时重新启动的事务看到A事务提交后的内容所以读提交也有他自己的并发问题。 5. RR级别也就是可重复读级别是MySQL默认的隔离级别只要你重启mysqld服务器隔离级别就会默认设置为RR级别。 在MySQL下可以看到终端B并没有出现并发问题但实际上在其他的数据库中事务隔离级别在RR级别下还会有幻读的问题只不过MySQL通过间隙锁行锁的方式解决了幻读的问题其他的一些数据库没有解决。 幻读指的是其他事务insert的数据可能在重复读的情况下被读取出来因为隔离是对数据进行加锁完成的而insert的数据本身并不存在所以一般加锁的方式无法解决幻读问题但MySQL解决了。 值得注意的是幻读指的是其他事务insert时重复读可能会读取出来插入数据后的表就像出现了幻觉一样。如果其他事务updatedelete数据则重复读还是可以避免产生并发问题的因为他们操纵的是已有的数据。 其实在RR级别下为什么读取是可重复读的呢sql第一次读取的时候就直接给数据加上行锁保证其他事务对数据无法进行update和delete同时给数据加上间隙锁如果表有索引则在当前记录的附近加上间隙锁防止insert数据的行为。
6. 串行化的隔离级别太简单粗暴了无论事务是执行什么操作都必须被严格强制以串行化的方式执行这样的并发度太低效率很慢实际中不会采用这样的方案可能会产生超时或锁竞争的问题产生这种隔离级别太极端了。 7. 从表格就可以看到隔离级别越高产生的并发问题就越少但随之数据库的并发性能也就越低所以往往需要在安全和性能之间寻找一个平衡点这个平衡点就是RR可重复读隔离级别同时也是数据库默认的隔离级别。 一致性从技术角度来看是依靠AID的技术来实现的但其实一致性和用户逻辑强相关一致性不仅仅需要在技术层面上支持好同样也需要程序员在用户逻辑层面维护好数据库事务的一致性。 4.MVCC提高读写并发时数据库的性能
1. 多版本并发控制MVCC是一个并发效率很高的读写冲突的控制方式在并发读写数据库时MVCC可以做到在读操作时不用阻塞写操作在写操作时不用阻塞读操作极大的提高了数据库读写并发时的性能。 此外MVCC也解决了RR级别下的幻读问题以及脏读不可重复读等问题。 MVCC是一把提升数据库性能的利剑。
2. MVCC为事务分配单向增长的事务ID事务对数据修改时会保存一个版本版本与事务ID关联。 所以每个事务都有自己的事务ID可以根据事务ID的大小决定事务到来的先后顺序事务ID越大事务越新。 mysqld一定会面临处理多个事务的情况所以mysqld要对多个事务作管理也就是先描述再组织所以每个事务都会对应着一个结构体对象。
3. MVCC实现的表中会有三个隐藏列字段DB_TRX_ID用于记录创建表中当前这条记录的事务ID或最后一次修改当前这条记录的事务IDDB_ROLL_PTR指针指向这条记录的上一个历史版本DB_ROW_ID就是我们很早之前谈论索引时的隐藏主键如果表中没有主键则MySQL默认会创建一棵以DB_ROW_ID为键值的聚簇索引也就是B树。 除了上述三个隐藏列字段之外还有一个标志删除位flag。 4. undo log也是实现MVCC的一个重要角色可以将其理解为一个保存事务对表中记录更改的版本链的缓冲区事务的隔离和回滚操作的实现都离不开undo log 5. 增删改都会形成当前记录的历史版本select没必要形成历史版本但select在读取的时候有两种选择一种是读取最新的记录另一种是读取历史版本的记录也就是当前读和快照读快照读保证了读写并发的安全性和并发度不需要通过加锁来实现因为快照读和增删改操作的数据是不同的记录版本一个是历史数据一个是当前数据。 undo log中的一条条历史版本称为一个个的快照一旦事务提交之后这些快照就会被free掉所以undo log中的记录是有进有出的不用担心undo log会被记录打满。
实现事务隔离不仅仅需要历史版本数据还离不开read view通过read view才可以真正实现出事务隔离也就是不同的事务在select读的时候应该看到怎样的版本信息。 读视图read view是事务在第一次执行快照读的时候就产生了的而read view其实就是类ReadView实例化出来的对象一般习惯称之为快照在这个快照对象内部有四个成员变量是非常重要的也是实现事务隔离的重要技术实现。 m_ids保存read view生成时系统中正在活跃的事务ID up_limit_id保存的是m_ids中事务ID最小的事务ID low_limit_id保存的是当前已出现过的事务ID最大值1也就是系统即将分配给下一个事务的ID creator_trx_id保存的是创建当前记录的事务ID 所以我们现在左手有read view右手有历史版本链中所有的记录的DB_TRX_ID而当前事务select读的时候应该读取到什么样的版本记录其实就是由read view和历史版本链所决定的。 下面的图其实就已经诠释了事务可见性的算法。 如果版本链中的某个记录对应的ID大于或等于limit ID说明这个记录对应的事务是在创建快照之后新起的事务那么这条记录就不应该被创建快照的事务所看到。 如果版本链中的某个记录对应的ID小于up ID或等于creator_trx_id则说明这个记录是在创建快照之前早就已经提交的事务或者这条记录本身就是由创建快照的事务所做的更改则说明这条记录应该被当前事务所看到。 如果版本链中的某个记录对应的ID在m_ids里面那就说明该记录对应的事务还没提交完呢创建read view的事务不应该看到这条记录一旦看到那就是脏读。如果版本链中的某个记录对应的ID不在m_ids里面同时小于limit ID大于up ID则说明该事务已经提交了但为什么他的ID不小于up ID呢其实是因为该事务到来的时间比较晚但该事务是短事务执行的很快快照形成时该事务早已执行完毕了所以这样的版本记录是可见的。 下面是源码对应的事务可见性的处理策略changes_visible是MySQL判断当前事务快照读应该看到什么样记录的一个函数trx_id_t是外面传的一个参数该参数应该被不断更新为版本链中的各个记录所对应的事务id以判断该记录是否该被调用changes_visible函数的事务所看到。 例如当idm_up_limit_id或id m_creator_trx_id时当前记录应该被看到所以返回trueidm_low_limit_id当前记录不应该被看到返回false或者如果m_ids里面的事务是空的同时Id是小于m_low_limit_id的话则说明该记录对应的事务是早就已经提交了的是可以看到的。 如果上面的判断条件都不满足的话判断当前记录对应id是否在m_ids里面如果在则不能看到返回false如果不在则可以看到返回true。 如果当前记录不应该被看到则继续遍历下一个版本链中的记录。
值得注意的是read view在第一次事务进行快照读的时候就形成了在事务运行期间像RR级别就会一直使用该read view。 下面的实验是典型的一个trx_id不在m_ids里面同时也小于limit_id大于up_id的情况这种情况的记录是可见的当前事务可以看到。 所以我们可以总结一下MVCC实现的基本原理以及事务快照读可见性的原理通过给每个事务对记录的增删改都分配对应的历史版本信息就像写时拷贝一样只要对记录作修改则在undo log中形成该事务的历史版本链同时给每个事务根据到来顺序的不同分配一个逐渐增长的事务id当事务在快照读的时候会首先形成一个快照read viewread view对象内部有四个重要的成员变量分别是up_limit_idlow_limit_idcreator_idm_ids通过这四个字段和undo log里面的版本链记录之间的比较得到创建read view的事务应该看到什么样的记录。
5.RR与RC的本质区别
1. 在MVCC下快照读并不会加锁所以他和写并不是互斥的。在事务A作出修改后提交之前事务B形成快照则修改的记录对应的事务ID刚好在快照内的m_ids里面则事务B不应该看到事务A对记录做出的修改。如果想要看到最新的数据则可以使用加共享锁的方式来读取此时读取到的数据就是最新的但这并不意味着最新的就一定是正确的我们不希望一个事务在运行期间读取到的结果发生不同。 2. 在事务B快照读之前事务A完成了对记录的修改并提交那么事务B就应该在他自己执行的整个期间都一直能够看到事务A对记录做出的修改因为事务A都已经提交了无论是RR还是RC都应该看到。 如果从MVCC实现原理角度来讲的话则可能是两种情况一种是事务A的ID小于up_limit_id或事务ID不在m_ids里面也就是说要么事务A到来的特别早并提前提交了形成快照的事务应该看到或者是事务A到来的比形成快照的事务晚但事务A是一个短事务在当前事务形成快照之前事务A就执行完并且提交了那么快照事务也应该看到。所以无论对应哪种情况事务B都应该看到事务A对记录做出的修改。
需要直到的是事务读到的数据是新的还是旧的并不重要事务在执行期间读到的数据始终都不变这才是重要的
3. RR与RC的本质区别就是快照的形成RR级别下事务第一次形成快照后则在后面事务整个的执行期间会一直使用该快照这也就是为什么RR级别下是可重复读的因为read view对象一直不变。而RC级别下事务每次快照读的时候都会重新生成新的read view这也就是为什么RC级别下可以看到其他事务提交之后的内容因为RC级别会生成新的read view重新进行可见性的判断。 两者之间的差别再说的本质一些RR级别下第一次快照读的时候会new一个read view对象并且在该事务执行期间一直使用这个read view对象RC级别下每次快照读的时候都会重新new一个read view对象并delete掉原来的read view对象所以在该事务执行期间一直使用不断更新的read view对象。
RU级别一直都是当前读没有加锁控制RR和RC都是快照读MVCC串行化也是当前读不过是加锁控制的所以串行化无论是读读之间还是读写之间还是写写之间都是需要竞争锁的这也就是为什么串行化并发度低的原因因为无论什么操作都加锁。 三、MySQL视图特性
1. 视图实际中用的并不多但我们也稍微了解一下。 创建视图是根据select查询结果来创建的create view view_name as select ……创建出来的视图其实就是一张表如果修改视图中的数据则原表中的数据也会随之被修改所以一般而言视图只用来查询不会用来作修改因为基表中的数据会受牵连。 如果你高频的只查询一部分表的数据则可以选择给这一部分数据创建视图下次查询时直接从视图中查询即可。 四、MySQL用户管理
1. MySQL安装好之后会有一个默认的database叫做mysql在该数据库内部会存在一个user表该表中存放了当前mysqld服务下所有的用户的信息包括很多的字段最常用的几个字段就是hostuserauthentication_string用户密码是经过password()函数加密过的所以我们看不懂。 2. 新建用户时要指定用户名主机名以及登录时需要认证的密码新建用户之后为了让我们新建的用户生效最好刷新一下权限flush privileges。 删除用户时需要指定用户名和host登录方法。 root用户可以更改所有用户的登录密码所以修改秘密时建议直接使用root用户的身份来修改所有用户的密码。 我们可以指定的给用户赋予权限比如对某一个具体的库某一个具体的表赋予查询增加删除修改等权限赋予权限时也可以指定密码不过尽量在创建用户时就指定好密码不要在赋权时指定密码。回收权限可以使用revoke指令来回收。
五、API和图形化界面的客户端
1. 除了我们之前一直用的命令行式的客户端之外还可以使用C语言连接数据库使用API的方式来作为客户端访问数据库服务我们可以直接使用yum install -y mysql-community-server下载一般下载的时候会自动给我们把开发包下载好如果没有开发包则可以使用yum install -y mysql-devel手动下载开发包下载安装好之后我们就可以使用vscode以API的方式来连接并使用数据库了。 安装好之后在/usr/include/mysql下会存在C语言连接数据库时使用的头文件在/lib64/mysql下会存在着连接数据库需要的动态库和静态库。 2. 准备好开发环境之后我们尝试连接一下数据库。 使用mysql.h头文件指明编译器搜索头文件时的路径。连接库的时候需要指明链接器的链接路径以及需要链接的库的名称这些字段都需要在makefile里面确定好。 链接库前必须先调用mysql_init进行初始化mysql_init会返回一个类似于文件描述符的东西使用myfd就可以对数据库进行操作。初始化好之后调用mysql_real_connect进行数据库的连接连接时需要传递对应的参数例如密码用户名登陆方式database名称端口号等等 mysql_query用于给数据库下发MySQL命令第一个参数为myfd也就是那个文件描述符下发的指令为增删改时我们返回给客户端的结果只需要是Query OK or Query failed 即可这样处理起来并不难我们可以通过API的方式自己实现一个类似于命令行式的客户端难度并不大只需要调用mysql_query即可难的是select查询语句因为查询是需要返回命令行处理结果的所以想要实现查询命令的下发仅仅有mysql_query是不够的还需要其他API的帮助。 下面我们来实现当下发的语句为查询语句时如何打印出查询sql的返回结果。 mysql_store_result会将语句的执行结果放到res里面我们只需要将信息从res提取出来并打印到显示器上即可mysql_num_rows用于获取结果集的行数mysql_nums_fields用于获取结果集的列数mysql_fetch_fields用于获取列名是什么返回的指针会指向一个一维数组一维数组中的内容就是各个列字段的名称。mysql_fetch_row获取结果集中的内容连续调用mysql_fetch_row他会像迭代器一样自动帮我们跳转到下一行并将下一行的地址返回到line里面所以我们依次打印出每行的内容即可。
mysql_fetch_field用起来不如mysql_fetch_fields方便后者直接返回一个一维数组即可我们遍历这个数组将数组的内容输出即可这样比较方便。 下面是具体的代码实现别忘了关闭mysql链接和释放掉结果集resres是动态申请的所以也要释放。
下面是执行查询语句后的结果
3. MySQL Workbench用起来只能说还凑合感觉还是不如直接敲命令行爽不过我们实际工作当中肯定用的都是图形化界面来访问数据库服务。使用的成本也比较低大家可以自己下载一个玩一玩