【数据库】- MySQL基础精要

NOTE: 特别说明,本文的所有内容并非原创,都是摘自下面所说的链接,如果侵权,请联系删除!!,具体详见MySQL系列文章,建议按照顺序仔细阅读,会有不一样的收获,帮助你完善自己的知识体系

MySQL数据类型

  • 数据库底层使用表来存放数据的,一张表有很多列,每个列都有可能存放不同格式的数据,不同格式的数据是不能混用的,所以MySQL提出了许多类型来存储不同格式的数据。
  • 用来存储整数的类型有TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT这几种,它们需要的存储空间不同,所以能表示的整数范围也不同。
  • 用来存储小数的有FLOAT、DOUBLE、DECIMAL类型,前两个属于浮点型,后一个属于定点型,浮点型更省存储空间,而定点型更精确,这些表示小数的类型都可以使用(M, D)来指定小数的有效位数和小数位数。
  • 用来存储字符串的有CHAR(M)、VARCHAR、TEXT、MEDIUMTEXT、LONGTEXT这几种,它们实际占用的字节存储空间依赖与我们当前使用的字符编码,因为在不同编码下,同一个字符可能被编码成不同长度的字节数据,其中的CHAR(M)是固定长度的类型,其余集中都是可变长度的类型,真实长度取决于实际的字符串长度。
  • 用来存储时间的有YEAR、DATE、TIME、DATETIME、TIMESTAMP这几种类型,需要注意的是,在在MySQL5.6.4这个版本之后,TIME、DATETIME、TIMESTAMP这几种类型添加了对小数秒的支持,但是存储小数秒又要使用额外的存储空间。另外,TIMESTAMP这种类型存储的是自1970-01-01 00:00:00时刻起的秒数,所以在不同时区下会显示不同的时间值。
  • 用来存储二进制数据的有BIT(M)、BINARY(M)、VARBINARY(M)、TINYBLOB、BLOB、MEDIUMBLOB、LONGBLOB这几种,除了BIT(M)是以二进制位为单位的以外,其余的类型都是以字节为单位的,并且它们的使用类似字符串中的各种类型,只不过一个是以字符为单位,一个以字节为单位而已

NOTE: MySQL数据类型

数据库的基本操作

  • MySQL的基本运行过程是:客户端程序发送命令给服务器程序,服务器程序按照接收的命令去操作实际的数据,然后把结果返回到客户端。
  • 在MySQL客户端输入命令时有一些注意事项:
    • ;、\g、\G都可以作为命令结束符号。
    • 只要按回车键的时候输入的语句里没有;、\g或者\G就算是语句没结束,可以换行后继续输入命令。
    • 可以一次提交多个命令。
    • 使用\c清除本次操作。
    • MySQL默认对命令的大小写并没有限制。
    • 字符串可以被单引号’或者双引号”引起来,但是我们推荐使用单引号’。
  • MySQL服务器可以包含若干数据库,每个数据库中可以包含若干个表。
  • 数据库相关操作如下:
    • 展示数据库:SHOW DATABASES;
    • 创建数据库:CREATE DATABASE 数据库名;
    • 切换当前数据库:USE 数据库名
    • 删除数据库:DROP DATABASE 数据库名
    • IF EXISTS 和 IF NOT EXISTS在创建和删除数据库时使用可以避免ERROR产生。

MySQL表结构的基本操作(上)

  • 创建表:
        CREATE TABLE 表名 (
            列名, 列的类型, [列的属性] COMMENT '列的注释',
            ... (若干个列的信息)
        ) COMMENT '表的注释';
    
  • 删除表:DROP TABLE 表名;
  • 各种约束性条件
    • 默认值:在插入语句中没有指定该列的值的情况下,使用默认值,声明语法如下:
        列名 列的类型 DEFAULT 默认值
      
    • 非空约束:声明了该属性的列不允许插入NULL值,声明语法:
      列名 列的类型 NOT NULL
      
    • 主键:唯一标识一条记录,并且一个表中最多字能有一个主键,主键值不能为NULL,声明语法:
      • 方式一:
        列名 列的类型 PRIMARY KEY
        
      • 方式二:
        PRIMARY KEY (列名1, 列名2, ...)
        
    • 唯一性约束:唯一标识一条记录,一个表中可以有多个唯一性约束,并且值可以为NULL,声明语法:
      • 方式一:
        列名 列的类型 UNIQUE [KEY]
        
    • 方式二:
        UNIQUE [KEY] [约束名称] (列名1, 列名2, ...)
      
    • 外键:表A的某个列或列组合的值依赖表B的某个列或列组合的值,则成表A为子表,表B为父表,表A的该列或者列组合称为外键,声明外键的方式如下:
      CONSTRAINT [外键名称] FOREIGN KEY(列1, 列2, ...) REFERENCES 父表名(父列1, 父列2, ...);
      
    • 自增:在插入语句没有包含自增列的情况下,该列的值会递增,声明方式如下:
      列名 列的类型 AUTO_INCREMENT
      

