MySQL必知必会——全球化和本地化

字符集为字母和符号的集合。编码为某个字符集成员的内部表示;校对为规定字符如何比较的指令。在MySQL的正常数据库活动(select、insert等)中,使用何种字符集和校对的决定在服务器、数据库和表级进行。

MySQL支持众多的字符集。为查看所支持的字符集完整列表,可以使用如下语句:

show character set; 这条语句显示所有可用的字符集以及每个字符集的描述和默认校对。

查看所支持校对的完整列表,可以使用如后语句: show collation; 此语句显示所用可用的校对,以及它们适用的字符集。而且许多校对出现两次,一次区分大小写(由_cs表示),一次不分区大小写(由_ci表示)。

一般地,MySQL如下确定使用什么样的字符集和校对。

1)如果指定character set和collate两者,则使用这些值。

2)如果只指定character set,则使用此字符集及其默认的校对。

3)如果即不指定character set,也不指定collate,则使用数据库默认。

最后,值得注意的是,如果绝对需要,串可以在字符集之间进行转换,为此,使用Cast()或Convent()函数。

MySQL必知必会——管理事务处理

并非所有引擎都支持明确的事务处理管理。MyISAM和InnoDB是两种最常用的引擎。前者不支持明确的事务处理管理,而后者支持。事务处理可以用来维护数据库的完整性,它保证成批的MySQL操作要么完全执行,要么完全不执行。

事务处理是一种机制,用来管理必须成批执行的MySQL操作,以保证数据库不包含不完整的操作结果。利用事务处理,可以保证一组操作不会中途停止,它们或者作为整体执行,或者完全不执行(除非明确指示)。如果没有错误发生,整组语句提交给(写到)数据库。如果发生错误,则进行回退(撤销)以恢复数据库到某个已知且安全的状态。

与事务处理相关的术语如下:

1)事务(transaction)指一组SQL语句。

2)回退(rollback)指撤销指定SQL语句的过程。

3)提交(commit)指将未存储的SQL语句结果写入数据库表。

4)保留点(save point)指事务处理中设置的临时占位符,可以对它发布回退(与回退整个事务处理不同)。

管理事务处理的关键在于将SQL语句组分解为逻辑块,并明确规定数据何时应该回退,何时应该不回退。

MySQL使用如下语句来标识事务的开始:

start transaction

MySQL的rollback命令用来回退(撤销)MySQL语句,rollback只能在一个事务处理内使用。

事务处理用来管理insert、update和delete语句。不能回退select语句(这样做也没有什么意义)。不能回退create或drop操作。事务处理块中可以使用这两条语句,但如果执行回退,它们不会被撤销。

一般的MySQL语句都是直接针对数据库表执行和编写的。这就是所谓的隐含提交,即提交(写或保存)操作是自动进行的。但是,在事务处理块中,提交不会隐含地进行。为进行明确的提交,使用commit语句。

当commit或rollback语句执行后,事务会自动关闭(将来的更改会隐含提交)。

创建保留点使用savepoint语句,如:savepoint name 每个保留点都取标识它的唯一名字,以便在回退时,MySQL知道要回退到何处。可以在MySQL代码中设置任意多的保留点,而且是越多越好。保留点在事务处理完成(执行一条rollback或commit)后自动释放。自MySQL 5以来,也可以用release savepoint 明确地释放保留点。

为指示MySQL不自动提交更改,需要使用如下语句:

set autocommit=0;

autocommit标志决定是否自动提交更改,不管有没有commit语句。设置autocommit为0(假)指示MySQL不自动提交更改(直到autocommit被设置为真为止)。autocommit标志是针对每个连接而不是服务器的。

Java核心技术——卷I——泛型程序设计

Java 5中泛型的引入成为Java程序设计语言自最初发行以来最显著的变化。泛型程序设计(generic programming)意味着编写的代码可以对多种不同类型的对象重用。在Java中增加泛型类之前,泛型程序设计是用继承实现的。

