MySql 面试开发技术点汇总

表结构设计

1、为什么一定要设一个主键? 

 答:因为你不设主键的情况下,innodb也会帮你生成一个隐藏列,作为自增主键。所以啦,反正都要生成一个主键,那你还不如自己指定一个主键,在有些情况下,就能显式的用上主键索引,提高查询效率!

 

2、你们主键是用自增还是UUID? 

 答:肯定答自增啊。innodb中的主键是聚簇索引。如果主键是自增的,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页。如果不是自增主键,那么可能会在中间插入,就会引发页的分裂,产生很多表碎片!。

  上面那句话看不懂没事,大白话一句就是:用自增插入性能好!
  另外,附一个测试表给你们,表名带uuid的就是用uuid作为主键。大家看一下就知道性能差距了:

                

  如上图所示,当主键是UUID的时候,插入时间更长,而且占用空间更大!

  额,大家千万不要忘了,当你回答自增主键后,想一下《自增主键用完该怎么办?》 

 

3、主键为什么不推荐有业务含义? 

 答:有如下两个原因

   (1)因为任何有业务含义的列都有改变的可能性,主键一旦带上了业务含义,那么主键就有可能发生变更。主键一旦发生变更,该数据在磁盘上的存储位置就会发生变更,有可能会引发页分裂,产生空间碎片。

  2)带有业务含义的主键,不一定是顺序自增的。那么就会导致数据的插入顺序,并不能保证后面插入数据的主键一定比前面的数据大。如果出现了,后面插入数据的主键比前面的小,就有可能引发页分裂,产生空间碎片。

4、表示枚举的字段为什么不用enum类型? 

 答:在工作中表示枚举的字段,一般用tinyint类型。那为什么不用enum类型呢?下面两个原因

   (1) ENUM类型的ORDER BY操作效率低,需要额外操作
   (2) 如果枚举值是数值,有陷阱
    举个例子,表结构如下

CREATE TABLE test (foobar ENUM('0', '1', '2'));

  此时,你执行语句   

mysql> INSERT INTO test VALUES (1);

    查询出的结果为

         

    就产生了一个坑爹的结果。
    插入语句应该像下面这么写,插入的才是1

mysql> INSERT INTO test VALUES (`1`);

 

5、货币字段用什么类型? 

 答:如果货币单位是分,可以用Int类型。如果坚持用元,用Decimal。千万不要答floatdouble,因为float和double是以二进制存储的,所以有一定的误差。

  打个比方,你建一个列如下