NOTE: MySQL表结构的基本操作(上)

表的基本操作(下)

  • 可以在列信息或者表信息后边用COMMENT语句添加注释。

  • 建议大家不要起各种非主流的名称,也不要使用全数字、带有空白字符或者MySQL保留字的名称,如果非要用的话需要用反引号``引起来,我们鼓励使用小写字母、数字、下划线、美元符号等作为名称,如果有多个单词的话,各个单词之间用下划线连接起来。

  • 可以用下边这些语句查看表结构:

    • DESCRIBE 表名;
    • DESC 表名;
    • EXPLAIN 表名;
    • SHOW COLUMNS FROM 表名;
    • SHOW FIELDS FROM 表名;
    • SHOW CREAETE TABLE 表名;
  • 如果声明了ZEROFILL 属性的整数列的实际值的位数小于显示宽度时,会在实际值的左侧补0,使补0的位数和实际值的位数相加正好等于显示宽度。使用时有一堆注意事项:

    • 该列必须是整数类型的

    • 该列必须有UNSIGNED ZEROFILL的属性

    • 该列的实际值的位数必须小于显示宽度

    • 在查询时,数据自动补0的条件有这几个:

    • 在创建表的时候,如果声明了ZEROFILL属性的列没有声明UNSIGNED属性,那MySQL会为该列自动生成UNSIGNED属性。

    • 每个整数类型都会有默认的显示宽度。

    • 显示宽度并不会影响实际类型的实际存储空间。

    • 对于没有声明ZEROFILL属性的列,显示宽度没有一毛钱卵用。

    • 只有列的实际值的位数小于显示宽度时才会补0,实际值的位数大于显示宽度时照原样输出。

  • 修改表的相关操作如下:

    • 修改列名

      • 方式一:
        ALTER TABLE 表名 MODIFY 列名 新数据类型 [新属性] [FIRST|AFTER 指定列名];
        
      • 方式二:
        ALTER TABLE 表名 CHANGE 旧列名 新列名 新数据类型 [新属性] [FIRST|AFTER 指定列名];
        
    • 修改表名

      • 方式一:
          ALTER TABLE 旧表名 RENAME TO 新表名;
        
      • 方式二:
          RENAME TABLE 旧表名1 TO 新表名1, 旧表名2 TO 新表名2, ... 旧表名n TO 新表名n;
        
    • 添加列:
      ALTER TABLE 表名 ADD COLUMN 列名 列的类型 [列的属性] [FIRST|AFTER 指定列名];
      
    • 删除列:
      ALTER TABLE DROP COLUMN 列名;
      

NOTE: 表的基本操作(下)

查询简介(一)

  • 我们可以在SELECT后边指定要查询的列的列表,然后在FROM后边指定要查询的表,可以只查询单个列的值,也可以查询多个列的值,也可以使用*简单的代表查询所有列的值。

  • 如果我们想去除重复结果的话,可以使用DISTINCT放在被查询的列前边。需要注意的是,两条记录重复的意思是,所以使用DISTINCT在多个列上会把两条记录的每一个列中的值都相同的重复行去掉,而不能做到不能做到一部分列去重,另一部分不去重。

  • 使用LIMIT语句限制查询结果的行数,LIMIT子句可以携带两个参数,其中开始行指的是我们想从第几行数据开始查询,限制条数是查询结果最多返回的记录条数。参数开始行可以被省略,默认从第0行开始。

  • 如果我们想让返回结果中的记录按照某种特定的规则排序,那我们必须显式的使用ORDER BY指定排序规则。其中,ASC指按照指定列的值的升序排序,DESC指按照指定列的值的降序排序。如果ORDER BY子句后有多个列的话,会先按照前边的列进行排序,如果前边的列的值相同,在相同的这些行中再按照后边的列进行排序。