ArrayList类有一个类型参数(type parameter)用来指示元素的类型。如后所示: var a=new ArrayList<**String**>(); 如果用一个明确的类型而不是var声明一个变量,则可以通过使用”菱形”语法省略构造器中的类型参数。省略的类型可以从变量的类型推断得出。Java 9扩展了菱形语法的使用范围,原先不接受这种语法的地方现在也可以使用了。如,可以对匿名子类使用菱形语法。类型参数的魅力所在:会让程序更容易读懂,也更安全。

泛型类(generic class)就是有一个或多个类型变量的类。类型变量在整个类定义中用于指定方法的返回类型以及字段和局部变量的类型。常见的做法是类型变量使用大写字母,而且很简短。Java库使用变量E表示集合的元素类型,K和V分别表示表的键和值的类型。T(必要时可以用相邻的字母U和S)表示“任意类型”。可以用具体的类型替换类型变量来实例化泛型类型。换句话说,泛型类相当于普通的工厂。从表面上看,Java的泛型类型类似于C++的模板类。唯一明显的不同是Java没有特殊的template关键字。

可以定义一个带有类型参数的方法。这个方法是在普通类中定义的,而不是在泛型类中。注意,类型变量放在修饰符的后面,并在返回类型的前面。当然,泛型方法可以在普通类中定义,也可以在泛型类中定义。当调用一个泛型方法时,可以把具体类型包围在尖括号中,放在方法名前面。但在C++,要将类型参数放在方法名后面。这有可能会导致解析的二义性。

有时,类和方法需要对类型变量加以约束。而在C++中,不能对模板参数的类型加以限制。Java中使用关键字extends,如后所示:<T extends BoundingTyep>。其中T应该是限定类型(bounding type)的子类型(subtype)。T和限定类型可以是类,也可以是接口。一个类型变量或通配符可以有多个限定,限定类型用 “&”分隔,而逗号用来分隔类型变量。在Java的继承中,可以根据需要拥有多个接口超类型,但最多有一个限定可以是类。如果有一个类作为限定,它必须是限定列表中的第一个限定。

虚拟机没有泛型类型对象——所有对象都是属于普通类。无论何时定义一个泛型类型,都会自动提供一个相应的原始类型(raw type)。这个原始类型的名字就是去掉类型参数后的泛型类型名。类型变量会被擦除(erased),并替换为其限定类型(或者,对于无限定的变量则替换为Object)。原始类型用第一个限定来替换类型变量,或者,如果没有给定限定,就替换为Object。Java的泛型与C++模板有很大的区别。C++会为每个模板的实例化产生不同的类型,这一现象称为“模板代码膨胀”。Java不存在这个问题。

编写一个泛型方法调用时,如果擦除了返回类型,编译器会插入强制类型转换。类型擦除也会出现在泛型方法中。总之,对于Java泛型的转换,需要记住以下几点:

1)虚拟机中没有泛型,只有普通的类和方法。

2)所有的类型参数都会替换为它们的限定类型。

3)会合成桥方法来保持多态。

4)为保持类型安全性,必要时会插入强制类型转换。

设计Java泛型时,主要目标是允许泛型代码和遗留代码之间能够互操作。

不能用基本类型代替类型参数。虚拟机中的对象总有一个特定的非泛型类型。因此,所有的类型查询只产生原始类型。为提醒这一风险,如果试图查询一个对象是否属于某个泛型类型,编译器会报错(使用instanceof时),或给出一个警告(使用强制类型转换时)。不能实例化参数化类型的数组。需要说明的是,只是不允许创建这些数组,而声明变量仍是合法的。不过,不能使用new来初始化这个变量。

可以使用@SafeVarargs注解来消除创建泛型数组的有关限制,不过这会隐藏着危险。@SafeVarargs只能用于声明为static、final或(Java 9)private的构造器和方法。

不能在类似 new T(……)的表达式中使用类型变量。就像不能实例化泛型实例一样,也不能实例化数组。不能在静态字段或方法中引用类型变量。既不能抛出也不能捕获泛型类的对象。实际上,泛型类扩展Throwable甚至都是不合法的。catch子句不能使用类型变量。不过,在异常规范中使用类型变量是允许。Java异常处理的一个基本原则是,必须为所有检查型异常提供一个处理器。不过可以利用泛型取消这个机制。当泛型类型被擦除后,不允许创建引发冲突的条件。泛型规范说明还引用了另外一个原则:“为了支持擦除转换,要施加一个限制:倘若两个接口类型是同一个接口的不同参数化,一个类或类型变量就不能同时作为这两个接口类型的子类。” 总是可以将参数化类型转换为一个原始类型。最后,泛型类可以扩展和实现其他的泛型类。

