二十三:使用存储过程:

1:mysql 5添加了对存储过程的支持。很多时候,一个完整的操作需要多条语句才能完成。存储过程简单来说,就是为以后的使用而保存的一条或多条mysql语句的集合,可将其视为批文件、函数。

2:使用存储过程有3个主要的好处:简单、安全和高性能。

3:一个返回产品平均价格的存储过程,代码如下:

delimiter //

create procedure productpricing()

begin

select avg(prod_price) as priceaverage

from products;

end//

这样就创建了名为productpricing的存储过程,begin和end用来定义存储过程体,过程体本身是一个简单的select语句。

因为默认的mysql语句分隔符为“;”,但是定义存储过程时,需要在内部使用”;”,所以需要使用“delimiter //”,临时将语句分隔符改为”//”,如果需要恢复默认的语句分隔符”;”,再次使用delimiter即可:”delimiter ;”。注意,除了”\”符号之外,任何字符都可以用作语句分隔符。

调用这个存储过程的语句为:call productpricing();结果如下:

4:存储过程在创建之后,被保存在服务器上以供使用,直到被删除。删除存储过程的命令如下:drop procedure productpricing;

如果指定的存储过程名不存在,则drop procedure将产生一个错误,可以使用下面的语句:drop procedure if exists productpricing;

5:一般来说,存储过程并不显示结果,而是把结果返回给你指定的参数。下面是productpricing的修改版本:

create procedure productpricing(

out pl decimal(8,2),

out ph decimal(8,2),

out pa decimal(8,2))

begin

select min(prod_price) into pl from products;

select max(prod_price) into ph from products;

select avg(prod_price) into pa from products;

end//

这个存储过程接受3个参数,pl存储产品最低价格,ph存储产品最高价格,pa存储平均价格。每个参数必须指定类型。参数类型与表中使用的数据类型相同。

关键字out表明相应的参数用来从存储过程中传出一个值。mysql支持in(传递给存储过程)和out(从存储过程中传出)和inout(传入和传出)。

调用该存储过程的语句是:call productpricing(@pricelow, @pricehigh, @priceaverage)//

注意,所有的变量都必须以@开始。在调用时,并不显示任何数据,要想显示结果,则:

select @pricelow,@pricehigh, @priceaverage,结果如下:

6:使用in和out参数的例子如下:

create procedure ordertotal(

in onumber INT,

out ototal decimal(8,2))

begin

select sum(item_price*quantity)

from orderitems

where order_num = onumber

into ototal;

end//

call ordertotal(20005,@total)//

select @total//  结果如下:

7:为了显示创建一个存储过程的create语句,可以使用show create procedure name,比如:

show create procedure ordertotal//  结果如下:

二十四:使用游标

1:mysql 5添加了对游标的支持。使用简单的select语句,没有办法得到第一行、下一行或前10行,也不存在每次一行的处理所有行的简单方法。

2:有时,需要在检索出来的行中前进或后退一行或多行。这时就需要使用游标。游标是一个存储在mysql服务器上的数据库查询,它不是一条select语句,而是被该语句检索出来的结果集。在存储了游标之后,应用程序可以根据需要滚动或浏览其中的数据。

3:mysql游标只能用于存储过程。

4:在能够使用游标之前,必须声明定义它。这个过程实际上没有检索数据,它只是定义要使用的select语句。一旦声明之后,必须打开游标以供使用。这个过程,会用前面定义的select语句把数据实际检索出来。

对于填有数据的游标,根据需要取出各行。在结束游标使用时,必须关闭游标。

5:游标用declare语句创建。declare命名游标,并定义相应的select语句,比如:

create procedure processorders()

begin

declare ordernumbers cursor

for

select order_num from orders;

end//

这个存储过程并没有做很多事,declare语句用来定义和命名游标,这里游标名为ordernumbers。存储过程处理完成后,游标就消失,因为它局限于存储过程。这里,即使调用该存储过程,也没有任何效果,因为该存储过程只是简单的定义了游标。