查询简介(二)之操作符

  • 我们需要将搜索条件放到WHERE子句中。针对不同的搜索条件,MySQL提供了非常丰富的操作符。
  • 如果某一列可以匹配的值有多个,可以使用IN或者NOT IN操作符。
  • 判断某个列的值是不是NULL,需要用IS NULL或者IS NOT NULL操作符。
  • 我们可以将多个简单的搜索条件合并在一起组成一个更大搜索条件,各个简单的搜索条件可以用下边的几种操作符连接起来:
    • AND操作符:该操作符两边的搜索条件全部满足后整个搜索条件才算满足。
    • OR操作符:该操作符两边的搜索条件只需要满足一个整个搜索条件就满足了
  • %代表任意一个字符串,_代表任意一个字符。如果需要把这两个通配符当作pu t不过需要特别注意的是,通配符不能代表NULL,如果需要匹配NULL的话,需要使用IS NULL或者IS NOT NULL!
  • %代表任意一个字符串,_:代表任意一个字符。如果需要把通配符当作普通字符看待的话,需要使用反斜杠\进行转义。另外,通配符不能代表NULL,如果需要匹配NULL的话,需要使用IS NULL或者IS NOT NULL

NOTE: 以下主要是将如何利用SQL进行数据分析,类似于ElasticSearch的聚合数据分析

查询简介(三)之表达式和函数

  • 表达式由操作数和操作符构成,单个的操作数也可以被当作是一个表达式,通常将表达式用在查询列表或者搜索条件处。

    • 常数
    • 列名
    • 函数调用
    • 子查询
    • 操作数可以是下边这几种类型:
      • 常数 常数很好理解,我们平时用到的数字、字符串、时间值什么的都可以被称为常数,它是一个确定的值,比如数字1,字符串’abc’,时间值2018-03-05 16:12:46啥的。

      • 列名 针对某个具体的表,它的列名可以被当作表达式的一部分,比如对于student_info表来说,number、name都可以作为操作数。

      • 函数调用 MySQL中有函数的概念,比方说我们前边提到的获取当前时间的NOW就算是一个函数,而在函数后边加个小括号就算是一个函数调用,比如NOW()。 如果你不清楚函数的概念,我们之后会详细唠叨的,现在不知道也可以~

    • 子查询

    • 常用的操作符可以是下边这几种类型:
      • 算数操作符
      • 比较操作符
      • 逻辑操作符
  • MySQL内置了许多函数来帮我们解决一些我们经常遇到的问题,我们常用到的函数有下边这些:

    • 文本处理函数
    • 日期和时间处理函数
    • 数值处理函数
    • 聚集函数 其中,聚集函数比较特殊,它是用来统计数据的。