在通配符类型中,允许类型参数发生变化。通配符限定与类型变量限定十分类似,但是,有一个附加能力,即可以指定一个超类型限定(supertype bound)。带有超类型限定的通配符允许写入一个泛型对象,而带有子类型限定的通配符允许读取一个泛型对象。还可以使用根本无限定的通配符。通配符不是类型变量,因此,不能在编写代码中使用 ”?“ 作为一种类。通配符捕获只有在非常限定的情况下才是合法的。编译器必须能够保证通配符表示单个确定的类型。

泛型Class类的 API如下:

one

Java泛型的突出特性之一是在虚拟机中擦除泛型类型。

为了表述泛型类型声明,可以使用java.lang.reflect包中的接口Type。这个接口包含以下子类型:

1)Class类,描述具体类型。

2)TypeVariable接口,描述类型变量。

3)WildcardType接口,描述通配符。

4)ParameterizedType接口,描述泛型类或接口类型。

5)GenericArrayType接口,描述泛型数组。

Type接口的继承层次如下。注意,最后4个子类型是接口,虚拟机将实例化实现这些接口的适当的类。

two

CDI和Guice等注入框架使用类型字面量来控制泛型类型的注入。

反射和泛型的的部分API如下:

three

four

MySQL必知必会——使用触发器

对触发器的支持是在MySQL 5中增加的。触发器是MySQL响应以下任意语句而自动执行的一条MySQL语句(或位于begin 和 end 语句之间的一组语句):

1)delete;

2)insert;

3)update。

其他MySQL语句不支持触发器。

在创建触发器时,需要给出以下信息:

1)唯一的触发器名;

2)触发器关联的表;

3)触发器应该响应的活动(delete、insert或update);

4)触发器何时执行(处理之前或之后)。

在MySQL 5中,触发器名必须唯一,但不是在每个数据库中唯一。这表示同一数据库的两个表可具有相同名字的触发器。这在其他每个数据库触发器名必须唯一的DBMS中是不允许的,而且以后的MySQL版本很可能会使命名规则更为严格。因此,现在最好是在数据库范围内使用唯一的触发器名。

触发器用 crate trigger 语句创建。只有表才支持触发器,视图不支持(临时表也不支持)。

触发器按每个表每个事件每次地定义,每个表每个事件每次只允许一个触发器。因此,每个表最多支持6个触发器(每条insert、update和delete的之前和之后)。单一触发器不能与多个事件或多个表关联。所以,如果需要对一个insert和update操作执行的触发器,则应该定义两个触发器。

如果 before 触发器失败,则MySQL将不执行请求的操作。此外,如果 before 触发器或语句本身失败,MySQL将不执行 after 触发器(如果有的话)。

触发器不能更新或覆盖。为了修改一个触发器,必须先删除它,然后再重新创建。删除触发器语句为 drop trigger 触发器名。

insert触发器在insert语句之前执行或之后执行。同时要清楚以下几点:

1)在insert触发器代码内,可引用一个new的虚拟表,访问被插入的行。

2)在before insert 触发器中,new中的值也可以被更新(允许更改被插入的值)。

3)对于 auto_increment 列,new在insert执行之前包含0,在insert执行之后包含新的自动生成值。

通常将before用于数据验证和净化(目的是保证插入表中的数据确实是需要的数据)。

delete触发器在delete语句执行之前或之后执行,同时要清楚以下两点:

1)在delete触发器代码内,可以引用一个名为 old 的虚拟表,访问被删除的行。

2)old 中的值全都是只读的,不能更新。

多语句触发器:触发器可以使用begin和end语句标记触发器体。使用begin end块的好处就是触发器能容纳多条SQL语句(在begin end 块中一条挨着一条)。

update触发器在update语句执行之前或之后执行,同时要清楚以下几点:

1)在update触发器代码内,可以引用一个名为 old 的虚拟表访问以前(update语句前)的值,引用一个名为new的虚拟表访问新更新的值。

2)在before update 触发器中,new中的值可能也被更新(允许更改将要用于update语句中的值)。

3)old 中的值全都是只读的,不能更新。

使用触发器时记住以下几点:

1)与其他DBMS相比,MySQL 5中支持的触发器想当初级。

2)创建触发器可能需要特殊的安全访问权限,但是,触发器的执行是自动的。如果,insert、update和delete语句能够执行,则相关的触发器也能执行。

3)应该用触发器来保证数据的一致性(大小写、格式等)。在触发器中执行这种类型的处理的优点是它总是进行这种处理,而且是透明地进行,与客户机应用无关。

4)触发器的一种非常有意义的使用是创建审计跟踪。使用触发器,把更改(如果需要,甚至还有之前和之后的状态)记录到另一个表非常容易。

5)MySQL触发器不支持call语句。这表示不能从触发器内调用存储过程。所需的存储过程代码需要复制到触发器内。

MySQL必知必会——使用游标

MySQL 5添加了对游标的支持。MySQL检索操作返回一组称为结果集的行。这组返回的行都是与SQL语句相匹配的行(零行或多行)。有时,需要在检索出来的行中前进或后退一行或是多行。这就是使用游标的原因。

游标(cursor)是一个存储在MySQL服务器上的数据库查询,它不是一条select语句,而是被该语句检索出来的结果集。在存储了游标之后,应用程序可以根据需要滚动或浏览其中的数据。游标主要用于交互式应用,其中用户需要滚动屏幕上的数据,并对数据进行浏览或做出更改。

只能用于存储过程:不想多数DBMS一样,MySQL游标只能用于存储过程(和函数)。

使用游标涉及的几个明确步骤如下:

1)在能够使用游标前,必须声明(定义)它。这个过程实际上没有检索数据,它只是定义要使用的select语句。

2)一旦声明后,必须打开游标以供使用。这个过程用前面定义的select语句把数据实际检索出来。

3)对于填有数据的游标,根据需要取出(检索)各行。

4)在结束游标使用时,必须关闭游标。

创建游标:游标用 declare 语句创建。declare命名游标,并定义相应的select语句,根据需要带有where和其他子句。

打开和关闭游标:游标用 open /close cursor 语句打开和关闭游标。open 已定义游标名字 ,close 已定义游标的名字。close释放游标使用的所有内部内存和资源,因此在每个游标不再需要时都应该关闭。在一个游标关闭后,如果没有重新打开,则不能使用它。但是,使用声明过的游标不需要再次声明,用open打开它就可以了。隐含关闭,如果不明确关闭游标。MySQL将会在到达end语句时自动关闭它。

使用游标数据:在一个游标被打开后,可以使用 fetch 语句分别访问它的每一行。fetch指定检索什么数据(所需的列),检索出来的数据存储在什么地方。它还向前移动游标中的内部行指针,使下一条fetch语句检索下一行(不重复读取同一行)。

declare 语句的发布存在特定的次序。用 declare 语句定义的局部变量必须在定义任意游标或句柄之前定义,而句柄必须在游标之后定义。不遵守此顺序将产生错误信息。

除了使用 repeat 语句外,MySQL还支持循环语句,它可以用来重复执行代码,直到使用 leave 语句手动退出为止。通常 repeat 语句的语法使它更适合于对游标进行循环。

MySQL必知必会——使用存储过程

MySQL 5添加了对存储过程的支持。存储过程简单来说,就是为以后的使用而保存的一条或多条MySQL语句的集合。可将其视为批文件,虽然它们的作用不仅限于批处理。

使用存储过程的一些理由如下:

1)通过把处理,封装在容易使用的单元中,简化复杂的操作。

2)由于不要求反复建立一系列处理步骤,这保证了数据的完整性。如果所有开发人员和应用程序都使用同一(试验和测试)存储过程,则所使用的代码都是相同的。这一点的延伸就是防止错误。需要执行的步骤越多,出错的可能性就越大。防止错误保证了数据的一致性。