6:下面以一个全面的例子来说明:

CREATE PROCEDURE processorders()

BEGIN

-- declarelocal variable

DECLARE done BOOLEAN  DEFAULT  0;

DECLARE o INT;

DECLARE t DECIMAL(8,2);

-- declare the cursor

DECLARE  ordernumbers  CURSOR

FOR

SELECT order_num  FROM orders ;

-- declare continue handler

DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;

-- createa table to store the results

CREATE TABLE IF NOT EXISTS ordertotals(order_num  INT , total DECIMAL(8,2));

--open the cursor

Open ordernumbers;

-- loopthrough all rows

REPEAT

-- get the ordernumber

FETCH ordernumbers INTO o;

-- get the total for this order

CALL ordertotal(o , 1 , t);

-- insert order and totalinto ordertotals

INSERT INTO ordertotals(order_num, total) VALUES(o , t);

-- endof loop

UNTIL done ENDREPEAT;

--close the cursor

Close ordernumbers;

END//

“--“ 表示注释,

open ordernumbers;表示打开游标,在处理open语句时,会执行查询,存储检索出的数据以供浏览和滚动。游标处理完成后,应当使用”close ordernumbers”关闭游标。close会释放游标所使用的内部资源,因此,每个游标不在需要时都应该关闭。

在一个游标关闭后,如果没有重新打开它,则不能使用它,如果不明确关闭游标,mysql将会在到达end语句时自动关闭它。

游标在打开后,可以使用fetch语句,分别访问它的每一行,fetch还将移动游标中的内部行指针,使下一条fetch语句检索下一行。所以,FETCH ordernumbers INTO o;表示将检索当前行的order_num,到一个名为o的局部声明的变量中。

fetch在repeat中,它会反复执行,直到done为真。done为真的条件是:

DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1; 这条语句定义了一个continue handler,它是在条件出现时被执行的代码。这里它指出,当sqlstate ‘02000’出现时,set done = 1. sqlstate ‘02000’是一个未找到条件,当repeat由于没有更多的行供循环而不能继续时,这个条件就会出现。

注意:用declare定义的局部变量必须在定义任意游标或句柄之前,而句柄必须在游标之后定义。如果不遵守,将会出错(已验证)。

在该例中,还创建了一个新表ordertotals,这个表将保存存储过程生成的结果。

用call执行这个存储过程,然后select * from ordertotals; 将得到如下结果:

二十五: 使用触发器

1:MySQL5版本后支持触发器。只有表支持触发器,视图不支持触发器。

2:如果你想要某条语句(或某些语句)在事件发生时自动执行,例如:每增加一个顾客到某个数据库表时,都检查其电话号码格式是否正确,区的缩写是否为大写等。

这就需要在某个表发生更改时自动处理。这就是触发器。触发器是MySQL响应以下任意语句而自动执行的一条MySQL语句(或位于BEGIN和END语句之间的一组语句):DELETE;INSERT;UPDATE。

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

3:创建触发器, 创建触发器需要给出4条信息:

唯一的触发器名;

触发器关联的表;

触发器应该响应的活动(DELETE、INSERT或UPDATE)

触发器何时执行(处理前还是后,前是BEFORE 后是AFTER)

在mysql5中,触发器名必须是每个表中唯一,但不是在每个数据库中唯一。这表示,在同一个数据库中的两个表,可具有相同名字的触发器。

创建触发器用CREATE TRIGGER:

CREATE  TRIGGER  newproduct  AFTER  INSERT ON products

FOR  EACH  ROW SELECT 'Product added'

(注意,这条语句在mysql5.0以上的版本中会出错,ttp://forums.forta.com/messages.cfm?threadid=430BA0BA-D826-7C62-F5ABFC6AAF6B4585

在这里作者作了相关解释, that is allowed in other DBMSs, andwas allowed in MySQL 5, but then not allowed by MySQL in later versions. Sorry.这个是版本问题。在MySQL5之前是支持的,在之后的版本就不支持这种用法了。)