查询简介(四)之类型转换和分组查询

  • 可能发生转换的场景有下边这几种:
    • 把操作数类型转换为适合操作符计算的相应类型。
    • 将函数参数转换为该函数期望的类型。
    • 存储数据时,把某个值转换为某个列需要的类型。
  • 类型转换时需要注意的一些地方:

    • MySQL会尽量把值转换为表达式中需要的类型,而不是产生错误。
    • 在运算时可能会自动提升操作数的类型。
  • MySQL使用GROUP BY子句创建分组,方便我们统计信息。分组的存在仅仅是为了方便我们统计每个分组中的信息,所以我们只需要把分组列和聚集函数放到查询列表处就好。

  • 对每个分组的统计信息进行过滤使用HAVING子句。

  • 使用分组注意事项:
    • 如果分组列中含有NULL值,那么NULL也会作为一个独立的分组存在。
    • 如果存在多个分组列,也就是嵌套分组,聚集函数将作用在最后的那个分组列上。
    • 如果查询语句中存在WHERE子句和ORDER BY子句,那么GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前。
    • 非分组列不能单独出现在检索列表中(可以被放到聚集函数中)。
    • GROUP BY子句后也可以跟随表达式(但不能是聚集函数)。
    • WHERE子句在数据分组前进行过滤,作用于每一条记录,WHERE子句过滤掉的记录将不包括在分组中。而HAVING子句在数据分组后进行过滤,作用于整个分组。
  • 简单的查询语句的格式如下:
    SELECT [DISTINCT] 查询列表
    [FROM 表名]
    [WHERE 布尔表达式]
    [GROUP BY 分组列表 [HAVING 分组过滤条件] ]
    [ORDER BY 排序列表]
    [LIMIT 开始行, 限制条数]
  • 其中各个部分的含义如下:

    • SELECT 查询列表:

      指定要查询的对象,可以是任意的合法表达式,不过通常我们都是指定列名为查询对象的。

    • [DISTINCT]

      在查询列表前指定DISTINCT,会将结果集中相同的记录去除掉。

    • FROM 表名

      指定要查询的表。

    • WHERE 布尔表达式

      对表中的记录进行过滤,符合指定布尔表达式的记录将被加入到结果集。

    • GROUP BY 分组列表 [HAVING 分组过滤条件]:

      在统计数据的时候,可以按照分组列表中的列或者表达式将结果分成若干组,分组之后可以使用聚集函数对各组数据进行统计。如果有过滤分组的需求,可以使用HAVING子句来进行过滤。

    • ORDER BY 排序列表:

      查询语句并不保证得到的结果集中记录是有序的,我们可以通过指定ORDER BY子句来明确要排序的列。

    • LIMIT 开始行, 限制条数:

      如果最后查询的得到的结果集中记录太多,我们可以通过LIMIT子句来指定结果集中开始查询的行以及一次查询最多返回的记录条数。

查询简介(五)之子查询

  • 标量子查询的结果只有一个值,如果结果有多个值的话会报错,可以在查询语句末尾使用LIMIT 1来保证只有一条结果。

  • 子查询的查询列表和外层查询WHERE子句的搜索条件要匹配!如果外层查询的WHERE子句中的表达式个数大于1个,需要用小括号()扩起来。

  • 在引用的列可能出现二义性时,必须使用列的全限定名(也就是用一个点.分隔的表名和列名)来注明该列所属的表。

  • 相关子查询是涉及外部查询的子查询,一般用在EXISTS和NOT EXISTS子查询里。

查询简介(六)之连接查询

连接本质上就是各个表的记录在符合连接条件下的自由组合。一个表中的每一条记录与另一个表中的每一条记录得到全部可能的组合的过程称之为生成笛卡尔积,这个笛卡尔积非常庞大,没有什么意义,我们在连接表的时候通常都会指明连接条件,也就是一个表中列的值和另一个表中列的值的关系。

重点是理解连接查询的过程

  • 有两种非常重要的连接类型:

    • 内连接:对于两个用于连接的表,任何一方的记录和另外一个表中任意一条记录的组合都不符合连接条件,那这条记录就不会被加入到最后的结果集。即是取交集
    • 自连接
    • 外连接:即使某条记录没有在另一个表中任意一条记录与它匹配,它也可以被加入结果集中。通常外连接分为这两种类型:
      • 左外连接
      • 右外连接
    • 使用外链接注意事项
      • 必须使用 ON 来明确连接条件
      • 普通搜索条件优先级更高

查询简介(七)之组合查询

  • 被合并的各个查询的查询对象个数必须相同。

  • 不能一个查询的结果集中有1个列,另一个却有2个列,这会报错的

  • 查询的结果集中显示的列名将以第一个查询中的列名为准。

  • 各个查询语句中的查询列表的类型兼容就可以(也就是说不必完全相同)。

    m1的类型是整数类型,n2是字符串类型,如果把这两个查询用UNION合并起来,那么整个结果集的的列的类型将变成字符串类型。虽然这种类型转换是支持的,但是将不同类型的数据放在一个列中容易造成混乱,还是建议大家将各个查询的查询列表置为相同的类型。