3)简化对变动的管理。如果表名、列名或业务逻辑(或别的内容)有变化,只需要更改存储过程的代码。使用它的人员甚至不需要知道这些变化。这一点的延伸就是安全性。通过存储过程限制对基础数据的访问减少了数据讹误(无意识的或别的原因所导致的数据讹误)的机会。

4)提高性能。因为使用存储过程比使用单独的SQL语句要快。

5)存在一些只能用在单个请求中的MySQL元素和特性,存储过程可以使用它们来编写功能更强更灵活的代码。

总结:使用存储过程有3个主要好处,即简单、安全、高性能。

而存储过程的一些缺陷如下:

1)一般来说,存储过程的编写比基本SQL语句复杂,编写存储过程需要更高的技能,更丰富的经验。

2)用户可能没有创建存储过程的安全访问权限。许多数据库管理员限制存储过程的创建权限,允许用户使用存储过程,但不允许他们创建存储过程。

MySQL将编写存储过程的安全和访问与执行存储过程的安全和访问区分开来。即使你不能(或不想)编写自己的存储过程,也仍然可以在适当的时候执行别的存储过程。

MySQL称存储过程的执行为调用,因此MySQL执行存储过程的语句为call。call接受存储过程的名字和需要传递给它的任意参数。

用 create procedure 创建存储过程的名字() 语句创建一个存储过程。如果存储过程接受参数,它们将在()中列举出来。如果没有参数,后面的()仍然需要。begin和end语句用来限定存储过程体。

MySQL对于存储过程体出现 ; 号时而需要修改MySQL默认的分隔符说明如下:

one

因为存储过程实际上是一种函数,所以存储过程名后需要有()符号(即使不传递参数也需要)。删除存储过程语句为:drop procedure 存储过程名字 需要注意的是没有使用后面的(),只给出存储过程名。

一般存储过程并不显示结果,而是把结果返回给指定的变量。变量内存中一个特定的位置,用来临时存储数据。

MySQL支持in(传递给存储过程),out(从存储过程传出)和inout(对存储过程传入和传出)类型的参数。存储过程的代码位于begin和end语句内。

存储过程的参数允许的数据类型与在表中使用的数据类型相同。但要注意,记录集不是允许的类型,因此,不能通过一个参数返回多个行和列。

所有MySQL变量都必须以@开始。

MySQL注释:前面放置 – 。

在存储过程中 declare 要求指定变量名和数据类型 ,它也支持可选的默认值。

为显示用来创建一个存储过程的 create 语句,使用 show create procedure 语句。为了获得包括何时、由谁创建等详细信息的存储过程列表,可使用show procedure status 。show procedure status列出所有存储过程。为限制其输出,可使用like指定一个过滤模式。

MySQL必知必会——视图

视图是虚拟的表。与包含数据的表不一样,视图只包含使用动态检索数据的查询。MySQL 5添加了对视图的支持。作为视图它不包含表中应该有的任何列或数据,它包含的是个SQL查询。

视图的一些常见应用如下:

1)重用SQL语句。

2)简化复杂的SQL操作。在编写查询后,可以方便地重用它而不必知道它的基本查询细节。

3)使用表的组成部分而不是整个表。

3)保护数据。可以给用户授予表的特定部分的访问权限而不是整个表的访问权限。

4)更改数据格式和表示。视图可返回与底层的表示和格式不同的数据。

重要的是视图仅仅是用来查看存储在别处的数据的一种设施。视图本身不包含数据,因此它们返回的数据是从其他表中检索出来。在添加或更改这些表中的数据时,视图将返回改变过的数据。

性能问题:因为视图不包含数据,所以每次使用视图时,都必须处理查询执行执行时所需的任一个检索。如果用多个联结和过滤创建了复杂的视图或者嵌套了视图,可能发现性能下降得很厉害。因此,在部署使用了大量视图的应用前,应该进行测试。

视图创建和使用的一些常见的规则和限制如下:

1)与表一样,视图必须唯一命名(不能给视图取与别的视图或表相同的名字)

2)对于可以创建的视图数目没有限制。

3)为了创建视图,必须具有足够的访问权限。这些限制通常由数据库管理人员授予。

