一、索引相关

1. 索引是个什么样的数据结构呢?

索引的数据结构和具体存储引擎的实现有关, 在MySQL中使用较多的索引有Hash索引,B+树索引等,而我们经常使用的InnoDB存储引擎的默认索引实现为:B+树索引.

2. Hash索引和B+树所有有什么区别或者说优劣呢?

首先要知道Hash索引和B+树索引的底层实现原理:
(我先叙述我个人理解,不要死记硬背,一定要理解,这里面试官很容易深问)

hash索引底层就是hash表,进行查找时,调用一次hash函数就可以获取到相应的键值,之后进行回表查询获得实际数据.B+树底层实现是多路平衡查找树.对于每一次的查询都是从根节点出发,查找到叶子节点方可以获得所查键值,然后根据查询判断是否需要回表查询数据.

那么可以看出他们有以下的不同:

hash索引进行等值查询更快(一般情况下),但是却无法进行范围查询.
因为在hash索引中经过hash函数建立索引之后,索引的顺序与原顺序无法保持一致,不能支持范围查询.而B+树的的所有节点皆遵循(左节点小于父节点,右节点大于父节点,多叉树也类似),天然支持范围.

hash索引不支持使用索引进行排序,原理同上.
hash索引不支持模糊查询以及多列索引的最左前缀匹配.原理也是因为hash函数的不可预测.AAAA和AAAAB的索引没有相关性.
hash索引任何时候都避免不了回表查询数据,而B+树在符合某些条件(聚簇索引,覆盖索引等)的时候可以只通过索引完成查询.
hash索引虽然在等值查询上较快,但是不稳定.性能不可预测,当某个键值存在大量重复的时候,发生hash碰撞,此时效率可能极差.而B+树的查询效率比较稳定,对于所有的查询都是从根节点到叶子节点,且树的高度较低.因此,在大多数情况下,直接选择B+树索引可以获得稳定且较好的查询速度.而不需要使用hash索引

3.在建立索引的时候,都有哪些需要考虑的因素呢?

建立索引的时候一般要考虑到字段的使用频率,经常作为条件进行查询的字段比较适合.如果需要建立联合索引的话,还需要考虑联合索引中的顺序.此外也要考虑其他方面,比如防止过多的所有对表造成太大的压力.这些都和实际的表结构以及查询方式有关.

4. 索引的好处和坏处

先说一下索引的好处:
提高数据的检索速度,降低数据库IO成本;索引会降数据排好序,降低了数据排序的成本;通过使用索引可以在查询的过程中优化使用隐藏器提高系统的性能。
再来索引的缺点:
创建索引和维护索引需要消耗时间,且由数据量决定,数据量很大时间更长;索引会占用一定的物理空间,若建立聚簇索引会更大,对数据进行增删改需要维护索引占用一定空间和效率。

5.索引的类型

索引,都是实现在存储引擎层的。主要有六种类型:

1、普通索引:最基本的索引,没有任何约束。
2、唯一索引:与普通索引类似,但具有唯一性约束。
3、主键索引:特殊的唯一索引,不允许有空值。
4、复合索引:将多个列组合在一起创建索引,可以覆盖多个列。
5、外键索引:只有InnoDB类型的表才可以使用外键索引,保证数据的一致性、完整性和实现级联操作。
6、全文索引:MySQL 自带的全文索引只能用于 InnoDB、MyISAM ,并且只能对英文进行全文检索,一般使用全文索引引擎。

二:事务相关

1. 什么是事务?

理解什么是事务最经典的就是转账的例子,比较基础,相信大家也都了解,这里就不再说一边了.

事务是一系列的操作,他们要符合ACID特性.最常见的理解就是:事务中的操作要么全部成功,要么全部失败.但是只是这样还不够的.

2. ACID是什么?可以详细说一下吗?