数据的插入、删除和更新

  • 使用INSERT语句来向表中插入数据,可以使用这两种方式:

    • 不指定需要插入数据的列:
      INSERT INTO 表名 VALUES(列1的值,列2的值, ..., 列n的值);
      

      这种方式高度依赖表中列的顺序,不推荐使用。

    • 显式指定需要插入数据的列
      INSERT INTO 表名(列1, 列2, ..., 列n) VALUES(列1的值,列2的值, ..., 列n的值);
      

      推荐使用这种方式进行插入,在表结构允许的情况下还可以只对部分列进行插入。

  • 直接在VALUES后多加几组值,每组值用小括号()扩起来并用逗号分隔就好了就是批量插入语句。

  • 对于主键或者有唯一性约束的列或列组合来说,新插入的记录如果和表中已有的记录重复的话,我们可以选择下边这两种插入策略:

    • 插入或忽略

      使用INSERT IGNORE语法,如果表中没有重复的记录,则插入,如果表中有重复的记录,则忽略本次插入。

    • 插入或更新

      使用INSERT ... ON DUPLICATE KEY UPDATE ...语法,如果表中没有重复的记录,则插入,如果表中有重复的记录,则按照规定更新这些重复记录中某些列的值。

  • 删除记录的语法很简单:
    DELETE FROM 表名 [WHERE 布尔表达式];
    
  • 更新记录的语法也很简单:
    UPDATE 表名 SET 列1=值1, 列2=值2, ...,  列n=值n [WHERE 布尔表达式];    
    

视图简介

视图也被称为虚拟表,因为我们可以对视图进行一些类似表的增删改查操作,只不过我们对视图的相关操作都会被映射到那个又臭又长的查询语句对应的底层的表上。

  • 创建视图
CREATE VIEW 视图名 AS 查询语句
  • 利用视图来创建新视图

  • 查看和删除视图
    • 查看
      SHOW CREATE VIEW 视图名
      
    • 删除
      DROP VIEW 视图名
      
  • 更新视图

不过并不是可以在所有的视图上执行更新语句的,在生成视图的时候使用了下边这些语句的都不能进行更新:

  • 分组
  • 连接查询
  • 子查询
  • 组合查询
  • 聚集函数
  • DISTINCT
  • 查询列表上是非列名的表达式

虽然有这么多限制,但是需要我们注意的是,一般情况下,我们只在视图上执行查询操作而不进行更新操作!这里介绍对视图的更新只是为了语法的完整性,并不是建议大家在实际使用过程中使用对视图的更新功能。

存储程序(一)之自定义变量简介

  • 存储程序组成

    存储程序分为存储例程、触发器和事件这几种类型。其中,存储例程又可以被细分为存储函数和存储过程

  • 自定义变量简介

    变量是和常量相对的,一般的程序语言都提供对变量的支持,MySQL中对我们自定义的变量的命名有个要求,那就是变量名称前必须加一个@符号

  • 复合语句

    delimiter $命令意味着修改MySQL客户端检测输入结束的符号为$,所以虽然我们连续输入了3个以分号;结尾的查询语句并且按了回车键,输入的内容并没有被提交,直到敲下$符号并回车,MySQL客户端才会将我们输入的内容提交到服务器,此时我们输入的内容里已经有3个独立的查询语句了,所以返回了3个结果集。

存储程序(二)之存储函数简介

存储例程是存储程序的一种类型,本质上也是封装了一些可执行的语句,只不过它的调用方式是:需要手动去调用!存储例程又可以分为存储函数存储过程 存储函数和一般的编程语言的语法有很多类似的特性,比如if,while,loop flag ,注释使用

  • 存储函数语法

存储函数其实就是一种函数,只不过在这个函数里可以执行命令语句而已。函数的概念大家都应该不陌生,它可以把处理某个问题的过程封装起来,之后我们直接调用函数就可以去解决同样的问题了,跟普通的程序语言函数有很多类似之处

CREATE FUNCTION 存储函数名称([参数列表])
RETURNS 返回值类型
BEGIN
    函数体内容
END

存储程序(三)之存储过程简介

  • 创建存储过程

存储函数和存储过程都属于存储例程,都是对某些语句的一个封装。存储函数侧重于执行这些语句并返回一个值,而存储过程更侧重于单纯的去执行这些语句

CREATE PROCEDURE 存储过程名称([参数列表])
BEGIN
    需要执行的语句
END    