创建新触发器newproduct ,它将在INSERT语句成功执行后执行。这个触发器还指定FOR EACH ROW,因此代码对每个插入的行执行。这个例子作用是,对每个插入的行显示一次文本”product added”。

触发器按每个表每个事件每次地定义,每个表每个事件每次只允许定义一个触发器,因此,每个表最多定义6个触发器(每条INSERT UPDATE 和DELETE的之前和之后)。单个触发器不能与多个事件或多个表关联,所以,如果你需要一个对INSERT 和UPDATE存储执行的触发器,则应该定义两个触发器。

如果BEFORE(之前)触发器失败,则MySQL将不执行SQL语句的请求操作,此外,如果BEFORE触发器或语句本身失败,MySQL将不执行AFTER(之后)触发器

4:删除触发器:

DROP TRIGGER newproduct;

触发器不能更新或覆盖,所以修改触发器只能先删除再创建

5:INSERT 触发器,INSERT触发器在INSERT语句执行之前或之后执行。需要知道以下几点:

a:在INSERT触发器代码内,可引用一个名为NEW的虚拟表,访问被插入的行;

b:在BEFORE INSERT触发器中,NEW中的值也可以被更新(允许更改插入的值);

c:对于AUTO_INCREMENT列,NEW在INSERT执行之前包含0,在INSERT执行之后包含新的自动生成值。

提示:通常BEFORE用于数据验证和净化(目的是保证插入表中的数据确实是需要的数据)。本提示也适用于UPDATE触发器。

比如:

create trigger neworder after insert on orders

for each row select new.order_num;

此代码创建一个名为neworder的触发器,在插入一个新订单到orders表时,mysql生成一个新订单号并保存到order_num中。触发器从new.orer_num取得这个值,并返回他。

DELETE 触发器,DELETE触发器在语句执行之前还是之后执行,需要知道以下几点:

a:在DELETE触发器代码内,你可以引用一个名为OLD的虚拟表,访问被删除的行;

b:OLD中的值全部是只读的,不能更新

例子演示适用OLD保存将要除的行到一个存档表中:

CREATE TRIGGER delete order  BEFORE  DELETE ON orders

FOR EACH ROW

BEGIN

INSERT INTO  archive_orders(order_num ,order_date , cust_id)

VALUES(OLD.order_num, OLD.order_date , OLD.cust_id);

END;

在任何订单删除之前执行这个触发器,它使用一条INSERT语句将OLD中的值(将要删除的值)保存到一个名为archive_orders的存档表中。

BEFORE DELETE触发器的优点是(相对于AFTER DELETE触发器),如果由于某种原因,订单不能被存档,DELETE本身将被放弃执行。

UPDATE触发器

UPDATE触发器在语句执行之前还是之后执行,需要知道以下几点:

a:在UPDATE触发器代码中,你可以引用一个名为OLD的虚拟表访问(UPDATE语句前)的值,引用一名为NEW的虚拟表访问新更新的值;

b:在BEFORE UPDATE触发器中,NEW中的值可能被更新,(允许更改将要用于UPDATE语句中的值)

c:OLD中的值全都是只读的,不能更新

例子:保证州名的缩写总是大写(不管UPDATE语句给出的是大写还是小写)

CREATE TRIGGER  update vendor  BEFORE UPDATE ON  vendores

FOR EACH ROW  SET NEW.vend_state  = Upper(NEW.vend_state)

6:触发器的进一步介绍

a:与其他DBMS相比,MySQL5中支持的触发器相当初级。以后可能会增强;

b: 创建触发器可能需要特殊的安全访问权限,但是触发器的执行时自动的.如果INSERT UPDATE DELETE能执行,触发器就能执行;

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

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