A=Atomicity
原子性,就是上面说的,要么全部成功,要么全部失败.不可能只执行一部分操作.C=Consistency
系统(数据库)总是从一个一致性的状态转移到另一个一致性的状态,不会存在中间状态.I=Isolation
隔离性: 通常来说:一个事务在完全提交之前,对其他事务是不可见的.注意前面的通常来说加了红色,意味着有例外情况.D=Durability
持久性,一旦事务提交,那么就永远是这样子了,哪怕系统崩溃也不会影响到这个事务的结果.

3. 同时有多个事务在进行会怎么样呢?(并发情况下事务问题)

多事务的并发进行一般会造成以下几个问题:脏读: A事务读取到了B事务未提交的内容,而B事务后面进行了回滚.不可重复读: 当设置A事务只能读取B事务已经提交的部分,会造成在A事务内的两次查询,结果竟然不一样,因为在此期间B事务进行了提交操作.幻读: A事务读取了一个范围的内容,而同时B事务在此期间插入了一条数据.造成"幻觉".

4. 怎么解决这些问题呢?MySQL的事务隔离级别了解吗?

MySQL的四种隔离级别如下:未提交读(READ UNCOMMITTED)
这就是上面所说的例外情况了,这个隔离级别下,其他事务可以看到本事务没有提交的部分修改.因此会造成脏读的问题(读取到了其他事务未提交的部分,而之后该事务进行了回滚).

这个级别的性能没有足够大的优势,但是又有很多的问题,因此很少使用.

已提交读(不可重复读)(READ COMMITTED)
其他事务只能读取到本事务已经提交的部分.这个隔离级别有 不可重复读的问题,在同一个事务内的两次读取,拿到的结果竟然不一样,因为另外一个事务对数据进行了修改.

REPEATABLE READ(可重复读)
可重复读隔离级别解决了上面不可重复读的问题(看名字也知道),但是仍然有一个新问题,就是 幻读,当你读取id> 10 的数据行时,对涉及到的所有行加上了读锁,此时例外一个事务新插入了一条id=11的数据,因为是新插入的,所以不会触发上面的锁的排斥,那么进行本事务进行下一次的查询时会发现有一条id=11的数据,而上次的查询操作并没有获取到,再进行插入就会有主键冲突的问题.

SERIALIZABLE(可串行化)
这是最高的隔离级别,可以解决上面提到的所有问题,因为他强制将所以的操作串行执行,这会导致并发性能极速下降,因此也不是很常用.

5. MySQL都有哪些锁呢?像上面那样子进行锁定岂不是有点阻碍并发效率了?

从锁的类别上来讲,有共享锁和排他锁.共享锁: 又叫做读锁. 当用户要进行数据的读取时,对数据加上共享锁.共享锁可以同时加上多个.排他锁: 又叫做写锁. 当用户要进行数据的写入时,对数据加上排他锁.排他锁只可以加一个,他和其他的排他锁,共享锁都相斥.

用上面的例子来说就是用户的行为有两种,一种是来看房,多个用户一起看房是可以接受的. 一种是真正的入住一晚,在这期间,无论是想入住的还是想看房的都不可以.

锁的粒度取决于具体的存储引擎,InnoDB实现了行级锁,页级锁,表级锁.

  • 共享锁/读锁:互不阻塞,优先级低

  • 排他锁/写锁:阻塞其他锁,优先级高,即确保在一个事务写入时不受其他事务的影响。

  • 锁粒度:锁定的数据量越少(粒度越小),并发程度越高,但相应的加锁、检测锁、释放锁用的系统开销也随之增大。

  • 锁策略:锁开销与数据安全性之间的平衡 主要两种:1 表锁:锁住整张表,读锁互不阻塞,写锁阻塞其他所有读写锁(同一张表)。开销最小。2 行级锁:对每一行数据(记录)加锁,开销大,并发程度高。

6.乐观锁和悲观锁

先介绍一个乐观锁:它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度, 因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。
在悲观锁的情况下,为了保证事务的隔离性,就需要一致性锁定读。 读取数据时给加锁,其它事务无法修改这些数据。修改删除数据时也要加锁,其它事务无法读取这些数据。再来说一下乐观锁:
相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。
而乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本( Version )记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。