存储过程和存储函数都是某些语句的一个封装,而且使用的语法格式都是一样的,下边我们着重说一下它们的不同点以加深大家的对这两者区别的印象:

  • 存储函数在定义时需要显式用RETURNS语句标明返回的数据类型,而且在函数体中必须使用RETURN语句来显式指定返回的值,存储过程不需要。
  • 存储函数的参数类型只能是IN,而存储过程支持IN、OUT、INOUT三种参数类型。
  • 存储函数只能返回一个值,而存储过程可以通过设置多个OUT类型的参数来返回多个结果。
  • 存储函数执行过程中产生的结果集并不会被显示到客户端,而存储过程执行过程中产生的结果集会被显示到客户端。
  • 存储函数的调用直接使用在表达式中,而存储过程只能通过CALL语句来显式调用。

存储程序(四)之游标简介

  • 游标既可以用在存储函数中,也可以用在存储过程中,我们下边以存储过程为例来说明游标的使用方式,它的使用大致分成这么四个步骤:

    • 创建游标
      DECLARE 游标名称 CURSOR FOR 查询语句;
      
    • 打开游标
      OPEN 游标名称;
      
    • 通过游标访问记录

      • 使用游标获取记录
        FETCH 游标名 INTO 变量1, 变量2, ... 变量n
        
      • 遍历结束时的执行策略

      其实在FETCH语句获取不到记录的时候会触发一个事件,从而我们可以得知所有的记录都被获取过了,然后我们就可以去主动的停止循环。MySQL中响应这个事件的语句如下:

      DECLARE CONTINUE HANDLER FOR NOT FOUND 可执行语句;  
      

      CONTINUE表示在FETCH语句获取不到记录的时候仍然会执行之后存储过程的语句,EXIT表示在FETCH语句获取不到记录的时候仍然不会执行之后存储过程的语句

      DECLARE EXIT HANDLER FOR NOT FOUND SET not_done = 0;
      
    • 关闭游标
      CLOSE 游标名称;
      

存储程序(五)之触发器和事件简介

  • 视图本质上就是某个查询语句的别名,我们对视图的相关操作都会被映射到那个又臭又长的查询语句对应的底层的表上。

  • 存储程序本质上是一些可执行的MySQL语句,根据调用情况不同分为3种类型,分别是存储例程、触发器和事件。

  • 存储例程需要我们手动去掉用,具体分为存储函数存储过程两种类型。

  • 触发器是在执行某条语句之前或者之后自动去调用另外一些语句。

  • 事件是定时执行的。

MySQL命令执行过程和存储引擎概述

  • 以查询请求为例,服务器程序处理客户端发送过来的请求大致分为三部分:

    • 第一部分:连接管理。

      主要是负责连接的建立与信息的认证。

    • 第二部分:解析与优化。

      这一部分分为三个步骤处理:查询缓存语法解析查询优化

    • 第三部分:存储引擎。

      主要负责对底层数据表中的数据进行提取和写入工作。

  • MySQL支持的存储引擎有好多好多种,它们在完成不同的功能上各有优劣,我们常用的就是InnoDB和MyISAM,其中InnoDB是服务器程序的默认存储引擎。

  • 一些常用的关于存储引擎的用法如下:

    • 查看当前服务器程序支持的存储引擎:
      SHOW ENGINES;
      
    • 创建表时指定表的存储引擎:
      CREATE TABLE 表名(
          建表语句;
      ) ENGINE = 存储引擎名称;
      
    • 修改表的存储引擎:
      ALTER TABLE 表名 ENGINE = 存储引擎名称;
      

MySQL的基本管理

  • MySQL服务器程序在类Unix系统的启动方式:

    • mysqld
    • mysql_safe
    • mysql.server
    • mysql_multi
  • MySQL服务器程序在Windows系统的启动方式:

    • mysqld
    • 以服务的方式启动:net start MySQL
  • 在服务器端关闭服务器程序:

    • 类Unix系统的关闭方式:mysql.server stop
    • Windows系统的以服务的方式关闭:net stop MySQL
  • 在客户端关闭服务器程序:

    • 通过语句关闭:mysql> shutdown;
    • 通过mysqladmin命令关闭 mysqladmin -h [主机名] -u [用户名] -p shutdown;
  • 启动选项是在服务器程序启动时我们程序员传递的一些参数,添加启动选项的方式:

    • 命令行中添加
    • 配置文件中添加
  • 系统变量是服务器程序里维护的一些变量,这些变量影响着服务器的行为。修改系统变量的方式:

    • 通过添加启动选项修改

    • 运行时通过SET语句修改,下边两种方式都可以:
      SET [GLOBAL|SESSION] 系统变量名 = 值;
      SET [@@(GLOBAL|SESSION).]var_name = XXX;
      

      其中的作用范围的意思如下:

      • GLOBAL:对所有客户端都有效。
      • SESSION:只对本客户端有效。
    • 查看系统变量的方式

   SHOW [GLOBAL|SESSION] VARIABLES [LIKE 匹配的模式];

  • 状态变量是用来显示服务器程序运行状况的,我们只能查看,查看方式是:
    SHOW [GLOBAL|SESSION] STATUS [LIKE 匹配的模式];
    