e:遗憾的是,MySQL触发器中不支持CALL语句,这表示不能从触发器中调用存储过程。所需要的存储过程代码需要复制到触发器内

二十六:管理事务处理

1:mysql中,并非所有的引擎都支持事务管理,比如常见的引擎myisam和innodb,前者就不支持事务,而后者支持。

2:事务处理可以用来维护数据库的完整性,它保证成批的mysql操作要么完全执行,要么完全不执行。比如给系统添加订单的过程如下;

a:检查数据库中是否存在相应的客户,从表customers中查询,如果不存在,则添加;

b:检索客户ID;

c:添加一行到orders表,把它与客户ID关联;

d:检索orders表中赋予的新订单ID;

e:对于订购的每个物品在orderitems表中添加一行,通过检索出来的ID,把它与orders表关联

这个例子中,如果在orders行添加之后,orderitems行添加之前出现了问题,那么数据库中就会有一个空订单。更糟的是,如果在添加orderitems行之中出现故障。结果是数据库中存在不完整的订单,而且你还不知道。

这就需要事务处理了。事务处理是一种机制,用来管理必须成批执行的mysql操作,以保证数据库不包含不完整的操作结果。利用事务处理,可以保证一组操作不会中途停止,它们或者作为整体执行,或者完全不执行。如果没有错误发生,整组语句提交给数据库表。如果发生错误,则进行回退,已恢复数据库到某个一直且安全的状态。

3:事务处理的关键词有:

事务(transaction):指一组sql语句;

回退(rollback):撤销指定sql语句的过程;

提交(commit):将未存储的sql语句结果写入数据库表中;

保留点(savepoint);事务处理中设置的临时占位符,可以对他进行回退,而不是回退整个事务。

4:mysql使用下面的语句来标示事务的开始:start transaction; 用rollback命令进行回退,比如下面的例子:

select* from ordertotals;

start transaction;

delete from ordertotals;

select * from ordertotals;

rollback;

select * from ordertotals;

这个例子中,首先显示ordertotals表的所有内容,然后开始一个事务处理,用一条delete语句删除ordertotals中的所有行,然后一条select语句验证ordertotals确实为空。此时,用一条rollback语句回退start transaction之后的所有语句,最后一条select语句显示该表不为空。

5:事务处理用来管理insert、update和delete语句,不能回退select(无意义),create和drop操作。事务处理块中可以使用这条语句,但如果执行回退,它们不会被撤销(已验证)。

6:一般的mysql语句都是直接对数据库表执行和编写的,这就是所谓的隐含提交,也就是提交操作是自动进行的。

但是,在事务处理中,提交不会隐含的进行。为进行明确的提交,使用commit语句,比如:

start  transaction;

delete from orderitems where order_num = 20010;

delete from orders where order_num = 20010;

commit;

这个例子中,从系统中完全删除订单20010.因为涉及更新两个数据库表orders和orderitems,所以使用事务处理块来保证订单不会部分删除。最后的commit语句只在不出错是写出更改。如果第一条delete起作用,但第二条失败,则delete不会提交。

当commit或rollback语句执行后,事务会自动关闭。

7:对于复杂的事务处理,可能需要部分提交或回退。为了支持回退部分事务处理,必须能在事务处理块中合适的位置放置占位符。这样,如果需要回退,可以会退到某个占位符。

占位符也叫保留点,使用savepoint语句: savepoint delete1;回退到保留点:rollback to delete1;

保留点在事务处理完成(执行commit或rollback)之后自动释放。

8:默认的mysql行为是自动提交所有更改。如果关闭自动提交,可以使用下面的语句:

set autocommit = 0;  注意,autocommit标志是针对每个连接而不是服务器的。

二十七:全球化和本地化

1:数据库表被用来存储和检索数据。不同语言和字符集需要以不同的方式存储和检索。因此,MySQL需要适应不同的字符集,适用不同的排序和检索数据的方法。