4)视图可以嵌套,即可以利用从其他视图中检索数据的查询来构造一个视图。

5)order by可以用在视图中,但如果从该视图中检索数据select中也含有order by,那么该视图的order by将被覆盖。

6)视图不能索引,也不能有关联的触发器或默认值。

7)视图可以和表一起使用。例如,编写一条联结表和视图的select语句。

如何使用视图如下所示:

1)视图用create view语句来创建。

2)使用show create view viewname;来查看创建视图的语句。

3)用drop删除视图,语法为drop view viewname。

4)更新视图时,可以先用drop再用create,也可以直接用create or replace view。如果要更新的视图不存在,则第2条更新语句会创建一个视图;如果要更新的视图存在,则第2条更新语句会替换原有试图。

视图的另一常见用途是重新格式化检索出的数据。

CUE:如果从试图检索数据时使用了一条where子句,则两组子句(一组在视图中,另一组是传递给视图的)将自动组合。

通常,视图是可更新的(即,可以对它们使用insert,update和delete)。更新一个视图将更新其基表(可以回忆下,视图本身没有数据)。如果对视图增加或删除行,实际上是对其基表增加和删除行。但是,并非所有视图都是可更新的,如果MySQL不能正确地确定被更新的基数据,则不允许更新(包括插入和删除)。这实际上意味着,如果视图定义中有以下操纵,则不能进行视图的更新:

1)分组(使用group by和having)。

2)联结。

3)子查询。

4)并。

5)聚集函数(MIN(),SUM()等等)。

6)distinct。

7)导出(计算)列

一般应该将视图用于检索(select语句)而不是更新(insert等)。

视图为虚拟的表。它们包含的不是数据而是根据需要检索数据的的查询。视图提供了一种MySQL的select语句层次的封装,可用来简化数据处理以及重新格式化基础数据或保护基础数据。

MySQL必知必会——创建和操作表

一般有以下两种创建表的方法:

1)使用具有交互式创建和管理表的工具。

2)表也可以直接用MySQL语句操纵。

利用create table创建表,必须给出以下信息:

1)新表的名字,在关键字create table之后给出。

2)表列的名字和定义,用逗号分隔。

表名紧跟在create table关键字后面。实际的表定义(所有列)括在圆括号之中。各列之间用逗号分隔。每列的定义以列名(它在表中是唯一的)开始,后跟列的数据类型。表的主键可以在创建表时用primary key关键字指定。整条语句由右圆括号后的分号结束。

在创建新表时,指定的表名必须不存在,否则将出错。如果要防止意外覆盖已有的表,SQL要求首先手工删除该表。然后再重建它,而不是简单的用创建表语句覆盖它。如果仅想在一个表不存在时创建它,应该在表名后给出 if not exists。这样做不检查已有表的模式是否与打算创建的表模式相匹配。它只是查看表名是否存在,并且仅在表名不存在时创建它。

null值就是没有值或缺值。允许null值的列也允许在插入行时不给出该列的值。不允许null值的列不接受该列没有值的行。换句话说,在插入或更新时,该列必须有值。null为默认设置,如果不指定not null,则认为指定的是null。

不要把null值与空串相混淆。null值是没有值,它不是空串。如果指定“”(两个单引号,其间没有字符),这在not null列是允许的。空串是一个有效的值,它不是无值。null值用关键字null而不是空串指定。

主键必须唯一。即表中的每个行必须具有唯一的主键值。如果主键使用单个列,则它的值必须唯一。如果使用多个列,则这些列的组合值必须唯一。为创建由多个列组成的主键,应该以逗号分隔的列表给出各列名,主键可以在创建表时定义或者创建之后定义。主键为其值唯一标识表中每个行的列。主键只能使用不允许null值的列。允许null值的列不能作为唯一标识。

auto_increment通知MySQL本列每当增加一行时自动增量。每次执行一个insert操纵时,MySQL自动对该列增量(从而才有这个关键字auto_increment),给该列赋予下一个可用的值。每个表只允许一个auto_increment列,而且它必须被索引(如,通过使它成为主键)。