字符集和编码

一个字符集从诞生到真正让计算机使用大致要经历下边5个步骤:

  • 明确包含字符的范围

    这个步骤就是确定字符集里应该包含哪些字符。比如ASCII字符集收录128个字符,而GB2312字符集收录7445个字符。

  • 给步骤1中确定的字符进行编号

    对于字符集中已经确定的字符,想个办法让某个字符和某个数字建立一一对应关系。

    因为ASCII字符集包含的字符较少,只有128个,所以编号方式也简单粗暴,直接每一个字符指定一个0~127的数字,比如给字符A编号为65。但是比较复杂的字符集就会温柔一点,比如GB2312字符集用了区位码的方式来给字符编号,我们稍后详细唠叨各种字符集是怎么编号的。

    NOTE: 特别注意:本步骤中的编号是一个纯数学编号,与计算机存储没任何关系。与下边步骤中的编码是两个完全不同的概念!!

  • 将步骤2中的编号确定逻辑上的字符编码

    计算机只能认识二进制,要把字符存到计算机里需要把字符编号映射为二进制数据。这种映射有的是直接把编号映射为二进制数据,有的因为一些原因不能直接映射,采用一些算法来计算出该编号对应的二进制数据。

    但是用二进制表示字符需要注意一下这些事:

    • 对于一段文本的二进制文件,计算机一次应该读多少位呢?

      计算机里是以字节(8位)为基本处理单位的,所以一次读的位数应该是8的倍数。 不同的字符集编码有不同的规定,有的一次读一个字节,有的一次读2个,有的一次读4个。我们把计算机一次读的字节称为编码单位(英文名叫Code Unit),也叫码元

    • 一个字符应该占几个码元呢?

      比如拿ASCII字符集来说,它一共收录了128个字符,ASCII编码规定1个字节作为1个码元,所以ASCII字符集一个码元就可以表示一个字符。

      但是有的编码方式一个码元可能占用好几个字节,而且收录的字符数量也都不同

      逻辑字符编码的意思就是把步骤2中的字符编号映射为一个二进制数字,并且规定好码元大小。所以一个字符就可以表示成一个或几个码元排列起来的二进制数字,我们称之为码元序列。有的时候为了简便,我们把逻辑字符编码就简称为编码

      对于同一种字符集,因为从编号映射到二进制数据的方式不同或者采用的码元大小不一样,同一种字符集也可能有多种编码方式。

  • 给步骤3中确定的逻辑上的字符编码生成物理上的字符编码。

    对于步骤3确定的二进制数字,是跟特定的计算机系统平台无关的逻辑意义上的编码,那么所谓的物理上的字符编码就是跟特定的计算机系统平台有关的更具体的编码。

    这个主要是针对码元是多个字节的情况,码元为单个字节的可以认为步骤3和步骤4是一样的。字节的排列顺序会收到不同系统的影响。我们下边在说多字节码元的编码方式的时候仔细说这个问题。

    经过物理编码后的二进制序列,我们称之为字节序列。当然,很多时候码元序列字节序列的值是一样的。

  • 面向计算机更底层,进行进一步的适应性编码处理。

    这一部分涉及计算机硬件怎么优化处理,我们并不需要了解,但是出于礼貌,还是要照抄一下(一般包括两种):

    • 一种是把字节序列映射到一套更受限制的值域内,以满足传输环境的限制,例如用于Email传输的Base64编码或者quoted-printable编码(可打印字符引用编码),都是把8位的字节映射为7位长的数据(Email协议设计为仅能传输7位的ASCII字符);

    • 另一种是压缩字节序列的值,如LZW或者进程长度编码等无损压缩技术。