2:术语:

字符集:  为字母和符号的集合

编码: 为某个字符集成员的内部表示

校对: 为规定字符如何比较的指令

校对为什么重要?排序英文正文很容易吗?或许不,考虑词APE、apex和Apple。怎么排序。还有区分和不区分大小写怎么排序,其他字符集则会有更为复杂的情况。

在MySQL的正常数据库活动(SELECT  INSERT等)中,不需要操心太多的东西。使用何种字符集和校对的决定在服务器、数据库和表级进行。

3:使用字符集和校对顺序

MySQL支持众多字符集。为了查看所支持的字符集的描述和默认校对,可以使用下来语句:        SHOW CHARACTER SET; 部分结果如下:

为了查看所支持校对以及适用的字符集的完整列表,使用下列语句:        SHOW COLLATION;  部分结果如下:

此语句显示所有可用的校对,以及它们适用的字符集。可以看到有的字符集具有不止一种校对。

通常系统管理在安装时定义一个默认的字符集和校对。此外也可以在创建数据库时,指定默认的字符集和校对。使用以下语句查看:

SHOW VARIABLES LIKE 'character%'

SHOW VARIABLES LIKE 'collation%'

实际上,字符集很少是服务器范围(甚至是数据库范围)的设置。不同的表,甚至不同的列都可能需要不同的字符集。而且两者都可以在创建时指定。

为了给表指定字符集和校对,可以使用带子句的CREATE TABLE:

CREATE TABLE mytable

(

Columnn1 INT,

Columnn2 VARCHAR(10)

) DEFAULT CHARACTER SET hebrew

COLLATE hebrew_general_ci

创建了一个包括两列的表,并且指定了一个字符集和一个校对顺序。这个例子中指定了CHARACTER SET 和COLLATE两者,一般MySQL如下确定使用什么样的字符集和校对:

a:如果指定CHARACTER SET 和COLLATE两者,这使用这些值

b:如果只指定CHARACTER SET 则使用此字符集及其默认的校对顺序

c:如果都没有指定则使用数据库默认

除了指定字符集和校对表外,MySQL还允许对每个列设置他们的字符集和校对,如下:

CREATE TABLE mytable

(

Column1 INT,

Column2 VARCHAR(10),

Column3 VARCHAR(10)  CHARACTER SET latin1 COLLATE latin1_general_ci

)DEFAULT CHARACTER SET hebrew

COLLATE hebrew_general_ci;

这里对整个表以及特定的列指定了CHARACTER SET 和 COLLATE。

4:校对在对用ORDER BY 子句检索出来的数据排序时起重要的作用。如果你需要用与创建表时不同的校对,排序特定的SELECT语句,也可以在SELECT 语句自身中进行:

SELECT * FROM customers

ORDER BY lastname , firstname COLLATE latin1_general_cs;

此SELECT使用CALLATE指定了一个备用的校对顺序。SELECT的其他子句,除了这里的ORDER BY 子句中使用以外,COLLATE还可以用于GROUP BY、HAVING、聚集函数、别名等。

二十八:安全管理

1:MySQL服务器的安全基础是:用户应该对他们需要的数据具有适当的访问权,不能多也不能少。访问控制,就是你需要给用户提供他们所需的访问权,且仅提供他们所需的访问权。管理访问控制需要创建和管理用户账号。

2:在非现实的数据库中使用root登录进行学习调试是对的。不过在现实世界的日常工作中,决不能使用root。而应该创建一系列不同权限的账号,用这些账号来登录对数据库进行操作。

3:MySQL用户账号和信息存储在名为mysql的MySQL数据库中,在其中的user表记录了用户信息:

USE mysql;

SELECT user FROM user;

一般不需要直接访问mysql数据库和表。上面语句的结果如下:

4:为了创建一个新用户账号,使用CREATE USER语句:

CREATE USER  gq  IDENTIFIED BY '123123';