三:表结构设计

1. 为什么要尽量设定一个主键?

主键是数据库确保数据行在整张表唯一性的保障,即使业务上本张表没有主键,也建议添加一个自增长的ID列作为主键.设定了主键之后,在后续的删改查的时候可能更加快速以及确保操作数据范围安全.

3. 字段为什么要求定义为not null?

MySQL官网这样介绍:
null值会占用更多的字节,且会在程序中造成很多与预期不符的情况.

4.如果要存储用户的密码散列,应该使用什么字段进行存储?

密码散列,盐,用户身份证号等固定长度的字符串应该使用char而不是varchar来存储,这样可以节省空间且提高检索效率.

四:存储引擎相关

1. MySQL支持哪些存储引擎?

MySQL支持多种存储引擎,比如InnoDB,MyISAM, Memory,Archive等等.在大多数的情况下,直接选择使用InnoDB引擎都是最合适的,InnoDB也是MySQL的默认存储引擎.

3.InnoDB和MyISAM有什么区别?

五:零散问题常问知识点总结

1. 说一说三个范式

第一范式:每个列都不可以再拆分。(属性不可分)

第二范式:在第一范式的基础上,非主键列完全依赖于主键,而不能是依赖于主键的一部分。(主键依赖性)

第三范式:在第二范式的基础上,非主键列只依赖于主键,不依赖于其他非主键。(传递依赖性)

在设计数据库结构的时候,要尽量遵守三范式,如果不遵守,必须有足够的理由。比如性能。事实上我们经常会为了性能而妥协数据库的设计。

3. MySQL中的varchar和char有什么区别.

char是一个定长字段,假如申请了char(10)的空间,那么无论实际存储多少内容.该字段都占用10个字符,而varchar是变长的,也就是说申请的只是最大长度,占用的空间为实际字符长度+1,最后一个字符存储使用了多长的空间.
在检索效率上来讲,char > varchar,因此在使用中,如果确定某个字段的值的长度,可以使用char,否则应该尽量使用varchar。例如存储用户MD5加密后的密码,则应该使用char.

4.关系型数据库和非关系型数据库的区别

很简单的啦,这里制作一个表格方便大家直观了解

5.一条sql语句如何在mysql中执行

  • 客户端发送查询到服务器;

  • 服务器检查查询缓存query 大小写敏感的哈希查找,常数时间)。如果命中,返回缓存中的结果,否则下一步;

  • 解析语句,生成执行计划;(SQL解析,预处理,优化器生成执行计划);

  • 根据执行计划,根据存储引擎的不同调用API,执行查询(一棵指令树);

  • 结果返回客户端

8.SQL语言包括哪几部分?每部分都有哪些操作关键字?

SQL语言包括数据定义(DDL)、数据操纵(DML),数据控制(DCL)和数据查询(DQL)四个部分。数据定义:Create Table,Alter Table,Drop Table, Craete/Drop Index等数据操纵:Select ,insert,update,delete,数据控制:grant,revoke数据查询:select

10.介绍一下mysql的三种删除操作

就是三个关键字:drop、deete、truncate区别:

  • delete和truncate只删除表的数据不删除表的结构。

  • 速度的话,是drop>truncate>delete

  • drop和truncate都是dll,操作立即生效,不能回滚,操作不触发trigger。

  • delete是dml,事务提交之后才会生效,如果有相应的trigger,执行的时候也会触发。

使用场景:不再需要表时,用drop;删除部分数据,用带where的delete;保留表而删除所有数据时用truncate;