覆盖auto_increment:当一个列被指定为auto_increment时,如果要覆盖自动增量,可以简单地在insert语句中指定一个值,只要它是唯一的(至今尚未使用过)即可,该值将被用来替代自动生成的值。后续的增量将开始使用该手工插入的值。

确定auto_increment的值:让MySQL生成(通过自动增量)主键的一个缺点就是无法知道这些值都是谁。那么可以使用last_insert_id()函数来获得这个值。select last_insert_id() 该语句返回最后一个auto_incremen值,然后可以将它用于后面的的MySQL语句中。

如果在插入行时没有给出值,MySQL允许指定此时使用默认值。默认值用create table语句的列定义中default关键字指定。与大多数DBMS不一样,MySQL不允许使用函数作为默认值,它只支持常量。许多数据库开发人员使用默认值而不是null列,特别是对于计算或数据分组的列更是如此。

与其他DBMS一样,MySQL有一个具体管理和处理数据的内部引擎。在使用create table语句时,该引擎具体创建表;在使用select语句进行其他数据处理时,该引擎在内部处理请求。多数时候,此引擎都隐藏在DBMS内,不需要太过多的关注它。但MySQL于其他DBMS又有些不一样,它是具有多种引擎的。它打包多个引擎,这些引擎都隐藏在MySQL服务器内,全都能执行create table和select等命令。

当然,完全可以忽略这些数据库引擎。如果省略engine=语句,则使用默认引擎(很可能是MyISAM),多数MySQL语句都会默认使用它。除此之外,还有以下几个常见的引擎:

1)InnoDB是一个可靠的事务处理引擎,它不支持全文本搜索。

2)MEMORY在功能等同于MyISAM,但由于数据存储在内存(不是在磁盘)中,速度很快(特别适合于临时表)。

3)MyISAM是一个性能极高的引擎,它支持全文本搜索,但不支持事务处理。

引擎类型可以混用。但混用引擎有一个大缺陷。就是外键(用于强制实施引用完整性)不能跨引擎,即用一个引擎的表不能引用具有使用不同引擎的表的外键。

为了更新表定义,可使用alter table语句。为了使用alter table更该表结构,必须给出以下信息:

1)在alter table之后给出要更改的表名(该表必须存在,否则将出错)。

2)所做更改的列表。

alter table一种常见用途是定义外键。为了对单个表进行多个更改,可以使用单条alter table语句,每个更改用逗号分隔。复杂的表结构更改一般需要手动删除过程,它涉及以下步骤:

1)用新的列布局创建一个新表。

2)使用insert select语句从旧表复制数据到新表。如果有必要,可以使用转换函数和计算字段。

3)检验包含所需要数据的新表。

4)重命名旧表(如果确定,可以删除它)。

5)用旧表原来的名字重新命名新表。

6)根据需要,重新创建触发器、存储过程、索引和外键。

使用alter table要极为小心,应该在进行改动前做一个完整的备份(模式和数据的备份)。数据库表的更改不能撤销,如果增加了不需要的列,可能不能删除它们。类似地,如果删除了不应该删除的列,可能会丢失该列中的所有数据。

删除表(整个表而不是其内容)非常简单,使用drop table语句即可。

使用rename table语句可以重命名一个表。rename可以对多个表重命名,用逗号分隔。

MySQL必知必会——更新和删除数据

为了更新(修改)表中的数据,可以使用update语句。可采用以下两种方式使用update:

1)更新表中特定行。

2)更新表中所有行。

不要省略where子句,在使用update时一定要注意这点。因为稍不注意,就会更新表中的所有行。与insert语句一样,同样是可以限制和控制update语句的使用。

基本的update语句由以下3部分组成,分别是:

1)要更新的表。

2)列名和它们的新值。

3)确定要更新行的过滤条件。

update语句总是以更新的表的名字开始。set命令用来将新值赋给更新的列。update语句以where子句结束,它告诉MySQL更新哪一行。而在更新多个列时,只需要使用单个set命令,每个“列=值”之间用逗号分隔(最后一列之后不用逗号)。

在update语句中使用子查询:update语句可以使用子查询,使得能用select语句检索出的数据更新列数据。