CREATE TABLE `t` (
  `price` float(10,2) DEFAULT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8

  然后insert给price列一个数据为1234567.23,你会发现显示出来的数据变为1234567.25,精度失准!

 

6、时间字段用什么类型? 

 答:此题无固定答案,应结合自己项目背景来答!把理由讲清楚就行!   

  (1) varchar,如果用varchar类型来存时间,优点在于显示直观。但是坑的地方也是挺多的。比如,插入的数据没有校验,你可能某天就发现一条数据为2013111的数据,请问这是代表2013年1月11日,还是2013年11月1日?

  其次,做时间比较运算,你需要用STR_TO_DATE等函数将其转化为时间类型,你会发现这么写是无法命中索引的。数据量一大,是个坑!

  (2) timestamp,该类型是四个字节的整数,它能表示的时间范围为1970-01-01 08:00:01到2038-01-19 11:14:07。2038年以后的时间,是无法用timestamp类型存储的。
    但是它有一个优势,timestamp类型是带有时区信息的。一旦你系统中的时区发生改变,例如你修改了时区

SET TIME_ZONE = "america/new_york";

   你会发现,项目中的该字段的值自己会发生变更。这个特性用来做一些国际化大项目,跨时区的应用时,特别注意!

  (3) datetime,datetime储存占用8个字节,它存储的时间范围为1000-01-01 00:00:00 ~ 9999-12-31 23:59:59。
   显然,存储时间范围更大。但是它坑的地方在于,他存储的是时间绝对值,不带有时区信息。如果你改变数据库的时区,该项的值不会自己发生变更!

  (4) bigint,也是8个字节,自己维护一个时间戳,表示范围比timestamp大多了,就是要自己维护,不大方便。

7、为什么不直接存储图片、音频、视频等大容量内容? 

 答:我们在实际应用中,都是用HDFS来存储文件。然后mysql中,只存文件的存放路径。mysql中有两个字段类型被用来设计存放大容量文件,也就是text和
blob类型。但是,我们在生产中,基本不用这两个类型!
  主要原因有如下两点:

   (1) Mysql内存临时表不支持TEXT、BLOB这样的大数据类型,如果查询中包含这样的数据,在排序等操作时,就不能使用内存临时表,必须使用磁盘临时表进行。导致查询效率缓慢
   (2) binlog内容太多。因为你数据内容比较大,就会造成binlog内容比较多。大家也知道,主从同步是靠binlog进行同步,binlog太大了,就会导致主从同步效率问题! 
 因此,不推荐使用text和blob类型!

 

8、字段为什么要定义为NOT NULL? 

 答:(1)索引性能不好

  Mysql难以优化引用可空列查询,它会使索引、索引统计和值更加复杂。可空列需要更多的存储空间,还需要mysql内部进行特殊处理。可空列被索引后,每条记录都需要一个额外的字节,还能导致MYisam 中固定大小的索引变成可变大小的索引。—— 出自《高性能mysql第二版》
   (2)查询会出现一些不可预料的结果

    这里举一个例子,大家就懂了。假设,表结构如下  

create table table_2 (
     `id` INT (11) NOT NULL,
    name varchar(20) NOT NULL
)

  表数据是这样的

  你执行语句  

select count(name) from table_2;

  你会发现结果为2,但是实际上是有四条数据的!类似的查询问题,其实有很多,不一一列举。
  记住,因为null列的存在,会出现很多出人意料的结果,从而浪费开发时间去排查Bug.

 也可参考这篇理解:https://www.cnblogs.com/myseries/p/11264178.html

 

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

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


 

索引相关

1、什么是索引?

  答: 索引是一种数据结构,可以帮助我们快速的进行数据的查找.

 

2、索引是个什么样的数据结构呢?

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

 

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

答:首先要知道Hash索引和B+树索引的底层实现原理:

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

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

  • hash索引进行等值查询更快(一般情况下),但是却无法进行范围查询.

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

  • hash索引不支持使用索引进行排序,原理同上.

  • hash索引不支持模糊查询以及多列索引的最左前缀匹配.原理也是因为hash函数的不可预测.AAAAAAAAB的索引没有相关性.

  • hash索引任何时候都避免不了回表查询数据,而B+树在符合某些条件(聚簇索引,覆盖索引等)的时候可以只通过索引完成查询.

  • hash索引虽然在等值查询上较快,但是不稳定.性能不可预测,当某个键值存在大量重复的时候,发生hash碰撞,此时效率可能极差.而B+树的查询效率比较稳定,对于所有的查询都是从根节点到叶子节点,且树的高度较低.

  因此,在大多数情况下,直接选择B+树索引可以获得稳定且较好的查询速度.而不需要使用hash索引.

 

4、上面提到了B+树在满足聚簇索引和覆盖索引的时候不需要回表查询数据,什么是聚簇索引?

答:在B+树的索引中,叶子节点可能存储了当前的key值,也可能存储了当前的key值以及整行的数据,这就是聚簇索引和非聚簇索引. 在InnoDB中,只有主键索引是聚簇索引,如果没有主键,则挑选一个唯一键建立聚簇索引.如果没有唯一键,则隐式的生成一个键来建立聚簇索引.

  当查询使用聚簇索引时,在对应的叶子节点,可以获取到整行数据,因此不用再次进行回表查询.

 

5、非聚簇索引一定会回表查询吗?

答:不一定,这涉及到查询语句所要求的字段是否全部命中了索引,如果全部命中了索引,那么就不必再进行回表查询.

  举个简单的例子,假设我们在员工表的年龄上建立了索引,那么当进行select age from employee where age < 20的查询时,在索引的叶子节点上,已经包含了age信息,不会再次进行回表查询.

题外话:什么是回表查询?

  通俗的讲就是,如果索引的列在 select 所需获得的列中(因为在 mysql 中索引是根据索引列的值进行排序的,所以索引节点中存在该列中的部分值)或者根据一次索引查询就能获得记录就不需要回表,如果 select 所需获得列中有大量的非索引列,索引就需要到表中找到相应的列的信息,这就叫回表。

  根据这个概念,当你使用 Explain 执行查询计划时,当结果中 Extra 出现了 using index、using where、using index condition 等你就认为使用了过滤条件,使用了索引,SQL 优化的还不错。这其实是一种错误的认识。

  因为,使用了索引并不代表查询就最优。从 using index condition、using index & using where 等可以看出,这条 SQL 语句其实是进行了回表的。

  还有些时候,你查看 Explain 执行计划后,发现明明走了索引,为什么还是慢?这里面可能就是存在回表了。下面我们通过一个例子来说明什么是回表。先创建一张表,sql 语句如下:

create table xttblog(
    id int primary key, 
    k int not null, 
    name varchar(16),
    index (k)
)engine = InnoDB;

然后,我们再执行下面的 SQL 语句,插入几条测试数据。

INSERT INTO xttblog(id, k, name) VALUES(1, 2, 'xttblog'),
    (2, 1, '业余草'),
    (3, 3, '业余草公众号');

  假设,现在我们要查询出 id 为 2 的数据。那么执行 select * from xttblog where ID = 2; 这条 SQL 语句就不需要回表。原因是根据主键的查询方式,则只需要搜索 ID 这棵 B+ 树。主键是唯一的,根据这个唯一的索引,MySQL 就能确定搜索的记录。

  但当我们使用 k 这个索引来查询 k = 2 的记录时就要用到回表。select * from xttblog where k = 2; 原因是通过 k 这个普通索引查询方式,则需要先搜索 k 索引树,然后得到主键 ID 的值为 1,再到 ID 索引树搜索一次。这个过程虽然用了索引,但实际上底层进行了两次索引查询,这个过程就称为回表

  也就是说,基于非主键索引的查询需要多扫描一棵索引树。因此,我们在应用中应该尽量使用主键查询

  我这里表里的数据量比较少,如果数据量大的话,你能很明显的看出两次查询所用的时间,很明显使用主键查询效率更高。

                      

                      SQL 回表

 

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

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

 

7、联合索引是什么?为什么需要注意联合索引中的顺序?

答:

   MySQL可以使用多个字段同时建立一个索引,叫做联合索引.在联合索引中,如果想要命中索引,需要按照建立索引时的字段顺序挨个使用,否则无法命中索引.

  具体原因为:

   MySQL使用索引时需要索引有序,假设现在建立了"name,age,school"的联合索引,那么索引的排序为: 先按照name排序,如果name相同,则按照age排序,如果age的值也相等,则按照school进行排序.

   当进行查询时,此时索引仅仅按照name严格有序,因此必须首先使用name字段进行等值查询,之后对于匹配到的列而言,其按照age字段严格有序,此时可以使用age字段用做索引查找,,,以此类推.因此在建立联合索引的时候应该注意索引列的顺序,一般情况下,将查询需求频繁或者字段选择性高的列放在前面.此外可以根据特例的查询或者表结构进行单独的调整.

 

8、创建的索引有没有被使用到?或者说怎么才可以知道这条语句运行很慢的原因?

答:MySQL提供了explain命令来查看语句的执行计划,MySQL在执行某个语句之前,会将该语句过一遍查询优化器,之后会拿到对语句的分析,也就是执行计划,其中包含了许多信息. 可以通过其中和索引有关的信息来分析是否命中了索引,例如possilbe_key,key,key_len等字段,分别说明了此语句可能会使用的索引,实际使用的索引以及使用的索引长度.

 

9、那么在哪些情况下会发生针对该列创建了索引但是在查询的时候并没有使用呢?

答:

  • 使用不等于查询,

  • 列参与了数学运算或者函数

  • 在字符串like时左边是通配符.类似于'%aaa'.

  • 当mysql分析全表扫描比使用索引快的时候不使用索引.

  • 当使用联合索引,前面一个条件为范围查询,后面的即使符合最左前缀原则,也无法使用索引.

 以上情况,MySQL无法使用索引.


事务相关

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、Innodb使用的是哪种隔离级别呢?

答:InnoDB默认使用的是可重复读隔离级别.

 

6、对MySQL的锁了解吗?

答:当数据库有并发事务的时候,可能会产生数据的不一致,这时候需要一些机制来保证访问的次序,锁机制就是这样的一个机制.

  就像酒店的房间,如果大家随意进出,就会出现多人抢夺同一个房间的情况,而在房间上装上锁,申请到钥匙的人才可以入住并且将房间锁起来,其他人只有等他使用完毕才可以再次使用.

 

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

答:从锁的类别上来讲,有共享锁排他锁.

  共享锁: 又叫做读锁. 当用户要进行数据的读取时,对数据加上共享锁.共享锁可以同时加上多个.

  排他锁: 又叫做写锁. 当用户要进行数据的写入时,对数据加上排他锁.排他锁只可以加一个,他和其他的排他锁,共享锁都相斥.

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

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

  他们的加锁开销从大大小,并发能力也是从大到小.


 

存储引擎相关

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

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

  1. InnoDBMyISAM有什么区别?

    • InnoDB支持事物,而MyISAM不支持事物

    • InnoDB支持行级锁,而MyISAM支持表级锁

    • InnoDB支持MVCC, 而MyISAM不支持

    • InnoDB支持外键,而MyISAM不支持

    • InnoDB不支持全文索引,而MyISAM支持。


 

零散问题

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

答:

  char是一个定长字段,假如申请了char(10)的空间,那么无论实际存储多少内容.该字段都占用10个字符,而varchar是变长的,也就是说申请的只是最大长度,占用的空间为实际字符长度+1,最后一个字符存储使用了多长的空间.

  在检索效率上来讲,char > varchar,因此在使用中,如果确定某个字段的值的长度,可以使用char,否则应该尽量使用varchar.例如存储用户MD5加密后的密码,则应该使用char.

 

2、varchar(10)和int(10)代表什么含义?

答:varchar的10代表了申请的空间长度,也是可以存储的数据的最大长度,而int的10只是代表了展示的长度,不足10位以0填充.也就是说,int(1)和int(10)所能存储的数字大小以及占用的空间都是相同的,只是在展示时按照长度展示.

 

3、MySQL的binlog有有几种录入格式?分别有什么区别?

答:有三种格式,statement,row和mixed.

  • statement模式下,记录单元为语句.即每一个sql造成的影响会记录.由于sql的执行是有上下文的,因此在保存的时候需要保存相关的信息,同时还有一些使用了函数之类的语句无法被记录复制.

  • row级别下,记录单元为每一行的改动,基本是可以全部记下来但是由于很多操作,会导致大量行的改动(比如alter table),因此这种模式的文件保存的信息太多,日志量太大.

  • mixed. 一种折中的方案,普通操作使用statement记录,当无法使用statement的时候使用row.

此外,新版的MySQL中对row级别也做了一些优化,当表结构发生变化的时候,会记录语句而不是逐行记录.

 

4、超大分页怎么处理?

答:超大的分页一般从两个方向上来解决.

  • 数据库层面,这也是我们主要集中关注的(虽然收效没那么大),类似于select * from table where age &gt; 20 limit 1000000,10这种查询其实也是有可以优化的余地的. 这条语句需要load1000000数据然后基本上全部丢弃,只取10条当然比较慢. 当时我们可以修改为select * from table where id in (select id from table where age &gt; 20 limit 1000000,10).这样虽然也load了一百万的数据,但是由于索引覆盖,要查询的所有字段都在索引中,所以速度会很快. 同时如果ID连续的好,我们还可以select * from table where id &gt; 1000000 limit 10,效率也是不错的,优化的可能性有许多种,但是核心思想都一样,就是减少load的数据.

  • 从需求的角度减少这种请求….主要是不做类似的需求(直接跳转到几百万页之后的具体某一页.只允许逐页查看或者按照给定的路线走,这样可预测,可缓存)以及防止ID泄漏且连续被人恶意攻击.

  解决超大分页,其实主要是靠缓存,可预测性的提前查到内容,缓存至redis等k-V数据库中,直接返回即可.

  在阿里巴巴《Java开发手册》中,对超大分页的解决办法是类似于上面提到的第一种.

 

 

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

答:

 在业务系统中,除了使用主键进行的查询,其他的我都会在测试库上测试其耗时,慢查询的统计主要由运维在做,会定期将业务中的慢查询反馈给我们.

 慢查询的优化首先要搞明白慢的原因是什么? 是查询条件没有命中索引?是load了不需要的数据列?还是数据量太大?

 所以优化也是针对这三个方向来的,

  • 首先分析语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写.

  • 分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引.

  • 如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表.

 

6、上面提到横向分表和纵向分表,可以分别举一个适合他们的例子吗?

答:  

  横向分表是按行分表.假设我们有一张用户表,主键是自增ID且同时是用户的ID.数据量较大,有1亿多条,那么此时放在一张表里的查询效果就不太理想.我们可以根据主键ID进行分表,无论是按尾号分,或者按ID的区间分都是可以的. 假设按照尾号0-99分为100个表,那么每张表中的数据就仅有100w.这时的查询效率无疑是可以满足要求的.

  纵向分表是按列分表.假设我们现在有一张文章表.包含字段id-摘要-内容.而系统中的展示形式是刷新出一个列表,列表中仅包含标题和摘要,当用户点击某篇文章进入详情时才需要正文内容.此时,如果数据量大,将内容这个很大且不经常使用的列放在一起会拖慢原表的查询速度.我们可以将上面的表分为两张.id-摘要,id-内容.当用户点击详情,那主键再来取一次内容即可.而增加的存储量只是很小的主键字段.代价很小.

  当然,分表其实和业务的关联度很高,在分表之前一定要做好调研以及benchmark.不要按照自己的猜想盲目操作.

 

7、什么是存储过程?有哪些优缺点?

答:

  存储过程是一些预编译的SQL语句。1、更加直白的理解:存储过程可以说是一个记录集,它是由一些T-SQL语句组成的代码块,这些T-SQL语句代码像一个方法一样实现一些功能(对单表或多表的增删改查),然后再给这个代码块取一个名字,在用到这个功能的时候调用他就行了。2、存储过程是一个预编译的代码块,执行效率比较高,一个存储过程替代大量T_SQL语句 ,可以降低网络通信量,提高通信速率,可以一定程度上确保数据安全

  但是,在互联网项目中,其实是不太推荐存储过程的,比较出名的就是阿里的《Java开发手册》中禁止使用存储过程,我个人的理解是,在互联网项目中,迭代太快,项目的生命周期也比较短,人员流动相比于传统的项目也更加频繁,在这样的情况下,存储过程的管理确实是没有那么方便,同时,复用性也没有写在服务层那么好.

 

8、说一说三个范式

答:

  第一范式: 每个列都不可以再拆分.

  第二范式: 非主键列完全依赖于主键,而不能是依赖于主键的一部分.

  第三范式: 非主键列只依赖于主键,不依赖于其他非主键.

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

 

9、MyBatis中的#

答:

  # 会将传入的内容当做字符串,而有什么区别?∗∗乱入了一个奇怪的问题.....我只是想单独记录一下这个问题,因为出现频率太高了.#会将传入的内容当做字符串,而会直接将传入值拼接在sql语句中.

  所以#可以在一定程度上预防sql注入攻击.

 

 

 

资料出处:https://www.itcodemonkey.com/article/15662.html

     https://juejin.im/post/5d351303f265da1bd30596f9

posted @ 2019-08-14 23:55  myseries  阅读(1337)  评论(0编辑  收藏  举报