CREATE USER创建了一个新用户账号。在创建用户时不一定需要口令,不过这个例子用IDENTIFIED BY '123123'给出了一个口令。这是,在user表中就可看见新创建的用户信息:

IDENTIFIED BY指定的口令为纯文本,MySQL将在保存到user表之前对其进行加密。为了作为散列值(也就是加密后的值)指定口令,使用IDENTIFIED
BY PASSWORD;

GRANT语句也可以创建用户账号,但一般来说CREATE USER是最清楚和最简单的句子。此外,也可以通过直接插入行到user用户表来增加用户,不过安全起见,一般不建议这样做。

5:重命名一个用户账号,使用RENAME USER语句:

RENAME USER gq TO gq2;

MySQL5 之前不支持RENAME USER ,以前重命名一个用户使用UPDATE直接更新user表。

6:为了删除用户账号,使用DROP USER语句:

DROP USER gq;

7:在创建用户账号后,必须接着分配访问权限。新创建的用户没有访问权限,它们只能登陆服务器,但不能看到数据,也不能执行任何数据库操作。查看用户账号的权限,使用:

SHOW GRANTS FOR gq;  结果如下:

gq2的权限为usage on *.*,usage表示根本没有权限,所以他表示在任意数据库和任意表上对任何东西都没有权限。

用户定义为user@host,MySQL的权限用用户名和主机名结合定义,如果不指定主机名,则使用默认的主机名%(授予用户访问权限而不管主机名,任意主机皆可)。

8:设置权限,可使用GRANT语句,GRANT要求至少给出以下信息:

要授予的权限;

被授予访问呢权限的数据库或表;

用户名;

比如
GRANT  SELECT  ON test. *  TO  gq;

GRANT允许用户在test .*(test数据库的所有表)上使用SELECT。通过只授予SELECT访问权限,用户gq对test数据库中的所有数据具有只读访问权限。

9:撤销权限使用revoke语句:    REVOKE SELECT ON test . *  FROM  gq;

取消gq对test 表的SELECT访问权限,被撤销的权限必须存在,否则出错

10:GRANT和REVOKE可在几个层次上控制访问权限

整个服务器,使用GRANT ALL和REVOKE ALL

整个数据库,    使用ON database . *

特定表,使用ON database . table

特定列;

特定的存储过程

11:可通过列出各权限并用逗号分隔,将多条GRANT语句串在一起:

GRANT SELECT ,INSERT  ON test . *  TO gq;

12:更改口令,可使用SET PASSWORD语句,新口令必须传递给Password()函数加密:

SET PASSWORD  FOR gq = Password('n3wp@$$wOrd');   //设置gq的口令

set password还可以用来设置自己的口令:

SET PASSWORD = Password('n3wp@$$wOrd');     //设置自己的口令

二十九:数据库维护

1:像所有的数据一样,MySQL的数据也必须经常备份。由于MySQL数据库是基于磁盘的文件,普通的备份系统和例程就能备份MySQL的数据库,但是,由于这些文件总是处于打开和使用状态,普通的文件副本备份不一定总是有效。

下面列出这个问题的可能解决方案:

a:使用命令行程序mysqldump转储所有数据库内容到某个外部文件。

b:可用命令行程序mysqlhotcopy从一个数据库复杂所有数据(并非使用数据库引擎都转储这个实用程序)

c:可以使用MySQL的BACKUP TABLE或SELECT INTO OUTFILE转储所有数据到某个外部文件。这两条语句都能接受将要创建的系统文件名,此系统文件必须不存在,否则会出错。数据可以用RESTORE TABLE来复原

2:进行数据库维护

MySQL提供了一系列的语句,可以用来保证数据库正确和正常运行。以下是你应该知道的一些语句:

a:ANALYZE TABLE  用来检查表键知否正确。

b:CHECK TABLE用来针对许多问题对表进行检查。

3:诊断启动问题