需要特别注意的是,我们平时简称的编码,如果作为动词来理解的话,可能是执行步骤3,也可能是步骤3和步骤4一块儿执行;如果作为名词来理解的话,也能是步骤3执行完一个字符对应的码元序列,也可能是步骤4执行完的实际的字节序列。这个编码这个词的含义需要放到上下文中进行理解但是编码和编号的区别是明显的!!。

MySQL的字符集和比较规则

  • 字符集的是某个字符范围的编码规则。

  • 比较规则是针对某个字符集中的字符比较大小的一种规则。

  • 在MySQL中,一个字符集可以有若干种比较规则,其中有一个默认的比较规则,一个比较规则必须对应一个字符集。

  • 查看MySQL中查看支持的字符集和比较规则的语句如下:
    SHOW (CHARACTER SET|CHARSET) [LIKE 匹配的模式];
    SHOW COLLATION [LIKE 匹配的模式];
    
  • MySQL有四个级别的字符集和比较规则

    • 服务器级别

      haracter_set_server表示服务器级别的字符集,collation_server表示服务器级别的比较规则。

    • 数据库级别

      创建和修改数据库时可以指定字符集和比较规则:

      CREATE DATABASE 数据库名
          [[DEFAULT] CHARACTER SET 字符集名称]
          [[DEFAULT] COLLATE 比较规则名称];
      ALTER DATABASE 数据库名
          [[DEFAULT] CHARACTER SET 字符集名称]
          [[DEFAULT] COLLATE 比较规则名称];
      

      character_set_database表示当前数据库的字符集,collation_database表示当前数据库的比较规则,这两个系统变量是只读的,不能修改。

    • 表级别

      创建和修改表的时候指定表的字符集和比较规则:

      CREATE TABLE 表名 (列的信息)
          [[DEFAULT] CHARACTER SET 字符集名称]
          [COLLATE 比较规则名称]]
      ALTER TABLE 表名
          [[DEFAULT] CHARACTER SET 字符集名称]
          [COLLATE 比较规则名称]
      
    • 列级别

      创建和修改列定义的时候可以指定该列的字符集和比较规则:

      CREATE TABLE 表名(
          列名 字符串类型 [CHARACTER SET 字符集名称] [COLLATE 比较规则名称],
          其他列...
      );
      ALTER TABLE 表名 MODIFY 列名 字符串类型 [CHARACTER SET 字符集名称] [COLLATE 比较规则名称];
      
  • 从发送请求到接收结果过程中发生的字符集转换:

    • 客户端使用操作系统的字符集编码请求字符串

    • 服务器将客户端发送来的字符串的字符集按照chacharacter_set_client转换为character_set_connection

    • 使用character_set_connection进行服务器操作。

    • 将结果集字符串的字符集从character_set_connection转为character_set_results发送到客户端

    • 客户端使用操作系统的字符集解析收到的结果集字符串

      在这个过程中各个系统变量的含义如下:

      系统变量 描述
      character_set_client 服务器解码请求时使用的字符集
      character_set_connection 服务器运行过程中使用的字符集
      character_set_results 服务器向客户端返回数据时使用的字符集

      一般情况下要使用保持这三个变量的值和客户端使用的字符集相同。

  • 比较规则的作用通常体现比较字符串大小的表达式以及对某个字符串列进行排序中。

常见问题

Mysql链接问题

  • 堆栈信息
** BEGIN NESTED EXCEPTION **

java.net.SocketException
MESSAGE: java.security.AccessControlException: access denied (java.net.SocketPermission 
127.0.0.1:3306 connect,resolve)

STACKTRACE:

java.net.SocketException: java.security.AccessControlException: access denied 
(java.net.SocketPermission 127.0.0.1:3306 connect,resolve)
        at com.mysql.jdbc.StandardSocketFactory.unwrapExceptionToProperClassAndThrowIt(StandardSocketFactory.
java:407)
        at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:268)

......

  • 解决方案

This is a Java exception, caused by your java.policy file. Its in your JAVA_HOME/jre/lib/security folder. Heres where it is in Ubuntu (using java 6).

/usr/lib/jvm/java-6-sun/jre/lib/security/java.policy

You need to add the following lines:

grant{
permission java.net.SocketPermission "127.0.0.1:3306", "connect, resolve";
};

Search

    Post Directory