ignore关键字:如果update语句更新多行,并且在更新这些行中的一行或多行时出现一个错误,则整个update操作被取消(错误发生前更新的所有行被恢复到它们原来的值)。为即使是发生错误,也继续进行更新,可以使用ignore关键字。如后所示:update ignore 表名……。

为了从一个表中删除(去掉)数据,使用delete语句。可以采用以下两种方式使用delete:

1)从表中删除特定的行。

2)从表中删除所有行。

与使用update语句千万不用省略where子句一样,在使用delete时同样要注意这点。因为稍不注意,就会错误地删除表中所有行。同样,也是可以限制和控制delete语句的使用。

delete from要求指定从中删除数据的表名,where子句过滤要删除的行。delete不需要列名或通配符。delete删除整行而不是删除列。为了删除指定的列,需使用update语句。

删除表的内容而不是表:delete语句从表中删除行,甚至是删除表中的所有行。但是delete不删除表本身。

更快的删除:如果想从表中删除所有行,不用使用delete。可使用truncate table语句,它完成相同的工作,但速度更快(truncate实际是删除原来的表并重新创建一个表,而不是逐行删除表中的数据)。

使用update或delete时所遵循的习惯:

1)除非确实打算更新和删除每一行,否则绝对不要使用不带where子句的update或delete语句。

2)保证每个表都有主键,尽可能像where子句那样使用它。

3)在对update或delete语句使用where子句前,应该先用select进行测试,保证它过滤的是正确的记录,以访编写的where子句不正确。

4)使用强制实施引用完整性的数据库,这样MySQL将不允许删除具有与其他表相关联的数据的行。

注意:MySQL没有撤消(undo)按钮,应该非常小心地使用update和delete。

MySQL必知必会——插入数据

insert语句是用来插入(或添加)行到数据库表的。插入可以用以下几种方式使用:

1)插入完整的行。

2)插入行的一部分。

3)插入多行。

4)插入某些查询的结果。

插入以及系统安全:可针对每个表或每个用户,利用MySQL的安全机制禁止使用insert语句。

把数据插入表中的最简单的方法是使用基本的insert语法,它要求指定表名和被插入到新行中的值。insert语句一般是不会产生输出的。存储到每个表列中的数据在values子句中给出,对每个列必须提供一个值。如果某个列没有值,应该使用null值(假定表允许对该列指定控制)。各个列必须以它们在表定义中出现的次序填充。

一般不要使用没有明确给出列的列表的insert语句。使用列的列表能使SQL代码继续发挥作用,即使表结构发生了变化。

不管使用哪种insert语法,都必须给出values的正确数目。如果不提供列名,则必须给每个列提供一个值。如果提供列名,则必须对每个列出的列给出一个值。如果不这样,将产生一条错误消息,相应的行插入不成功。当然,如果表的定义允许,则可以在insert操作中省略某些列。省略的列必须满足以下某个条件:

1)该列定义为允许NULL值(无值或空值)。

2)在表定义中给出默认值。这表示如果不给出值,将使用默认值。

如果对表中不允许NULL且没有默认值的列不给出值,则MySQL将产生一条错误消息,相应的行插入不成功。

提高整体性能:数据库经常被多个客户访问,对处理什么请求以及用什么次序处理进行管理是MySQL的任务。insert操作可能很耗时(特别是有很多索引需要更新时),而且它可能降低等待处理的select语句的性能。如果数据检索是最重要的(通常是这样的),则可以通过在insert和into之间添加关键字low_priority,指示MySQL降低insert语句的优先级。另外,这种方法同样适用于update和delete语句。

可以使用多条insert语句,甚至一次提交它们,每条语句用一个分号结束。

insert一般用来给表插入一个指定列值的行。但是,insert还存在另一种形式,可以利用它将一条select语句的结果插入表中。这就是所谓的insert select,顾名思义,它是由一条insert语句和一条select语句组成的。

insert select中的列名:事实上,MySQL不关心select返回的列名。它使用的是列的位置,因此select中的第一列(不管其列名)将用来填充表列中指定的第一个列,第二列将用来填充表列中指定的第二个列,如此等等。这对于从使用不同列名的表中导入数据是非常有用的。insert select中的select语句可包含where子句以过滤插入的数据。