服务器的启动问题通常在对MySQL配置或服务器本身进行更改时出现。MySQL在这个问题发生时报告错误,但由于多数MySQL服务器是作为系统进程或服务自动启动的,这些消息可能看不到。

在排除系统启动问题时,首先应该尽量用手动启动服务器。MySQL服务器自身通过在命令行上执行mysqld启动。下面是几个重要的mysqld命令行选项:

--help显示帮助

--safe-mode装载减去某些最佳配置的服务器

--verbose显示全文本消息

--version显示版本信息然后退出

三十:改善性能

1:MySQL是用一系列的默认设置预先配置的,从这些设置开始通常是很好的。但过一段时间后你可能需要调整内存分配、缓冲区大小等(为了查看当前配置,可使用SHOW VARIABLES;和 SHOW
STATUS;)。

2:MySQL是一个多用户多线程的DBMS,换言之,它经常同时执行多个任务。如果这些任务中的某个执行缓慢,则所有的请求都会执行缓慢。如果你遇到显著的性能不良,可使用SHOW PROCESSLIST显示所有活动进程(以及它们的线程ID和执行时间),你还可以用KILL命令(kill
 id号)终结某个特定的进程(使用这个命令需要作为管理员登陆)。

3:可以使用EXPLAIN语句让MySQL解释它将如何执行一条SELECT语句

4: 一般来说,存储过程执行的比一条一条执行的其中的各条MySQL语句快

5:决不要检索比需求还要多的数据,换言之,不要用SELECT * FROM (除非真的需要)

6:在导入数据时,应该关闭自动提交。你可以还想删除索引(包括FULLTEXT索引),然后再导入完成后再重建它们。

7:必须索引数据库表以改善数据检索的性能。索引改善数据检索的性能,但损害数据插入、删除和更新的新能。如果你有一些表,它们世界数据库且不经常被搜索,则在有必要之前不要索引它们。

8:LIKE很慢,一般来说,最好的使用FULLTEXT而不是LIKE

最新文章

  1. 使用VS2010创建WebService 发布、测试
  2. 在oracle中通过connect by prior来实现递归查询!
  3. foreach为什么要实现IEnumerable接口而不是直接用IEnumerator接口
  4. Android 通过Java代码生成创建界面。动态生成View,动态设置View属性。addRules详解
  5. Android 使WebView支持HTML5 Video(全屏)播放的方法
  6. ubuntu(Mint-17)修改dns
  7. [0x01 用Python讲解数据结构与算法] 关于数据结构和算法还有编程
  8. 在VS2012中采用C++中调用DLL中的函数 (4)
  9. Sqli-labs less 53
  10. centos编译helloworld的几个小问题
  11. 《编写高质量代码-Web前端开发修改之道》笔记--第二章 团队合作
  12. 分享一下个人的Vim配置文件
  13. delphi TFontDialog
  14. iOS 开发问题集锦(二)
  15. Word字体与像素的对应关系(转)
  16. 历年NOIP选题题解汇总
  17. WPF 圆角输入框
  18. Prefix tree
  19. 设计模式总结篇系列:原型模式(Prototype)
  20. Mysql-innoDB存储引擎(事物,锁,MVCC)

热门文章

  1. Vuejs实战项目步骤一
  2. LA4670 Dominating Patterns AC自动机模板
  3. Leetcode441Arranging Coins排列硬币
  4. Django项目:CRM(客户关系管理系统)--41--33PerfectCRM实现King_admin编辑整张表限制
  5. iBaties对比hibernate
  6. C# WPF 仿QQ靠近屏幕上方自动缩起功能实现
  7. java 5 绘图GUI
  8. oracle常用的时间格式转换
  9. Laravel 5.2 使用 JWT 完成多用户认证 | Laravel China 社区 - 高品质的 Laravel 开发者社区 - Powered by PHPHub
  10. Data Lake Analytics: 使用DataWorks来调度DLA任务