六:零散基础问题(有些不重要,看看即可

1.什么是视图

视图是一个虚表,它的行列数据是从别的基础表中获得的,某几个字段可能来自于基础表A,某几个字段可能来自于基础表B。操作视图的时候,实际上操作的就是基础表。视图整个的建立和删除不影响基础表,而对视图内容的删除、增加、修改直接影响基本表。当视图来自于多个基本表时,不允许删除和增加数据。视图在物理上是不存在的,数据库系统没有专门的位置为视图存储数据,视图的数据来源于查询语句。

视图的作用:

提高了sql语句的复用性,就像一个函数;对数据库进行了重构,却不影响程序的运行;针对不同用户来说,提高了安全性能;

2. 关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都怎么优化过?

在业务系统中,除了使用主键进行的查询,其他的我都会在测试库上测试其耗时,慢查询的统计主要由运维在做,会定期将业务中的慢查询反馈给我们.
慢查询的优化首先要搞明白慢的原因是什么? 是查询条件没有命中索引?是load了不需要的数据列?还是数据量太大?
所以优化也是针对这三个方向来的,
首先分析语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写.
分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引.
如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表.

3. 什么是存储过程?有哪些优缺点?

存储过程是一些预编译的SQL语句。

1、更加直白的理解:存储过程可以说是一个记录集,它是由一些T-SQL语句组成的代码块,这些T-SQL语句代码像一个方法一样实现一些功能(对单表或多表的增删改查),然后再给这个代码块取一个名字,在用到这个功能的时候调用他就行了。

2、存储过程是一个预编译的代码块,执行效率比较高,一个存储过程替代大量T_SQL语句 ,可以降低网络通信量,提高通信速率,可以一定程度上确保数据安全

4.什么是触发器

触发器是监听某种情况,触发某种操作。
创建触发器有四元素:一个监听地点(table)、一个监听事件(insert、update、delete)、一个触发时间(before、after)、一个触发事件(insert、delete、update)。
触发器是数据库对象之一,与函数非常类似,需要声明、执行。但是触发器的执行是由事件来触发的。当表发生更改时,需要自动进行一些处理,比如每增加一条学生的记录,学生的总数就需要同时改变,这时候就要执行一次计算学生总数的操作。触发器的操作包括创建触发器、查看触发器及删除触发器。

==========================

HashMap:

Hash表是一个数组+链表的结构,这种结构能够保证在遍历与增删的过程中,如果不产生hash碰撞,仅需一次定位就可完成,时间复杂度能保证在O(1)。  在jdk1.7中,只是单纯的数组+链表的结构,但是如果散列表中的hash碰撞过多时,会造成效率的降低,所以在JKD1.8中对这种情况进行了控制,当一个hash值上的链表长度大于8时,该节点上的数据就不再以链表进行存储,而是转成了一个红黑树。

hash碰撞:

hash是指,两个元素通过hash函数计算出的值是一样的,是同一个存储地址。当后面的元素要插入到这个地址时,发现已经被占用了,这时候就产生了hash冲突

hash冲突的解决方法:

开放定址法(查询产生冲突的地址的下一个地址是否被占用,直到寻找到空的地址),再散列法,链地址法等。hashmap采用的就是链地址法,jdk1.7中,当冲突时,在冲突的地址上生成一个链表,将冲突的元素的key,通过equals进行比较,相同即覆盖,不同则添加到链表上,此时如果链表过长,效率就会大大降低,查找和添加操作的时间复杂度都为O(n);但是在jdk1.8中如果链表长度大于8,链表就会转化为红黑树,时间复杂度也降为了O(logn),性能得到了很大的优化。

JDK8中HashMap链表转红黑树的阈值为什么选8?为什么用红黑树做优化

在平常我们用HashMap的时候,HashMap里面存储的key是具有良好的hash算法的key(比如String、Integer等包装类),冲突几率自然微乎其微,此时链表几乎不会转化为红黑树,但是当key为我们自定义的对象时,我们可能采用了不好的hash算法,使HashMap中key的冲突率极高,但是这时HashMap为了保证高速的查找效率,就引入了红黑树来优化查询了。

为什么树化的临界值为8?

通过源码我们得知HashMap源码作者通过泊松分布算出,当桶中结点个数为8时,出现的几率是亿分之6的,因此常见的情况是桶中个数小于8的情况,此时链表的查询性能和红黑树相差不多,因为转化为树还需要时间和空间,所以此时没有转化成树的必要。

既然个数为8时发生的几率这么低,我们为什么还要当链表个数大于8时来树化来优化这几乎不会发生的场景呢?

首先我们要知道亿分之6这个几乎不可能的概率是建立在什么情况下的 答案是:建立在良好的hash算法情况下,例如String,Integer等包装类的hash算法、如果一旦发生桶中元素大于8,说明是不正常情况,可能采用了冲突较大的hash算法,此时桶中个数出现超过8的概率是非常大的,可能有n个key冲突在同一个桶中,此时再看链表的平均查询复杂度和红黑树的时间复杂度,就知道为什么要引入红黑树了,

举个例子,若hash算法写的不好,一个桶中冲突1024个key,使用链表平均需要查询512次,但是红黑树仅仅10次,红黑树的引入保证了在大量hash冲突的情况下,HashMap还具有良好的查询性能

hash冲突的解决方法以及hashMap的底层实现

大家平时都用过hashMap,但是可能大家对hashMap的底层实现不太了解,同时对其中可能出现的hash冲突有些不了解,这几天我翻了下资料,也稍微了解下,记录下来,以免遗忘。

上图就是一个散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。但是当关键字数量比较大的时候,难免就会造成一个问题,就是不一样的关键字隐射到同一个地址上,这样就造成了一个问题,就是hash冲突。那么如何解决呢?

一般比较常用的方法有开放地址法:(内容来自百度百科)
1. 开放寻址法:Hi=(H(key) + di) MOD m,i=1,2,…,k(k<=m-1),其中H(key)为散列函数,m为散列表长,di为增量序列,可有下列三种取法:
        1.1. di=1,2,3,…,m-1,称线性探测再散列;顺序查看表的下一单元,直至找到某个空单元,或查遍全表。
        1.2. di=1^2,-1^2,2^2,-2^2,⑶^2,…,±(k)^2,(k<=m/2)称二次探测再散列;在表的左右进行跳跃式探测。
        1.3. di=伪随机数序列,称伪随机探测再散列。根据产生的随机数进行探测。

2. 再散列法:建立多个hash函数,若是当发生hash冲突的时候,使用下一个hash函数,直到找到可以存放元素的位置。

3 .拉链法(链地址法):就是在冲突的位置上建立一个链表,然后将冲突的元素插入到链表尾端,

4 .建立公共溢出区:将哈希表分为基本表和溢出表,将与基本表发生冲突的元素放入溢出表中。

底层的hashMap是由数组和链表来实现的,就是上面说的拉链法。首先当插入的时候,会根据key的hash值然后计算出相应的数组下标,计算方法是index = hashcode%table.length,(这个下标就是上面提到的bucket),当这个下标上面已经存在元素的时候那么就会形成链表,将后插入的元素放到尾端,若是下标上面没有存在元素的话,那么将直接将元素放到这个位置上。
当进行查询的时候,同样会根据key的hash值先计算相应的下标,然后到相应的位置上进行查找,若是这个下标上面有很多元素的话,那么将在这个链表上一直查找直到找到对应的元素。

数据库sqlite3怎么排顺序_【数据库02】MySQL数据库面试题相关推荐

  1. 经典mysql数据库面试题_【数据库】MySQL经典面试题(练习)

    id number(32) NOT NULL, name varchar(10) DEFAULT NULL, sax varchar(10) DEFAULT NULL, age number(6) D ...

  2. mysql数据库+易语言的应用_易语言mysql数据应用源码

    易语言mysql数据应用源码 易语言mysql数据应用源码 系统结构:注册账号,连接Mysql,用户注册验证码,修改密码验证码,忘记密码验证码,修改密码,忘记密码, ======窗口程序集1 | | ...

  3. 运维mysql数据库面试题_运维面试题之数据库

    mysql篇: mysql主从复制原理? mysql的复制是基于3个线程 1.master上的binlog dump线程负责把binlog 事件传到slave 2.slave上面的IO线程负责接收bi ...

  4. mysql数据库面试题 软件测试_软件测试数据库面试题一

    前提 本次分享只局限于 sql server 和 mysql 这两种数据库,其他数据库暂不总结 正文 1. 对查询的字段进行去重(distinct) 用法注意: 1. distinct[查询字段],必 ...

  5. sae mysql 同步本地_MYSQL入门之三_将本地MySQL数据导入SAE数据库_MySQL

    bitsCN.com MYSQL入门之三_将本地MySQL数据导入SAE数据库 1. MySQL字符集 MySQL的默认字符集是latin1,将本地MySQL库导出成sql,再导入到SAE的MySQL ...

  6. C# 联合查询_直击数据库面试题:数据库查询语句

    Student(S#,Sname,Sage,Ssex) 学生表 Course(C#,Cname,T#) 课程表 SC(S#,C#,score) 成绩表 Teacher(T#,Tname) 教师表 问题 ...

  7. 混合索引_数据库面试题:查询在什么情况下不?索引-数据库知识点

    查询在什么情况下不⾛索引 数据库面试题 ⾸先,我们可以说通过explain去排查⼀个慢查询,进⽽找到它的索引(参看第五题),当创建索引却不⾛索引时,我们就需要考虑到优化器的问题. 在⼀条单表查询语句真 ...

  8. datagrid如何获取一行数据中的某个字段值_或许是全网最全面关于数据库面试题...

    原文: https://www.enmotech.com/web/detail/1/794/1.html 两万字全面论述数据库面试题(上) https://www.enmotech.com/web/d ...

  9. mysql纵表 主键_数据库面试题-sql语句

    原标题:数据库面试题-sql语句 1,写出一条Sql语句:取出表A中第31到第40记录(SQLServer,以自动增长的ID作为主键,注意:ID可能不是连续的. 答: → 解1: select top ...

  10. 连接mysql数据库的三个接口_数据库的三种接口

    数据库(Database)是按照数据结构来组织.存储和管理数据的仓库,它产生于距今六十多年前,随着信息技术和市场的发展,特别是二十世纪九十年代以后,数据管理不再仅仅是存储和管理数据,而转变成用户所需要 ...

最新文章

  1. WPF Datagrid with some read-only rows - Stack Overflow
  2. php查询每个小时的数据,php – MySQL显示表中每小时的条目数
  3. 从电脑传PDF到IPad的阅读器上
  4. springboot简易集成mybatisPlus+多数据源
  5. 用对齐原则求结构体长度
  6. 【Android开发】我的第一个安卓程序
  7. URAL 1013 K-based Numbers. Version 3
  8. python随堂技术演讲时间表
  9. C# OpenTK教程 - 1.1 创建窗口
  10. 通信线路工程验收规范 gb51171-2016_一级建造师市政涉及到的相关规范汇总
  11. php 获取来源域名方法,PHP获取域名方法
  12. iOS内存管理部分内容
  13. 智能计算系统1 环境搭建
  14. weblogic 启动很慢_【转】解决weblogic启动慢和创建域慢的方法
  15. .doc文件不显示word图标的解决方法
  16. QT控件被其他控件遮盖
  17. B站评论区抽奖[python]
  18. 街霸 隆(Ryu)升龙拳(Syoryuken)动画(四)制作过程中几个版本动画比较一下
  19. 微信小程序反编译的应对方法
  20. golang 递归方式解析json串

热门文章

  1. HttpUtility.UrlEncode、HttpUtility.UrlDecode、Server.UrlEncode、Server.UrlDecode的区分与应用
  2. 线性代数【一】:行列式的概念与计算
  3. opencv视频转图片并保存到文件夹下
  4. 开源矿工 - 记一个完整的软件是如何开发和运行的
  5. nginx限制并发连接数和连接请求数
  6. ubuntu 防止软件包自动更新
  7. 作业题---设计一个类,求和的方法,求乘积的方法
  8. Android系统在新进程中启动自定义服务过程(startService)的原理分析
  9. VBA读取固定文件夹中txt内容
  10. autoresizingMask的用法