作者微信:15013593099 欢迎交流
mysqldump --triggers --events --routines --lock-all-tables -u root -p > /mnt/data.sql
1 sudo apt-get update
2. sudo apt-get install mysql-server Could not resolve 'security.ubuntu.com'
Err http://extras.ubuntu.com trusty Release.gpg
Could not resolve 'extras.ubuntu.com'
Err http://us.archive.ubuntu.com trusty InRelease
Err http://us.archive.ubuntu.com trusty Release.gpg
Could not resolve 'us.archive.ubuntu.com'
从Error Message 上看来似乎是“cn.archive.ubuntu.com”域名解析出错。于是在windows cmd中里Ping了一下这个域名,发现可以Ping 通。
C:\Documents and Settings\Administrator>ping us.archive.ubuntu.com
Pinging us.archive.ubuntu.com [91.189.91.14] with 32 bytes of data:
Reply from 91.189.91.14: bytes=32 time=224ms TTL=47
Reply from 91.189.91.14: bytes=32 time=224ms TTL=47
Reply from 91.189.91.14: bytes=32 time=224ms TTL=47
C:\Documents and Settings\Administrator>ping security.ubuntu.com
Pinging security.ubuntu.com [91.189.91.13] with 32 bytes of data:
Reply from 91.189.91.13: bytes=32 time=230ms TTL=47
Reply from 91.189.91.13: bytes=32 time=235ms TTL=47
Reply from 91.189.91.13: bytes=32 time=230ms TTL=47
Reply from 91.189.91.13: bytes=32 time=230ms TTL=47
C:\Documents and Settings\Administrator>ping extras.ubuntu.com
Pinging extras.ubuntu.com [91.189.92.152] with 32 bytes of data:
Reply from 91.189.92.152: bytes=32 time=284ms TTL=42
Reply from 91.189.92.152: bytes=32 time=283ms TTL=42
Reply from 91.189.92.152: bytes=32 time=284ms TTL=42
Reply from 91.189.92.152: bytes=32 time=284ms TTL=42
于是尝试通过修改 /etc/hosts 解决这个问题:
Setting up libhtml-template-perl (2.95-1) ...
Processing triggers for ureadahead (0.100.0-16) ...
Setting up mysql-server (5.5.43-0ubuntu0.14.04.1) ...
Processing triggers for libc-bin (2.19-0ubuntu6.5) ...
Preparing to unpack .../mysql-client_5.5.43-0ubuntu0.14.04.1_all.deb ...
Unpacking mysql-client (5.5.43-0ubuntu0.14.04.1) ...
Setting up mysql-client (5.5.43-0ubuntu0.14.04.1) ...
Processing triggers for man-db (2.6.7.1-1ubuntu1) ...
Setting up zlib1g-dev:i386 (1:1.2.8.dfsg-1ubuntu1) ...
Setting up libmysqlclient-dev (5.5.43-0ubuntu0.14.04.1) ...
至此安装完毕
1、使用 service 启动:service mysql start
2、使用 mysqld 脚本启动:/etc/inint.d/mysql start
3、使用 safe_mysqld 启动:safe_mysql&
sudo netstat -tap | grep mysql
a@ubuntu:~$ sudo netstat -tap | grep mysql
tcp 0 0 localhost:mysql *:* LISTEN 6911/mysqld
说明是成功的 port在LISTEN状态
show databases;
mysql> show databases
-> ;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+
3 rows in set (0.00 sec)
use mysql
mysql> use mysql
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
显示数据表单
show tables
mysql> show tables;
+---------------------------+
| Tables_in_mysql |
+---------------------------+
| columns_priv |
| db |
| event |
| func |
| general_log |
| help_category |
| help_keyword |
| help_relation |
| help_topic |
| host |
| ndb_binlog_index |
| plugin |
| proc |
| procs_priv |
| proxies_priv |
| servers |
| slow_log |
| tables_priv |
| time_zone |
| time_zone_leap_second |
| time_zone_name |
| time_zone_transition |
| time_zone_transition_type |
| user |
+---------------------------+
24 rows in set (0.00 sec)
#include
#include
#include "mysql.h"
int main()
{
MYSQL mysql;
char f1[100];
int f2;
char host[100];
char user[100];
char pwd[100];
char db[100];
int port;
char query[1000];
char yn;
printf("Please enter the host:\n");
scanf("%s",host);
printf("Please enter the username:\n");
scanf("%s",user);
printf("Please enter the password:\n");
scanf("%s",pwd);
printf("Please select a database:\n");
scanf("%s",db);
printf("Please enter the tcp port:\n");
scanf("%d",&port);
mysql_init(&mysql);
if(mysql_real_connect(&mysql, host, user, pwd, db, port, NULL, 0))
{
printf("Please enter the f1:\n");
scanf("%s",f1);
printf("Please enter the f2:\n");
scanf("%d",&f2);
getchar();
sprintf(query, "INSERT INTO test (id, test1, test2) VALUES (null, '%s', '%d')", f1,f2);
if(!mysql_real_query(&mysql,query,strlen(query)))
{
printf("Insert successed!!!\n");
printf("Whether to print the last SQL:(y/n)");
scanf("%c",&yn);
if(yn=='y')
{
printf("%s\n",query);
mysql_close(&mysql);
}
else
{
mysql_close(&mysql);
return;
}
}
else
{
printf("Insert failed!!!\n");
}
}
else
{
printf("Connect to MySQL failed!!!\n");
}
}
#include
#include
#include "mysql.h"
int main()
{
MYSQL mysql;
char host[100];
char user[100];
char pwd[100];
char db[100];
int port;
char query[1000];
char yn;
int id;
printf("Please enter the host:\n");
scanf("%s",host);
printf("Please enter the username:\n");
scanf("%s",user);
printf("Please enter the password:\n");
scanf("%s",pwd);
printf("Please select a database:\n");
scanf("%s",db);
printf("Please enter the tcp port:\n");
scanf("%d",&port);
mysql_init(&mysql);
if(mysql_real_connect(&mysql, host, user, pwd, db, port, NULL, 0))
{
printf("Please enter the id which you want to delete:\n");
scanf("%d",&id);
getchar();
sprintf(query, "DELETE FROM test WHERE id=%d", id);
if(!mysql_real_query(&mysql,query,strlen(query)))
{
printf("Delete successed!!!\n");
printf("Whether to print the last SQL:(y/n)");
scanf("%c",&yn);
if(yn=='y')
{
printf("%s\n",query);
mysql_close(&mysql);
}
else
{
mysql_close(&mysql);
return;
}
}
else
{
printf("Delete failed!!!\n");
}
}
else
{
printf("Connect to MySQL failed!!!\n");
}
}
#include
#include
#include "mysql.h"
int main()
{
MYSQL mysql;
char host[100];
char user[100];
char pwd[100];
char db[100];
int port;
char query[1000];
char f1[100];
int f2;
char yn;
int id;
printf("Please enter the host:\n");
scanf("%s",host);
printf("Please enter the username:\n");
scanf("%s",user);
printf("Please enter the password:\n");
scanf("%s",pwd);
printf("Please select a database:\n");
scanf("%s",db);
printf("Please enter the tcp port:\n");
scanf("%d",&port);
mysql_init(&mysql);
if(mysql_real_connect(&mysql, host, user, pwd, db, port, NULL, 0))
{
printf("Please enter the content you want to modify on test1:\n");
scanf("%s",f1);
printf("Please enter the content you want to modify on test2:\n");
scanf("%d",&f2);
printf("Please select one id which you want to modify:\n");
scanf("%d",&id);
getchar();
sprintf(query, "UPDATE test SET test1='%s', test2='%d' WHERE id=%d", f1,f2,id);
if(!mysql_real_query(&mysql,query,strlen(query)))
{
printf("Delete successed!!!\n");
printf("Whether to print the last SQL:(y/n)");
scanf("%c",&yn);
if(yn=='y')
{
printf("%s\n",query);
mysql_close(&mysql);
}
else
{
mysql_close(&mysql);
return;
}
}
else
{
printf("Delete failed!!!\n");
}
}
else
{
printf("Connect to MySQL failed!!!\n");
}
}
#include
#include
#include "mysql.h"
int main()
{
MYSQL mysql;
MYSQL_RES *res;
MYSQL_ROW row;
char f1[100];
char f2[100];
char host[100];
char user[100];
char pwd[100];
char db[100];
int port;
char query[1000];
char yn;
int id;
printf("Please enter the host:\n");
scanf("%s",host);
printf("Please enter the username:\n");
scanf("%s",user);
printf("Please enter the password:\n");
scanf("%s",pwd);
printf("Please select a database:\n");
scanf("%s",db);
printf("Please enter the tcp port:\n");
scanf("%d",&port);
mysql_init(&mysql);
if(mysql_real_connect(&mysql, host, user, pwd, db, port, NULL, 0))
{
printf("Please enter the f1:\n");
scanf("%s",f1);
printf("Please enter the f2:\n");
scanf("%s",&f2);
printf("Please enter a id which you want to find:\n");
scanf("%d",&id);
getchar();
sprintf(query, "SELECT %s,%s FROM test WHERE id=%d", f1,f2,id);
if(!mysql_real_query(&mysql,query,strlen(query)))
{
res=mysql_store_result(&mysql);
while(row=mysql_fetch_row(res))
{
printf("%-12s",row[0]);
printf("%12s",row[1]);
printf("\n");
}
printf("Whether to print the last SQL:(y/n)");
scanf("%c",&yn);
if(yn=='y')
{
printf("%s\n",query);
mysql_close(&mysql);
}
else
{
mysql_close(&mysql);
return;
}
}
else
{
printf("Select failed!!!\n");
}
}
else
{
printf("Connect to MySQL failed!!!\n");
}
}
写一个简单的程序来访问该数据库,实现 show tables 功能:
#include
#include
#include
int main()
{
MYSQL *conn;
MYSQL_RES *res;
MYSQL_ROW row;
char server[] = "localhost";
char user[] = "root";
char password[] = "1";
char database[] = "mysql";
conn = mysql_init(NULL);
if (!mysql_real_connect(conn, server,user, password, database, 0, NULL, 0))
{
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);
}
if (mysql_query(conn, "show tables"))
{
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);
}
res = mysql_use_result(conn);
printf("MySQL Tables in mysql database:\n");
while ((row = mysql_fetch_row(res)) != NULL)
{
printf("%s \n", row[0]);
}
mysql_free_result(res);
mysql_close(conn);
printf("finish! \n");
return 0;
}
编译代码的时候需要链接mysql的库,可以通过如下方式编译:
gcc -Wall sqltest.c -o sqltest -lmysqlclient
然后运行编译好的代码:
a@ubuntu:~/db$ gcc -Wall sqltest.c -o sqltest -lmysqlclienta@ubuntu:~/db$ sudo ./sqltest
MySQL Tables in mysql database:
columns_priv
db
event
func
general_log
help_category
help_keyword
help_relation
help_topic
host
ndb_binlog_index
plugin
proc
procs_priv
proxies_priv
servers
slow_log
tables_priv
time_zone
time_zone_leap_second
time_zone_name
time_zone_transition
time_zone_transition_type
user
finish!
假定mysql的头文件在/usr/include/mysql,库文件在/usr/lib/mysql,执行下列命令进行编译:
gcc -gtestsql.c -I/usr/include/mysql -L/usr/lib/mysql -lmysqlclient -lz
在linux上安装好mysql后,建立我们测试用的数据库和表,并插入记录,sql语句如下:
mysql_init()
mysql_real_connect()
mysql_real_query()
mysql_store_result()
mysql_fetch_row()
mysql_free_result()
mysql_close()
MYSQL
MYSQL_RES
MYSQL_ROW
1.调用mysql_init()初始化MYSQL结构,许多的函数执行需要这个结构体。
2.调用mysql_real_connect()连接数据库,参数中涉及到数据库名,数据库登录名,数据库密码等等。
3.调用mysql_real_query()执行一条Select SQL语句,通过mysql_store_result()的返回值获得Select的结果,返回的结果就是一个MYSQL_RES结构的指针。
4.调用mysql_fetch_row()获得一条记录,函数的返回值是MYSQL_ROW对象,这是一个char二维数组。获取一条记录以后,mysql_fetch_row会将游标自动向下移动一条记录。
5.调用mysql_free_result()释放结果资源,调用mysql_close关闭连接。
#include
#include
#include
#include
int main()
{
char out[100];
MYSQL mysql;
MYSQL_RES* res;
int num_fields;
int count_fields;
int num_rows;
mysql_init(&mysql);
mysql_real_connect(&mysql,NULL,"root","123","ta",0,NULL,0);
fprintf(stdout,"--insert------------------------/n");
mysql_real_query(&mysql,"INSERT INTO t1 VALUES(6,'n6')",29);
count_fields = mysql_field_count(&mysql);
sprintf(out,"insert----count_fields is %d/n",count_fields);
fprintf(stdout,out);
res = mysql_store_result(&mysql);
if(res == NULL)
{
fprintf(stdout,"insert---store return null/n");
}
else
{
num_fields = mysql_num_fields(res);
sprintf(out,"insert---num_fields is %d/n",num_fields);
fprintf(stdout,out);
}
fprintf(stdout,"---select-----------/n");
mysql_real_query(&mysql,"SELECT * FROM t1",16);
count_fields = mysql_field_count(&mysql);
sprintf(out,"select---count_fields is %d/n",count_fields);
fprintf(stdout,out);
res = mysql_store_result(&mysql);
if(res == NULL)
{
fprintf(stdout,"select---store return null/n");
}
else
{
num_fields = mysql_num_fields(res);
sprintf(out,"select---num_fields is %d/n",num_fields);
fprintf(stdout,out);
num_rows = mysql_num_rows(res);
sprintf(out,"select---num_rows is %d/n",num_rows);
fprintf(stdout,out);
}
fprintf(stdout,"---select 0------/n");
mysql_real_query(&mysql,"SELECT * FROM t1 where id = 10",30);
count_fields = mysql_field_count(&mysql);
sprintf(out,"select 0---count_fields is %d/n",count_fields);
fprintf(stdout,out);
res = mysql_store_result(&mysql);
if(res == NULL)
{
fprintf(stdout,"select 0---store return null/n");
}
else
{
num_fields = mysql_num_fields(res);
sprintf(out,"select 0---num_fields is %d/n",num_fields);
fprintf(stdout,out);
num_rows = mysql_num_rows(res);
sprintf(out,"select 0---num_rows is %d/n",num_rows);
fprintf(stdout,out);
}
mysql_free_result(res);
mysql_close(&mysql);
exit(0);
}
--insert------------------------
insert----count_fields is 0
insert---store return null
---select-----------
select---count_fields is 2
select---num_fields is 2
select---num_rows is 7
---select 0------
select 0---count_fields is 2
select 0---num_fields is 2
select 0---num_rows is 0
显然,当执行insert语句的时候,是没有结果返回的,因此列的个数为0,且mysql_store_result返回NULL。因此可以通过mysql_field_count()是否返回0来判断是否有结果返回,而不需要执行mysql_store_result来判断是否返回了NULL。我想,mysql_field_count()的效率肯定要比mysql_store_result()高。
在这种情况下,由于没有返回结果,因此mysql_store_result()返回NULL,也就是得不到res指针,于是mysql_num_fields()函数就无法执行,缺少必要的参数。
当执行第一条select语句的时候,返回了结果,因此mysql_field_count()和mysql_num_fields()都返回了正确的列的个数2,mysql_num_rows()返回了记录的条数7.
当执行第二条select语句,由于表中没有 id = 0 的记录,因此mysql_num_rows返回了0表示记录数为0,但是,我们发现mysql_store_result()并没有返回NULL,mysql_num_fields()和mysql_field_count()还是返回了2.
执行结果有三种情况,第一是执行insert、update和delete这样的语句的时候,是不会有任何内容返回,因此mysql_store_result()会返回一个NULL。第二,执行select或show这样的语句时,一定会有内容返回,可以取得列信息,但是记录可以为0,也可以不为0。这就像一个表,表头一定存在,但是表中可以没有数据。
另外:
mysql_affected_rows()函数的作用是,当执行update insert delete 时,返回影响的行数。
MYSQL是用来连接数据库的通讯过程,要连接MYSQL,必须建立MYSQL实例,通过mysql_init初始化方能开始进行连接。这个结构代表返回行的一个查询的(SELECT, SHOW, DESCRIBE, EXPLAIN)的结果
typedef struct st_mysql { NET net; /* Communication parameters */ gptr connector_fd; /* ConnectorFd for SSL */ char *host,*user,*passwd,*unix_socket, *server_version,*host_info,*info,*db; unsigned int port,client_flag,server_capabilities; unsigned int protocol_version; unsigned int field_count; unsigned int server_status; unsigned long thread_id; /* Id for connection in server */ my_ulonglong affected_rows; my_ulonglong insert_id; /* id if insert on table with NEXTNR */ my_ulonglong extra_info; /* Used by mysqlshow */ unsigned long packet_length; enum mysql_status status; MYSQL_FIELD *fields; MEM_ROOT field_alloc; my_bool free_me; /* If free in mysql_close */ my_bool reconnect; /* set to 1 if automatic reconnect */ struct st_mysql_options options; char scramble_buff[9]; struct charset_info_st *charset; unsigned int server_language; } MYSQL; |
返回的数据称为“数据集”,在C的API里对应的就是MYSQL_RES了,从数据库读取数据,最后就是从MYSQL_RES中读取数据。
typedef struct st_mysql_res { my_ulonglong row_count; unsigned int field_count, current_field; MYSQL_FIELD *fields; MYSQL_DATA *data; MYSQL_ROWS *data_cursor; MEM_ROOT field_alloc; MYSQL_ROW row; /* If unbuffered read */ MYSQL_ROW current_row; /* buffer to current row */ unsigned long *lengths; /* column lengths of current row */ MYSQL *handle; /* for unbuffered reads */ my_bool eof; /* Used my mysql_fetch_row */ } MYSQL_RES; |
是一个行数据的类型安全(type-safe)的表示。当前它实现为一个计数字节的字符串 数组。 (如果字段值可能包含二进制数据,你不能将这些视为空终止串,因为这样的值可以在内部包含空字节) 行通过调用mysql_fetch_row()获得
typedef char** MYSQL_ROW; |
这个结构包含字段信息,例如字段名、类型和大小。其成员在下面更详细地描述。你可以通过重复调用mysql_fetch_field()对每一列获得MYSQL_FIELD 结构。字段值不是这个结构的部分;他们被包含在一个MYSQL_ROW 结构中
typedef struct st_mysql_field { char *name; /* Name of column */ char *table; /* Table of column if column was a field */ char *def; /* Default value (set by mysql_list_fields) */ enum enum_field_types type; /* Type of field. Se mysql_com.h for types */ unsigned int length; /* Width of column */ unsigned int max_length; /* Max width of selected set */ unsigned int flags; /* Div flags */ unsigned int decimals; /* Number of decimals in field */ } MYSQL_FIELD |
该类型用于行编号和 mysql_affected_rows ()、mysql_num_rows()和 mysql_insert_id()。这种类型提供 0 到 1.84e19 的一个范围。在一些系统上,试图打印类 型 my_ulonglong 的值将不工作。为了打印出这样的值,将它变换到 unsigned long 并且使 用一个%lu 打印格式。
typedef unsigned long my_ulonglong; |
1) 所需头文件: #include
2) 功能: 获得或初始化一个MYSQL结构
3) 函数原型: MYSQL *mysql_init(MYSQL *mysql)
4) 函数返回值: 一个被始化的MYSQL*句柄
5) 备注: 在内存不足的情况下,返回NULL
1) 所需头文件: #include
2) 函数功能: 关闭一个服务器连接,并释放与连接相关的内存
3) 函数原型: void mysql_close(MYSQL *mysql);
4) 函数传入值: MYSQL类型的指针
5) 函数返回值: 无
1) 所需头文件: #include
2) 函数功能: 连接一个MySQL服务器
3) 函数原型: MYSQL * mysql_connect(MYSQL *mysql,const char *host,const char *user,const char *passwd);
4) 函数传入值: mysql表示一个现存mysql结构的地址
host表示MYSQL服务器的主机名或IP
user表示登录的用户名
passwd表示登录的密码
5) 函数返回值: 如果连接成功,一个MYSQL *连接句柄:如果连接失败,NULL
6) 备注: 该函数不推荐,使用mysql_real_connect()代替
1) 所需文件: #include
2) 函数功能:连接数据库
3) 函数原型:MYSQL *mysql_real_connect(MYSQL *mysql,const char *host,const char *user,const char *passwd,const char *db,unsigned int port,const char *unix_socket,unsigned int client_flag);
4) 函数传入值: mysql表示一个现存mysql结构的地址
host表示MYSQL服务器的主机名或IP
user表示登录的用户名
passwd表示登录的密码
db表示要连接的数据库
port表示MySQL服务器的TCP/IP端口
unix_socket表示连接类型
client_flag表示MySQL运行ODBC数据库的标记
注:
参数的指定方式如下:
第1个参数应是已有MYSQL结构的地址。调用mysql_real_connect()之前,必须调用mysql_init()来初始化MYSQL结构。通过mysql_options()调用,可更改多种连接选项。
“host”的值必须是主机名或IP地址。如果“host”是NULL或字符串"localhost",连接将被视为与本地主机的连接。如果操作系统支持套接字(Unix)或命名管道(Windows),将使用它们而不是TCP/IP连接到服务器。
“user”参数包含用户的MySQL登录ID。如果“user”是NULL或空字符串"",用户将被视为当前用户。在UNIX环境下,它是当前的登录名。在Windows ODBC下,必须明确指定当前用户名。
“passwd”参数包含用户的密码。如果“passwd”是NULL,仅会对该用户的(拥有1个空密码字段的)用户表中的条目进行匹配检查。这样,数据库管理员就能按特定的方式设置MySQL权限系统,根据用户是否拥有指定的密码,用户将获得不同的权限。
调用mysql_real_connect()之前,不要尝试加密密码,密码加密将由客户端API自动处理。
“db”是数据库名称。如果db为NULL,连接会将默认的数据库设为该值。
如果“port”不是0,其值将用作TCP/IP连接的端口号。注意,“host”参数决定了连接的类型。
如果unix_socket不是NULL,该字符串描述了应使用的套接字或命名管道。注意,“host”参数决定了连接的类型。
client_flag的值通常为0,但是,也能将其设置为下述标志的组合,以允许特定功能:
标志名称 |
标志描述 |
CLIENT_COMPRESS |
使用压缩协议。 |
CLIENT_FOUND_ROWS |
返回发现的行数(匹配的),而不是受影响的行数。 |
CLIENT_IGNORE_SPACE |
允许在函数名后使用空格。使所有的函数名成为保留字。 |
CLIENT_INTERACTIVE |
关闭连接之前,允许interactive_timeout秒的不活动时间。 |
CLIENT_LOCAL_FILES |
允许LOAD DATA LOCAL处理功能。 |
CLIENT_MULTI_STATEMENTS |
通知服务器,客户端可能在单个字符串内发送多条语句。使用该标识可以获取多个查询结果 |
CLIENT_MULTI_RESULTS |
通知服务器,客户端能够处理来自多语句执行。 |
CLIENT_NO_SCHEMA |
禁止db_name.tbl_name.col_name语法。 |
CLIENT_ODBC |
客户端是ODBC客户端。它将mysql变得更为ODBC友好。 |
CLIENT_SSL |
使用SSL,该选项不应由应用程序设置,而是在客户端库内部设置。 |
5) 函数返回值: 如果连接成功,返回与第一个参数值相同的一个MYSQL*连接句柄:如果连接失败,返回NULL,通过mysql_error()获取出错原因。
1) 所需头文件: #include
2) 函数功能: 返回最新的UPDATE,DELETE或INSERT查询影响的行数
3) 函数原型:mysql_affected_rows(MYSQL *mysql)
4) 函数传入值: MYSQL类型指针
5) 函数返回值: 大于零的一个整数表示受到影响或检索出来的行数。零表示没有区配查序中WHERE子句的记录或目前还没有查询被执行;-1表示查询返回一个错误,或对于一个SELECT查询
1) 所需头文件: #include
2) 函数功能: 对指定的连接执行查询
3) 函数原型: int mysql_query(MYSQL *mysql,const char *query);
4) 函数传入值: query表示执行的SQL语句
5) 函数返回值: 如果查询成功,为零,出错为非零。
6) 相关函数: mysql_real_query
1) 所需头文件: #include
2) 函数功能:对指定的连接执行查询
3) 函数原型: int mysql_real_query(MYSQL *mysql,const char *query,unsigned int length);
4) 函数传入值: query表示执行的SQL语句
Length表示SQL语句的长度
5) 函数返回值: 如果查询成功,为零,出错为非零。出错的代码及原因如下所示:
出错代码 |
原因 |
CR_COMMANDS_OUT_OF_SYNC |
命令以一个不适当的次序被执行。 |
CR_SERVER_GONE_ERROR |
MySQL服务器关闭了。 |
CR_SERVER_LOST |
对服务器的连接在查询期间失去。 |
CR_UNKNOWN_ERROR |
发生一个未知的错误 |
6) 备注:对于包含二进制数据的查询,使用mysql_real_query()而不是mysql_query(),因为二进制代码数据可能包含“\0”字符,而且,mysql_real_query()比mysql_query()更快,因为它对查询字符串调用strlen()。
1) 所需头文件: #include
2) 函数功能:获取结果标识符
3) 函数原型: MYSQL_RES *mysql_store_result(MYSQL *mysql);
4) 函数传入值: MYSQL:类型的指针
5) 函数返回值: 一个MYSQL_RES结果结构,如果发生一个错误发NULL
6) 备注:
如果希望了解查询是否应返回结果集,可使用mysql_field_count()进行检查。“mysql_field_count()”。mysql_store_result()将查询的全部结果读取到客户端,分配1个MYSQL_RES结构,并将结果置于该结构中。
如果查询未返回结果集,mysql_store_result()将返回Null指针(例如,如果查询是INSERT语句)。如果读取结果集失败,mysql_store_result()还会返回Null指针。通过检查mysql_error()是否返回非空字符串,mysql_errno()是否返回非0值,或mysql_field_count()是否返回0,可以检查是否出现了错误。如果未返回行,将返回空的结果集。(空结果集设置不同于作为返回值的空指针)。一旦调用了mysql_store_result()并获得了不是Null指针的结果,可调用mysql_num_rows()来找出结果集中的行数。
可以调用mysql_fetch_row()来获取结果集中的行,或调用mysql_row_seek()和mysql_row_tell()来获取或设置结果集中的当前行位置。一旦完成了对结果集的操作,必须调用mysql_free_result()。
1) 所需头文件: #include
2) 函数功能: 为无缓冲的结果集获得结果标识符
3) 函数原型: MYSQL_RES *mysql_use_result(MYSQL *mysql);
4) 函数传入值: MYSQL类型的指针
5) 函数返回值: 一个MYSQL_RES结果结构,如果发生一个错误发NULL
6) 备注:
mysql_use_result()将初始化结果集检索,但并不像mysql_store_result()那样将结果集实际读取到客户端。它必须通过对mysql_fetch_row()的调用,对每一行分别进行检索。这将直接从服务器读取结果,而不会将其保存在临时表或本地缓冲区内,与mysql_store_result()相比,速度更快而且使用的内存也更少。客户端仅为当前行和通信缓冲区分配内存,分配的内存可增加到max_allowed_packet字节。
使用mysql_use_result()时,必须执行mysql_fetch_row(),直至返回NULL值,否则,未获取的行将作为下一个检索的一部分返回。C API给出命令不同步错误,如果忘记了执行该操作,将不能运行该命令。不应与从mysql_use_result()返回的结果一起使用mysql_data_seek()、mysql_row_seek()、mysql_row_tell()、mysql_num_rows()或mysql_affected_rows(),也不应发出其他查询,直至mysql_use_result()完成为止。(但是,提取了所有行后,mysql_num_rows()将准确返回提取的行数)。一旦完成了对结果集的操作,必须调用mysql_free_result()。
1) 所需头文件: #include
2) 函数功能: 检索一个结果集合的下一行
3) 函数原型:MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
4) 函数传入值:MYSQL_RES:结构的指针
5) 函数返回值: 下一行的一个MYSQL_ROW结构。如果没有更多的行可检索或如果出现一个错误,NULL
1) 所需头文件: #include
2) 函数功能: 返回最近查询的列数
3) 函数原型:unsigned int mysql_field_count(MYSQL *mysql);
4) 函数传入值:MYSQL类型的指针
5) 函数返回值: 结果集中列数的无符号整数
1) 所需头文件: #include
2) 函数功能: 返回指定结果集中列的数量
3) 函数原型:unsigned int mysql_num_fields(MYSQL_RES *res);
4) 函数传入值:MYSQL_RES 结构的指针
5) 函数返回值: 结果集合中字段数量的一个无符号整数
1) 所需头文件: #include
2) 函数功能: 创建一个数据库
3) 函数原型:int mysql_create_db(MYSQL *mysql,const char *db);
4) 函数传入值:MYSQL:类型的指针
db:要创建的数据库名
5) 函数返回值: 如果数据库成功地被创建,返回零,如果发生错误,为非零。
1) 所需头文件: #include
2) 函数功能: 选择一个数据库
3) 函数原型:int mysql_select_db(MYSQL *mysql,const char *db);
4) 函数传入值:MYSQL:类型的指针
db:要创建的数据库名
5) 函数返回值: 如果数据库成功地被创建,返回零,如果发生错误,为非零。
#include if (!(sock = mysql_real_connect(&mysql,"localhost","dbuser","dbpwd","9tmd_bbs_utf8",0,NULL,0))) { |
使用下面的命令编译
gcc -o demo ./demo.c -I/usr/include/mysql -L/usr/lib64/mysql -lmysqlclient (-lz) (-lm) 后面两个选项可选 |
使用下面的命令运行
./demo |
http://dev.mysql.com/doc/refman/5.1/zh/apis.html
MySQL中的每一个数据库和数据表分别对应文件系统中的目录和其下的文件。
在Linux下数据库文件的存放目录一般为/var/lib/mysql
备份文件前,需要将MySQL服务停止,然后将数据库目录拷贝即可。
恢复数据数据库时,需要先创建好一个数据库(不一定同名),然后将备份出来的文件(注意,不是目录)复制到对应的MySQL数据库目录中。
使用这一方法备份和恢复数据库时,需要新旧的MySQL版本一致,否则可能会出现错误。
备份数据库:mysqldump –user=root –password=root密码 –lock-all-tables 数据库名 > 备份文件.sql
恢复数据库:mysql -u root –password=root密码 数据库名 < 备份文件.sql
把MySql数据库存放目录/var/lib/mysql下面的pw85数据库备份到/home/mysql_data里面,并且保存为mysqldata_bak_2012_04_11.tar.gz的压缩文件格式(2012_04_11是指备份执行时当天的日期), 最后只保留最近7天的备份。
每天你在/home/mysql_data目录下面可以看到类似mysqldata_bak_2012_04_11.tar.gz这样的压缩文件。如果需要恢复文件的时候,只需要把这个文件解压:tar -zxvf mysqldata_bak_2012_04_11.tar.gz
然后导入到数据库中即可。
/home/mysql_data
cd /home #进入目录
mkdir mysql_data #创建目录
:/home/mysql_data/mysql_databak.sh
cd /home/mysql_data #进入目录
touch mysql_databak.sh #创建文件
nano mysql_databak.sh #编辑文件,输入以下内容
chmod +x /home/mysql_data/mysql_databak.sh
nano /etc/crontab #编辑文件,在下面添加
45 22 * * * root /home/mysql_data/mysql_databak.sh #表示每天22点45分执行备份
ctrl+o #保存配置
ctrl+x #退出
service cron stop #停止
service cron start #启动
/etc/init.d/cron restart #重启
chkconfig cron on #设为开机启动
#!/bin/sh
DUMP=/usr/bin/mysqldump #mysqldump备份程序执行路径
OUT_DIR=/home/mysql_data #备份文件存放路径
LINUX_USER=root #系统用户名
DB_NAME=pw85 #要备份的数据库名字
DB_USER=root #数据库账号 注意:非root用户要用备份参数 --skip-lock-tables,否则可能会报错
DB_PASS=123456 #数据库密码
DAYS=7 #DAYS=7代表删除7天前的备份,即只保留最近7天的备份
cd $OUT_DIR #进入备份存放目录
DATE=`date +%Y_%m_%d` #获取当前系统时间
OUT_SQL="$DATE.sql" #备份数据库的文件名
TAR_SQL="mysqldata_bak_$DATE.tar.gz" #最终保存的数据库备份文件名
$DUMP -u$DB_USER -p$DB_PASS $DB_NAME --default-character-set=utf8 --opt -Q -R --skip-lock-tables> $OUT_SQL #备份
tar -czf $TAR_SQL ./$OUT_SQL #压缩为.tar.gz格式
rm $OUT_SQL #删除.sql格式的备份文件
chown $LINUX_USER:$LINUX_USER $OUT_DIR/$TAR_SQL #更改备份数据库文件的所有者
find $OUT_DIR -name "mysqldata_bak*" -type f -mtime +$DAYS -exec rm {} \; #删除7天前的备份文件
mysqldump -hhostname -uusername -ppassword databasename > backupfile.sql
备份MySQL数据库为带删除表的格式备份MySQL数据库为带删除表的格式,能够让该备份覆盖已有数据库而不需要手动删除原有数据库。
mysqldump ---add-drop-table -uusername -ppassword databasename > backupfile.sql
mysqldump -hhostname -uusername -ppassword databasename | gzip > backupfile.sql.gz
mysqldump -hhostname -uusername -ppassword databasename specific_table1 specific_table2 > backupfile.sql
mysqldump -hhostname -uusername -ppassword --databases databasename1 databasename2 databasename3 > multibackupfile.sql
mysqldump --no-data --databases databasename1 databasename2 databasename3 > structurebackupfile.sql
mysqldump --all-databases allbackupfile.sql
mysql -hhostname -uusername -ppassword databasename < backupfile.sql
gunzip < backupfile.sql.gz | mysql -uusername -ppassword databasename
mysqldump \-uusername \-ppassword databasename \| mysql \--host=*.*.*.\* \-C databasename
mysqldump < mysqldump options> | gzip > outputfile.sql.gz
gunzip < outputfile.sql.gz | mysql < mysql options>
mysqldump < mysqldump options> | bzip2 > outputfile.sql.bz2
bunzip2 < outputfile.sql.bz2 | mysql < mysql options>
sudo
/etc/init
.d
/mysql
start
sudo
/etc/init
.d
/mysql
stop
sudo
/etc/init
.d
/mysql
restart
cat
/var/log/mysql
.err
cat
/var/log/mysql/error
.log
修改 /etc/mysql/my.cnf
在 [client] 下面增加:
default-character-set=utf8 或 character_set_server=utf8
在 [mysqld] 下面增加:
default-character-set=utf8 或 character_set_server=utf8
unknown variable 'default-character-set=utf8'
修改配置文件 /etc/mysql/my.cnf 中的“default-character-set=utf8” 为 “character_set_server=utf8”
1) Mysql刚安装好后无密码,使用”mysqladmin–uroot password 密码”修改管理员密码
2) 以管理员身份登录数据库,使用”mysql–u root”
3) 原来有密码,现在要修改,使用”mysqladmin–uroot–p旧密码 password 新密码”
Mysql安装好后,默认有两个数据库(mysql和test),而且除了root用户外,其他用户只能访问test数据库。
Mysql中设置了5个授权表(user/db/host/tables_priv/columnts_priv)。
1) 创建新用户,方法如下:
A. mysql–u root –p #以管理员身份登录
B. insert into mysql.user(host,user,password) values(‘%’,’guest’,password(‘guest’));#创建一个用户名为guest的用户
C. flush privileges;#重载授权表
2) 删除用户,方法如下:
A. mysql–u root –p #以管理员身份登录
B. delete from mysql.user where user=’guest’;
C. flush privileges;
3) 更改用户密码,方法如下:
A. mysql–u root –p #以管理员身份登录
B. update mysql.user set password=password(‘123’) where user=’guest’;
C. flush privileges;
4) 用户授权,方法如下:
格式:GRANT 权限列表[(字段列表)] ON 数据库名称.表名 TO 用户名@域名或IP地址 [IDENTIFIED BY ‘密码值’] [WITH GRANT OPTION];
常用权限如下:
全局管理权限: |
例一:要授权给用户guest可以从任意主机连接到数据库服务器,并具有完全访问学生选课数据库xsxk的权限。
grant all on xsxk.* to guest@’%’ identified by ‘guest’;
说明:
A. %表示从任何主机连接到数据库服务器,也可以用空白
B. %.gdvcp.net 表示从gdvcp.net域中的任何主机连接到数据库服务器
C. 192.168.85.% 表示从192.168.85.0子网中任何主机连接到数据库服务器
D. localhost 表示从本地主机连接
E. 192.168.85.242 表示从IP为192.168.85.242的主机连接
例二:新建一个用户tom,让他能从子网192.168.85.0中任何主机连接到数据库服务器,可以读取数据库xsxk的内容,并且能修改表course中字段teacher的值。
grant select on xsxk.* to tom@’192.168.85.%’ identified by ‘123’;
grant update(teacher) on xsxk.course to tom@’192.168.85.%’;
例三:mysql管理员要授权用户admin可以从本地连接到数据库服务器,对学生选课数据库xsxk具有完全访问权限,并可将其拥有的权限授予其他用户
grant all on xsxk.* to admin@localhost identified by ‘123’ with grant option;
5) 用户撤权,方法如下:
格式:REVOKE 权限列表[(字段列表)] ON 数据库名.表名 FROM 用户名@域名或IP地址;
例:mysql管理员要撤销用户admin@localhost对数据库xsxk所拥有的创建删除数据库与表的权限,并撤销该用户可以把自己拥有的权限授予其他用户的权限。
revokecreate,drop on xsxk.* from admin@localhost;
revoke grant option on xsxk.* from admin@localhost;
1) 创建数据库:create database 数据库名;
2) 查看数据库:show databases;
3) 选择数据库:use 数据库名;
4) 删除数据库:drop database 数据库名;
1) 创建表
格式:create table 表名(字段1,…字段n,[表级约束]) [Type=表类型];
注:
A. 字段i(i=1,…n)格式为:
字段名 字段类型 [字段约束]
说明一:字段类型,规定了某字段所允许输入的数据类型
类型 |
描述 |
int |
允许值在0至2的32次方减1(无符号)之间标准整数 |
double |
双精度浮点数 |
char |
最大长度不超过255字符定长字符串 |
varchar |
最大长度不超过255字符变长字符串 |
text |
最大长度为65535字符字符串 |
blob |
可变数据的二进制类型 |
date |
YYYYMMDD格式日期类型 |
说明二:字段约束,用来进一步对某个字段所允许输入的数据进行约束,常用的字段约束如下:
约束 |
描述 |
NULL(或NOT NULL) |
指定允许(或不允许)某字段为空,默认为NULL |
DEFAULT |
为某字段指定一个默认值 |
AUTO_INCREMENT |
自动为某个INT字段生成一个递增1的整数 |
B. 表级约束:用于表示表的主键、外键、索引和唯一约束。
约束 |
描述 |
Primary key |
为表指定主键 |
Foreign key ……References |
为表指定外键 |
Unique |
为某字段创建索引,此字段必须唯一 |
Fulltext |
为某字段建立全文索引 |
C. 表类型:用于指定表的类型,即数据的存储格式。
表类型 |
描述 |
MyISAM |
具有很多优化和增强的特性,是mysql默认表类型 |
ISAM |
类似于MyISAM,但功能较少 |
HEAP |
保存在内存中,存取速度快,但存储容量小,恢复难 |
BDB |
支持事务和页锁定 |
INNODB |
支持事务、外键和行级锁,是mysql中最完善表格式 |
MERGE |
可把多个MyISAM表构建为一个虚拟表,使得这些表的查询就像在一个表上进行,提高查询速度和修复效率,并节省了磁盘空间 |
例:create table student(snovarchar(7) not null, snamevarchar(20) not null, ssex char(1) default ‘t’, sbirthday date, sdepa char(20), primary key(sno));
注:
a) 建好后可通过describe命令查看表结构
b) 系统会在/var/lib(or lib64)/mysql/xxkk目录下创建student.frm(表定义文件)、student.MDY(数据文件)、student.MYI(索引文件)三个文件
2) 复制表
格式:create table 新表名 like 源表名;
3) 删除表
格式:drop table 表名1[,表名2,…];
4) 修改表
格式:alter table 表名 更改动作1[,更改动作2,…];
A. 增加表中字段
alter table student add saddressvarchar(25);
B. 更改表字段名和字段类型
alter table student change saddressbeizhu text;
C. 删除字段
alter table student drop beizhu;
D. 更改名称
alter table student rename to xs;
1) 插入记录
格式:insert into 表名(字段1,字段2,…,字段n) values(字段1的值,字段2的值,…,字段n的值);
例1:要在表student中插入一组数据
insert into student(sno,sname,ssex,sbirthday,sdepa) values(‘1’,’lilei’,default,19850721,’math’);
例2:要插入与前一次操作相同的记录,可使用如下的缩写
insert into student values(‘1’,’lilei’,default,19850721,’math’);
例3:表中有默认字段,若取默认字段值,这时只需修改要修改的内容
insert into student(sno,sname,sbirthday) values(‘2’,’lucy’,19850613);
例4:在一个insert语句中使用多个values字句,可插入多条记录
insert into student values(‘3’,’hanmeimei’,’f’,19850203,’computer’),(‘4’,’lily’,f,19850613,’computer’);
2) 删除记录
格式:delete from 表名 where 条件表达式
例1:删除表student中sno为’3’的记录
delete from student where sno=’3’;
例2:从表student中删除sname字段值前2位为’li’的记录
delete from student where left(sname,2)=’li’;
删除表中所有记录的方法:truncate table student;
3) 修改记录
格式:update 表名 set 字段名1=字段值1[,字段名2=字段值2,…] where 条件表达式;
例:修改表student中sno为’1’的记录,将其sdepa字段值改为’computer’
update student set sdepa=’computer’ where sno=’1’;
1) 在创建表的同时创建索引
例:要创建一个选课课程表course,将课程编号cno设置为主键,同时为课程名称cname创建名为cna的索引
create table course(cnovarchar(5) not null, cnamevarchar(30) not null, teacher varchar(20), primary key(cno), index can(cname));
2) 向已存在的表添加索引(unique或index子句)
格式:create [unique] index 索引名 on 表名(字段名1[(长度)],…);
例1:为表student的sname创建名为sna的索引
create index sna on student(sname);
例2:为表student的sname创建名为sna的索引,且索引长度为10
create index sna on student(sname(10));
3) 删除索引
格式:drop index 索引名 on 表名;
例:删除表student中索引名为sna的索引
drop index sna on student;
Mysql的查询语句和SQL Server基本相同,不同之处包括以下几点:
1) 获取前n个记录:SQL Server使用top n,位于select之后;mysql使用limit n,位于整个查询语句之后
存储过程是数据库存储的一个重要的功能,但是MySQL在5.0以前并不支持存储过程。
CREATE PROCEDURE过程名([过程参数[,...]])
[特性...]过程体
例子:
mysql> DELIMITER // mysql> CREATE PROCEDURE proc1(OUT s int) -> BEGIN -> SELECT COUNT(*) INTO s FROM user; -> END -> // mysql> DELIMITER ; |
注:
A. 这里需要注意的是DELIMITER //和DELIMITER ;两句,DELIMITER是分割符的意思,因为MySQL默认以";"为分隔符,如果我们没有声明分割符,那么编译器会把存储过程当成SQL语句进行处理,则存储过程的编译过程会报错,所以要事先用DELIMITER关键字申明当前段分隔符,这样MySQL才会将";"当做存储过程中的代码,不会执行这些代码,用完了之后要把分隔符还原。
B. 存储过程根据需要可能会有输入、输出、输入输出参数,这里有一个输出参数s,类型是int型,如果有多个参数用","分割开。
C. 如果过程体为多行,则它的开始与结束使用BEGIN与END进行标识。
如果是用MySQL的Administrator管理工具时,可以直接创建,不再需要声明分割符。
MySQL存储过程的参数用在存储过程的定义,共有三种参数类型,IN,OUT,INOUT,形式如:
CREATE PROCEDURE([[IN |OUT |INOUT ]参数名数据类形...])
IN输入参数:表示该参数的值必须在调用存储过程时指定,在存储过程中修改该参数的值不能被返回,为默认值
OUT输出参数:该值可在存储过程内部被改变,并可返回
INOUT输入输出参数:调用时指定,并且可被改变和返回
1) IN参数例子
创建:
1. mysql > DELIMITER // 2. mysql > CREATE PROCEDURE demo_in_parameter(IN p_in int) 3. -> BEGIN 4. -> SELECT p_in; 5. -> SET p_in=2; 6. -> SELECT p_in; 7. -> END; 8. -> // 9. mysql > DELIMITER ; |
执行结果:
1. mysql > SET @p_in=1; 2. mysql > CALL demo_in_parameter(@p_in); 3. +------+ 4. | p_in | 5. +------+ 6. | 1 | 7. +------+ 8. 9. +------+ 10. | p_in | 11. +------+ 12. | 2 | 13. +------+ 14. 15. mysql> SELECT @p_in; 16. +-------+ 17. | @p_in | 18. +-------+ 19. | 1 | 20. +-------+ |
以上可以看出,p_in虽然在存储过程中被修改,但并不影响@p_id的值
2) OUT参数例子
创建:
1. mysql > DELIMITER // 2. mysql > CREATE PROCEDURE demo_out_parameter(OUT p_out int) 3. -> BEGIN 4. -> SELECT p_out; 5. -> SET p_out=2; 6. -> SELECT p_out; 7. -> END; 8. -> // 9. mysql > DELIMITER ; |
执行结果:
1. mysql > SET @p_out=1; 2. mysql > CALL sp_demo_out_parameter(@p_out); 3. +-------+ 4. | p_out | 5. +-------+ 6. | NULL | 7. +-------+ 8. 9. +-------+ 10. | p_out | 11. +-------+ 12. | 2 | 13. +-------+ 14. 15. mysql> SELECT @p_out; 16. +-------+ 17. | p_out | 18. +-------+ 19. | 2 | 20. +-------+ |
3) INOUT参数例子
创建:
1. mysql > DELIMITER // 2. mysql > CREATE PROCEDURE demo_inout_parameter(INOUT p_inout int) 3. -> BEGIN 4. -> SELECT p_inout; 5. -> SET p_inout=2; 6. -> SELECT p_inout; 7. -> END; 8. -> // 9. mysql > DELIMITER ; |
执行结果:
1. mysql > SET @p_inout=1; 2. mysql > CALL demo_inout_parameter(@p_inout) ; 3. +---------+ 4. | p_inout | 5. +---------+ 6. | 1 | 7. +---------+ 8. 9. +---------+ 10. | p_inout | 11. +---------+ 12. | 2 | 13. +---------+ 14. 15. mysql > SELECT @p_inout; 16. +----------+ 17. | @p_inout | 18. +----------+ 19. | 2 | 20. +----------+ |
1) 变量定义
DECLARE variable_name [,variable_name...] datatype [DEFAULT value];
其中,datatype为MySQL的数据类型,如:int, float, date, varchar(length)
例如:
1. DECLARE l_int int unsigned default 4000000;
2. DECLARE l_numeric number(8,2) DEFAULT 9.95;
3. DECLARE l_date date DEFAULT '1999-12-31';
4. DECLARE l_datetime datetime DEFAULT '1999-12-31 23:59:59';
5. DECLARE l_varchar varchar(255) DEFAULT 'This will not be padded';
2) 变量赋值
SET变量名=表达式值[,variable_name = expression ...]
3) 用户变量
A. 在MySQL客户端使用用户变量
1. mysql > SELECT 'Hello World' into @x; 2. mysql > SELECT @x; 3. +-------------+ 4. | @x | 5. +-------------+ 6. | Hello World | 7. +-------------+ 8. mysql > SET @y='Goodbye Cruel World'; 9. mysql > SELECT @y; 10. +---------------------+ 11. | @y | 12. +---------------------+ 13. | Goodbye Cruel World | 14. +---------------------+ 15. 16. mysql > SET @z=1+2+3; 17. mysql > SELECT @z; 18. +------+ 19. | @z | 20. +------+ 21. | 6 | 22. +------+ |
B. 在存储过程中使用用户变量
1. mysql > CREATE PROCEDURE GreetWorld( ) SELECT CONCAT(@greeting,' World'); 2. mysql > SET @greeting='Hello'; 3. mysql > CALL GreetWorld( ); 4. +----------------------------+ 5. | CONCAT(@greeting,' World') | 6. +----------------------------+ 7. | Hello World | 8. +----------------------------+ |
C. 在存储过程间传递全局范围的用户变量
1. mysql> CREATE PROCEDURE p1() SET @last_procedure='p1'; 2. mysql> CREATE PROCEDURE p2() SELECT CONCAT('Last procedure was ',@last_proc); 3. mysql> CALL p1( ); 4. mysql> CALL p2( ); 5. +-----------------------------------------------+ 6. | CONCAT('Last procedure was ',@last_proc | 7. +-----------------------------------------------+ 8. | Last procedure was p1 | 9. +-----------------------------------------------+ |
注意:
a) 户变量名一般以@开头
b) 滥用用户变量会导致程序难以理解及管理
MySQL存储过程可使用两种风格的注释
双模杠:--一般用于单行注释
c风格:一般用于多行注释
例如:
1. mysql > DELIMITER // 2. mysql > CREATE PROCEDURE proc1 --name存储过程名 3. -> (IN parameter1 INTEGER) 4. -> BEGIN 5. -> DECLARE variable1 CHAR(10); 6. -> IF parameter1 = 17 THEN 7. -> SET variable1 = 'birds'; 8. -> ELSE 9. -> SET variable1 = 'beasts'; 10. -> END IF; 11. -> INSERT INTO table1 VALUES (variable1); 12. -> END 13. -> // 14. mysql > DELIMITER ; |
1) MySQL 存储过程名字后面的“()”是必须的,即使没有一个参数,也需要“()”
2) MySQL 存储过程参数,不能在参数名称前加“@”,如:“@a int”。下面的创建存储过程语法在 MySQL 中是错误的(在 SQL Server 中是正确的)。 MySQL 存储过程中的变量,不需要在变量名字前加“@”,虽然 MySQL 客户端用户变量要加个“@”。
create procedure pr_add ( @a int, -- 错误 b int -- 正确 ) |
3) MySQL 存储过程的参数不能指定默认值。
4) MySQL 存储过程不需要在 procedure body 前面加 “as”。而 SQL Server 存储过程必须加 “as” 关键字。
create procedure pr_add ( a int, b int ) as -- 错误,MySQL 不需要 “as” begin mysql statement ...; end; |
5) 如果 MySQL 存储过程中包含多条 MySQL 语句,则需要 begin end 关键字。
6) MySQL 存储过程中的每条语句的末尾,都要加上分号 “;”
7) 不能在 MySQL 存储过程中使用 “return” 关键字。
8) 因为 MySQL 存储过程参数没有默认值,所以在调用 MySQL 存储过程时候,不能省略参数。可以用 null 来替代
用call和你过程名以及一个括号,括号里面根据需要,加入参数,参数包括输入参数、输出参数、输入输出参数。具体的调用方法可以参看上面的例子。
我们像知道一个数据库下面有那些表,我们一般采用show tables;进行查看。那么我们要查看某个数据库下面的存储过程,是否也可以采用呢?答案是,我们可以查看某个数据库下面的存储过程,但是是令一钟方式。
我们可以用
select name from mysql.proc where db=’数据库名’;
或者
select routine_name from information_schema.routines where routine_schema='数据库名';
或者
show procedure status where db='数据库名';
进行查询。
如果我们想知道,某个存储过程的详细,那我们又该怎么做呢?是不是也可以像操作表一样用describe表名进行查看呢?
答案是:我们可以查看存储过程的详细,但是需要用另一种方法:
SHOW CREATE PROCEDURE数据库.存储过程名;
就可以查看当前存储过程的详细。
ALTER PROCEDURE
更改用CREATE PROCEDURE建立的预先指定的存储过程,其不会影响相关存储过程或存储功能。
DROP PROCEDURE
从MySQL的表格中删除一个或多个存储过程。
变量作用域
内部的变量在其作用域范围内享有更高的优先权,当执行到end。变量时,内部变量消失,此时已经在其作用域外,变量不再可见了,应为在存储
过程外再也不能找到这个申明的变量,但是你可以通过out参数或者将其值指派
给会话变量来保存其值。
1. mysql > DELIMITER // 2. mysql > CREATE PROCEDURE proc3() 3. -> begin 4. -> declare x1 varchar(5) default 'outer'; 5. -> begin 6. -> declare x1 varchar(5) default 'inner'; 7. -> select x1; 8. -> end; 9. -> select x1; 10. -> end; 11. -> // 12. mysql > DELIMITER ; |
条件语句
1) if-then -else语句
1. mysql > DELIMITER // 2. mysql > CREATE PROCEDURE proc2(IN parameter int) 3. -> begin 4. -> declare var int; 5. -> set var=parameter+1; 6. -> if var=0 then 7. -> insert into t values(17); 8. -> end if; 9. -> if parameter=0 then 10. -> update t set s1=s1+1; 11. -> else 12. -> update t set s1=s1+2; 13. -> end if; 14. -> end; 15. -> // 16. mysql > DELIMITER ; |
2) case语句:
1. mysql > DELIMITER // 2. mysql > CREATE PROCEDURE proc3 (in parameter int) 3. -> begin 4. -> declare var int; 5. -> set var=parameter+1; 6. -> case var 7. -> when 0 then 8. -> insert into t values(17); 9. -> when 1 then 10. -> insert into t values(18); 11. -> else 12. -> insert into t values(19); 13. -> end case; 14. -> end; 15. -> // 16. mysql > DELIMITER ; |
3) 循环语句
A. while ···· end while:
1. mysql > DELIMITER // 2. mysql > CREATE PROCEDURE proc4() 3. -> begin 4. -> declare var int; 5. -> set var=0; 6. -> while var<6 do 7. -> insert into t values(var); 8. -> set var=var+1; 9. -> end while; 10. -> end; 11. -> // 12. mysql > DELIMITER ; |
B. repeat···· end repeat:
1. mysql > DELIMITER // 2. mysql > CREATE PROCEDURE proc5 () 3. -> begin 4. -> declare v int; 5. -> set v=0; 6. -> repeat 7. -> insert into t values(v); 8. -> set v=v+1; 9. -> until v>=5 10. -> end repeat; 11. -> end; 12. -> // 13. mysql > DELIMITER ; |
C. loop ·····end loop:
loop循环不需要初始条件,这点和while循环相似,同时和repeat循环一样不需要结束条件, leave语句的意义是离开循环。
1. mysql > DELIMITER // 2. mysql > CREATE PROCEDURE proc6 () 3. -> begin 4. -> declare v int; 5. -> set v=0; 6. -> LOOP_LABLE:loop 7. -> insert into t values(v); 8. -> set v=v+1; 9. -> if v >=5 then 10. -> leave LOOP_LABLE; 11. -> end if; 12. -> end loop; 13. -> end; 14. -> // 15. mysql > DELIMITER ; |
D. LABLES标号:
标号可以用在begin repeat while或者loop语句前,语句标号只能在合法的语句前面使用。可以跳出循环,使运行指令达到复合语句的最后一步。
4) ITERATE迭代
通过引用复合语句的标号,来从新开始复合语句
1. mysql > DELIMITER // 2. mysql > CREATE PROCEDURE proc10 () 3. -> begin 4. -> declare v int; 5. -> set v=0; 6. -> LOOP_LABLE:loop 7. -> if v=3 then 8. -> set v=v+1; 9. -> ITERATE LOOP_LABLE; 10. -> end if; 11. -> insert into t values(v); 12. -> set v=v+1; 13. -> if v>=5 then 14. -> leave LOOP_LABLE; 15. -> end if; 16. -> end loop; 17. -> end; 18. -> // 19. mysql > DELIMITER ; |
字符串类
1) CHARSET(str) //返回字串字符集
2) CONCAT (string2 [,... ]) //连接字串
3) INSTR (string ,substring ) //返回substring首次在string中出现的位置,不存在返回0
4) LCASE (string2 ) //转换成小写
5) LEFT (string2 ,length ) //从string2中的左边起取length个字符
6) LENGTH (string ) //string长度
7) LOAD_FILE (file_name ) //从文件读取内容
8) LOCATE (substring , string [,start_position ] )同INSTR,但可指定开始位置
9) LPAD (string2 ,length ,pad ) //重复用pad加在string开头,直到字串长度为length
10) LTRIM (string2 ) //去除前端空格
11) REPEAT (string2 ,count ) //重复count次
12) REPLACE (str ,search_str ,replace_str ) //在str中用replace_str替换search_str
13) RPAD (string2 ,length ,pad) //在str后用pad补充,直到长度为length
14) RTRIM (string2 ) //去除后端空格
15) STRCMP (string1 ,string2 ) //逐字符比较两字串大小,
16) SUBSTRING (str , position [,length ]) //从str的position开始,取length个字符
注:mysql中处理字符串时,默认第一个字符下标为1,即参数position必须大于等于1
例:
1. mysql> select substring('abcd',0,2); 2. +-----------------------+ 3. | substring('abcd',0,2) | 4. +-----------------------+ 5. | | 6. +-----------------------+ 7. 1 row in set (0.00 sec) 8. 9. mysql> select substring('abcd',1,2); 10. +-----------------------+ 11. | substring('abcd',1,2) | 12. +-----------------------+ 13. | ab | 14. +-----------------------+ 15. 1 row in set (0.02 sec) |
17) TRIM([[BOTH|LEADING|TRAILING] [padding] FROM]string2) //去除指定位置的指定字符
18) UCASE (string2 ) //转换成大写
19) RIGHT(string2,length) //取string2最后length个字符
20) SPACE(count) //生成count个空格
数学类
1) ABS (number2 ) //绝对值
2) BIN (decimal_number ) //十进制转二进制
3) CEILING (number2 ) //向上取整
4) CONV(number2,from_base,to_base) //进制转换
5) FLOOR (number2 ) //向下取整
6) FORMAT (number,decimal_places ) //保留小数位数
7) HEX (DecimalNumber ) //转十六进制
注:HEX()中可传入字符串,则返回其ASC-11码,如HEX('DEF')返回4142143
也可以传入十进制整数,返回其十六进制编码,如HEX(25)返回19
8) LEAST (number , number2 [,..]) //求最小值
9) MOD (numerator ,denominator ) //求余
10) POWER (number ,power ) //求指数
11) RAND([seed]) //随机数
12) ROUND (number [,decimals ]) //四舍五入,decimals为小数位数]
注:返回类型并非均为整数,如:
(1)默认变为整形值
1. mysql> select round(1.23); 2. +-------------+ 3. | round(1.23) | 4. +-------------+ 5. | 1 | 6. +-------------+ 7. 1 row in set (0.00 sec) 8. 9. mysql> select round(1.56); 10. +-------------+ 11. | round(1.56) | 12. +-------------+ 13. | 2 | 14. +-------------+ 15. 1 row in set (0.00 sec) |
(2)可以设定小数位数,返回浮点型数据
1. mysql> select round(1.567,2); 2. +----------------+ 3. | round(1.567,2) | 4. +----------------+ 5. | 1.57 | 6. +----------------+ 7. 1 row in set (0.00 sec) 8. SIGN (number2 ) // |
日期时间类
1) ADDTIME (date2 ,time_interval ) //将time_interval加到date2
2) CONVERT_TZ (datetime2 ,fromTZ ,toTZ ) //转换时区
3) CURRENT_DATE ( ) //当前日期
4) CURRENT_TIME ( ) //当前时间
5) CURRENT_TIMESTAMP ( ) //当前时间戳
6) DATE (datetime ) //返回datetime的日期部分
7) DATE_ADD (date2 , INTERVAL d_valued_type ) //在date2中加上日期或时间
8) DATE_FORMAT (datetime ,FormatCodes ) //使用formatcodes格式显示datetime
9) DATE_SUB (date2 , INTERVAL d_valued_type ) //在date2上减去一个时间
10) DATEDIFF (date1 ,date2 ) //两个日期差
11) DAY (date ) //返回日期的天
12) DAYNAME (date ) //英文星期
13) DAYOFWEEK (date ) //星期(1-7) ,1为星期天
14) DAYOFYEAR (date ) //一年中的第几天
15) EXTRACT (interval_name FROM date ) //从date中提取日期的指定部分
16) MAKEDATE (year ,day ) //给出年及年中的第几天,生成日期串
17) MAKETIME (hour ,minute ,second ) //生成时间串
18) MONTHNAME (date ) //英文月份名
19) NOW ( ) //当前时间
20) SEC_TO_TIME (seconds ) //秒数转成时间
21) STR_TO_DATE (string ,format ) //字串转成时间,以format格式显示
22) TIMEDIFF (datetime1 ,datetime2 ) //两个时间差
23) TIME_TO_SEC (time ) //时间转秒数]
24) WEEK (date_time [,start_of_week ]) //第几周
25) YEAR (datetime ) //年份
26) DAYOFMONTH(datetime) //月的第几天
27) HOUR(datetime) //小时
28) LAST_DAY(date) //date的月的最后日期
29) MICROSECOND(datetime) //微秒
30) MONTH(datetime) //月
31) MINUTE(datetime) //分返回符号,正负或0
32) SQRT(number2) //开平方
事务
-- 启动事务 start transaction; …… -- 运行没有异常,提交事务 |
游标
-- 声明游标
-- 声明游标的异常处理,设置一个终止标记
-- 打开游标
-- 读取一行数据到变量
-- 这个就是判断是否游标已经到达了最后
-- 读取下一行的数据
-- 关闭游标 close cur; |
格式:create [or replace] [algorithm = {undefined | merge | temptable}] view [db_name.]view_name [(column_list)] as select_statement [with [cascaded | local] check option]
注:
A. 若给定了[or replace],则表示当已具有同名的视图时,将覆盖原视图。
B. select_statement是一个查询语句,这个查询语句可从表或其它的视图中查询。
C. 视图属于数据库,因此需要指定数据库的名称,若未指定时,表示在当前的数据库创建新视图。
D. 表和表共享数据库中相同的名称空间,因此,数据库不能包含相同名称的表和视图,并且,视图的列名也不能重复。
创建一个产品表(product)和一个购买记录表(purchase),再通过视图purchase_detail查询出购买的详细信息。
create table product |
创建成功后,输入:select * from purchase_detail;
运行效果如下:
+-------+-------+-----+-------------+ |
1) 运行创建视图的语句需要用户具有创建视图(crate view)的权限,若加了[or replace]时,还需要用户具有删除视图(drop view)的权限;
2) select语句不能包含from子句中的子查询;
3) select语句不能引用系统或用户变量;
4) select语句不能引用预处理语句参数;
5) 在存储子程序内,定义不能引用子程序参数或局部变量;
6) 在定义中引用的表或视图必须存在。但是,创建了视图后,能够舍弃定义引用的表或视图。要想检查视图定义是否存在这类问题,可使用check table语句;
7) 在定义中不能引用temporary表,不能创建temporary视图;
8) 在视图定义中命名的表必须已存在;
9) 不能将触发程序与视图关联在一起;
10) 在视图定义中允许使用order by,但是,如果从特定视图进行了选择,而该视图使用了具有自己order by的语句,它将被忽略。
格式:alter [algorithm = {undefined | merge | temptable}] view view_name [(column_list)] as select_statement [with [cascaded | local] check option]
将上一小节中中创建的视purchase_detail进行修改,去掉qty列,语句如下:
alter view purchase_detail as select product.name as name, product .price as price, product .price * purchase.qty as total_value from product, purchase where product.product_id = purchase.product_id; |
MySQL的事件调度器可以精确到每秒钟执行一个任务,而操作系统的计划任务(如:Linux下的CRON或Windows下的任务计划)只能精确到每分钟执行一次。
事件调度器有时也可称为临时触发器(temporal triggers),因为事件调度器是基于特定时间周期触发来执行某些任务,而触发器(Triggers)是基于某个表所产生的事件触发的,区别也就在这里。
有如下几种方法:
1) 执行:SET GLOBAL event_scheduler = 1
2) 执行:SET GLOBAL event_scheduler = ON
3) 在配置my.cnf文件 中加上 event_scheduler = 1
4) 在启动命令加上”--event_scheduler=1”
有如下方法:
1) 执行:SHOW VARIABLES LIKE “event_scheduler”
2) 执行:select @event_scheduler
3) 执行:SHOW PROCESSLIST
CREATE EVENT [IF NOT EXISTS] event_name ON SCHEDULE schedule [ON COMPLETION [NOT] PRESERVE] [ENABLE | DISABLE] [COMMENT 'comment'] DO sql_statement; |
1) schedule:
AT TIMESTAMP [+ INTERVAL INTERVAL]
| EVERY INTERVAL [STARTS TIMESTAMP] [ENDS TIMESTAMP]
2) INTERVAL:
quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |
WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |
DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}
先创建一个表
CREATE TABLE aaa (timeline TIMESTAMP); |
1) 每秒插入一条记录到数据表
CREATE EVENT e_test_insert ON SCHEDULE EVERY 1 SECOND DO INSERT INTO aaa VALUES (CURRENT_TIMESTAMP); |
2) 5天后清空aaa表
CREATE EVENT e_test ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 5 DAY DO TRUNCATE TABLE aaa; |
3) 每天定时清空aaa表:
CREATE EVENT e_test ON SCHEDULE EVERY 1 DAY DO TRUNCATE TABLE aaa; |
4) 5天后开启每天定时清空aaa表:
CREATE EVENT e_test ON SCHEDULE EVERY 1 DAY STARTS CURRENT_TIMESTAMP + INTERVAL 5 DAY DO TRUNCATE TABLE aaa; |
5) 每天定时清空aaa表,5天后停止执行:
CREATE EVENT e_test ON SCHEDULE EVERY 1 DAY ENDS CURRENT_TIMESTAMP + INTERVAL 5 DAY DO TRUNCATE TABLE aaa; |
6) 5天后开启每天定时清空test表,一个月后停止执行:
CREATE EVENT e_test ON SCHEDULE EVERY 1 DAY STARTS CURRENT_TIMESTAMP + INTERVAL 5 DAY ENDS CURRENT_TIMESTAMP + INTERVAL 1 MONTH DO TRUNCATE TABLE aaa; |
7) 每天定时清空test表(只执行一次,任务完成后就终止该事件):
[ON COMPLETION [NOT] PRESERVE]可以设置这个事件是执行一次还是持久执行,默认为NOT PRESERVE。[ENABLE | DISABLE]可是设置该事件创建后状态是否开启或关闭,默认为ENABLE。[COMMENT ‘comment’]可以给该事件加上注释。
CREATE EVENT e_test ON SCHEDULE EVERY 1 DAY ON COMPLETION NOT PRESERVE DO TRUNCATE TABLE aaa; |
ALTER EVENT event_name [ON SCHEDULE schedule] [RENAME TO new_event_name] [ON COMPLETION [NOT] PRESERVE] [COMMENT 'comment'] [ENABLE | DISABLE] [DO sql_statement] |
1) 临时关闭事件:ALTER EVENT e_test DISABLE | OFF
2) 开启事件:ALTER EVENT e_test ENABLE | ON
3) 将每天清空aaa表改为5天清空一次:
ALTER EVENT e_test ON SCHEDULE EVERY 5 DAY; |
DROP EVENT [IF EXISTS] event_name |
1) 删除事件的前提是事件必须存在,否则会产生ERROR 1513(HY000):Unknown event错误,因此最好加上IF EXISTS
2) 删除事件时如果事件状态为DISABLE,则当重新启动mysql服务后,该事件将被删除
当用变量做表名时,简单的用set或者declare语句定义变量,然后直接作为sql的表名是不行的,mysql会把变量名当作表名。在其他的sql数据库中也是如此。mssql使用如下的语句解决:
PREPARE stmt_name FROM preparable_stmt; |
注:
A. PREPARE stmt_name FROM preparable_stmt;预定义一个语句,并将它赋给stmt_name,tmt_name是不区分大小写的。
B. 即使preparable_stmt语句中的?所代表的是一个字符串,你也不需要将?用引号包含起来。
C. 如果新的 PREPARE 语句使用了一个已存在的stmt_name,那么原有的将被立即释放!即使这个新的 PREPARE 语句因为错误而不能被正确执行。
D. PREPARE stmt_name的作用域是当前客户端连接会话可见。
E. 要释放一个预定义语句的资源,可以使用 DEALLOCATE PREPARE 句法。
F. EXECUTE stmt_name句法中,如果stmt_name不存在,将会引发一个错误。
G. 如果在终止客户端连接会话时,没有显式地调用 DEALLOCATE PREPARE 句法释放资源,服务器端会自己动释放它。
H. 在预定义语句中,CREATE TABLE, DELETE, DO, INSERT, REPLACE, SELECT, SET, UPDATE, 和大部分的 SHOW 句法被支持。
I. PREPARE 语句不可以用于自定义函数。
mysql> source trig.sql
Query OK, 0 rows affected, 1 warning (0.00 sec)
Query OK, 0 rows affected (0.04 sec)
Query OK, 1 row affected (0.16 sec)
Empty set (0.16 sec)
Empty set (0.16 sec)
CREATE DATABASE my_frist_db;
USE my_frist_db;
DROP TABLE IF EXISTS tab1;
CREATE TABLE tab1(
tab_id varchar(11),
provinceNameCn varchar(24)
);
DROP TABLE IF EXISTS tab2;
CREATE TABLE tab2(
tab_id varchar(11),
provinceNameCn varchar(24)
);
delimiter ||
DROP TRIGGER IF EXISTS t_afterinsert_on_tab1 ||
CREATE TRIGGER t_afterinsert_on_tab1
AFTER INSERT ON tab1
FOR EACH ROW
BEGIN
insert into tab2(tab_id,provinceNameCn) values(new.tab_id,new.provinceNameCn);
END||
delimiter ;
delimiter ||
DROP TRIGGER IF EXISTS t_afterdelete_on_tab1||
CREATE TRIGGER t_afterdelete_on_tab1
AFTER DELETE ON tab1
FOR EACH ROW
BEGIN
delete from tab2 where tab_id=old.tab_id;
END||
delimiter ;
delimiter ||
DROP TRIGGER IF EXISTS t_afterupdate_on_tab1||
CREATE TRIGGER t_afterupdate_on_tab1
AFTER UPDATE ON tab1
FOR EACH ROW
BEGIN
update tab2 set provinceNameCn=new.provinceNameCn where tab_id=new.tab_id;
#DELETE FROM tab2 WHERE tab_id='00';
#INSERT INTO tab2(tab_id,provinceNameCn) values(new.tab_id,new.provinceNameCn);
END||
delimiter ;
INSERT INTO tab1(tab_id,provinceNameCn) VALUES('0001','aaa');
INSERT INTO tab1(tab_id,provinceNameCn) VALUES('0002','aab');
INSERT INTO tab1(tab_id,provinceNameCn) VALUES('0003','aac');
SELECT * FROM tab1;
SELECT * FROM tab2;
UPDATE tab1 SET provinceNameCn='999' WHERE tab_id='0002';
SELECT * FROM tab1;
SELECT * FROM tab2;
DELETE FROM tab1 WHERE tab_id='0001';
SELECT * FROM tab1;
SELECT * FROM tab2;
mysql> source trig.sql
ERROR 1007 (HY000): Can't create database 'my_frist_db'; database exists
Database changed
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.04 sec)
Query OK, 0 rows affected (0.02 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected, 1 warning (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected, 1 warning (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected, 1 warning (0.01 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 1 row affected (0.05 sec)
Query OK, 1 row affected (0.00 sec)
Query OK, 1 row affected (0.00 sec)
+--------+----------------+
| tab_id | provinceNameCn |
+--------+----------------+
| 0001 | aaa |
| 0002 | aab |
| 0003 | aac |
+--------+----------------+
3 rows in set (0.00 sec)
+--------+----------------+
| tab_id | provinceNameCn |
+--------+----------------+
| 0001 | aaa |
| 0002 | aab |
| 0003 | aac |
+--------+----------------+
3 rows in set (0.00 sec)
Query OK, 1 row affected (0.10 sec)
Rows matched: 1 Changed: 1 Warnings: 0
+--------+----------------+
| tab_id | provinceNameCn |
+--------+----------------+
| 0001 | aaa |
| 0002 | 999 |
| 0003 | aac |
+--------+----------------+
3 rows in set (0.00 sec)
+--------+----------------+
| tab_id | provinceNameCn |
+--------+----------------+
| 0001 | aaa |
| 0002 | 999 |
| 0003 | aac |
+--------+----------------+
3 rows in set (0.00 sec)
Query OK, 1 row affected (0.01 sec)
+--------+----------------+
| tab_id | provinceNameCn |
+--------+----------------+
| 0002 | 999 |
| 0003 | aac |
+--------+----------------+
2 rows in set (0.00 sec)
+--------+----------------+
| tab_id | provinceNameCn |
+--------+----------------+
| 0002 | 999 |
| 0003 | aac |
+--------+----------------+
2 rows in set (0.00 sec)
下订单自动减少库存,更改订单的时候纠正库存,恶意订单时纠正数量
现有如下两张表
编号(id)名称(name)价格(price)库存(stock)
1 F16战斗机 10000 100
2 法拉利 800 70
3 航空母舰 5000 20
4 三栖交通工具 1000 50
DROP TABLE IF EXISTS shop;
CREATE TABLE shop(
id int(11),
name varchar(11),
price int(11),
stock int(11)
);
INSERT INTO shop(id,name,price,stock) values(1,'F16战斗机', 10000, 10);
INSERT INTO shop(id,name,price,stock) values(2,'法拉利', 800, 100);
INSERT INTO shop(id,name,price,stock) values(3,'航空母舰',5000, 11);
INSERT INTO shop(id,name,price,stock) values(4,'三栖交通工具', 1000, 30);
编号(id)商品编号(tid)购买数量(num)
DROP TABLE IF EXISTS commande;
CREATE TABLE commande(
tid int(11),
num int(11)
);
我们现在要买5架F16战斗机,下一个订单,需要做什么?
传统的做法:
insert into commande(tid,num) values(1,5);
update shop set stock = stock-5 where id = 1;
新的方式:
我们可以使用触发器,一触即发!!
地点:(表,table),
监视的事件:(insert,delete,update)
时间:(before/after)
触发的事件:(insert,delete,update)
需求:现在我们要购买10辆法拉利, 商品表里的触发器应该 这样写:
#商品表的触发器
delimiter ||
DROP TRIGGER IF EXISTS tg1_insert_shop ||
create trigger tg1_insert_shop
after -- 事件触发在 下订单之后
insert -- 监视插入事件
on commande -- 监视 order订单表
for each row
begin
update shop set stock=stock-new.num where id= new.tid; -- 注意这里是 old.id=new.tid
end ||
delimiter ;
执行在commande表的操作:
insert into commande(tid,num) values(2,10);
需求:先购买了10个辆法拉利,然后要把数量更改为5,写出触发器;
#商品表的触发器
delimiter ||
DROP TRIGGER IF EXISTS tg1_update_shop ||
create trigger tg1_update_shop
after
update
on commande
for each row
begin
update shop set stock = stock + old.num - new.num where id = new.tid; -- 监视更新,既不漏掉旧的,也不漏掉新的,计算差额
end ||
delimiter ;
测试:
update commande set num=8 where tid=2;
需求:若订单数量超过10的话,就认为是恶意订单,只让其购买10个。
Before:在监视事件发生之前触发的,触发事件要早于监视事件。
#商品表的触发器
delimiter $
create trigger tg_update_before
before
insert
on commande
for each row
begin
if new.num > 10 then
set new.num = 10;
end if;
update shop set stock = stock - new.num where id = new.tid;
end $
测试:
insert into commande(tid,num) values(2,22);
- view sourceprint?01 delimiter //
- create trigger InsertUser
- before insert on user
- for each row
- Begin
- insert into user_group(uid,gid) values(new.uid,'group4444444444');
- end;//
- delimiter ;
- delimiter //
- create trigger InsertUser
- before insert on user
- for each row
- Begin
- IF new.Type=2 then
- insert into user_group(uid,gid) values(new.uid,'group4444444444');
- else
- insert into user_group(uid,gid) values(new.uid,'group55555555555')
- END IF;
- end;//
- delimiter ;
- delimiter //
- create trigger InsertUser
- before insert on user
- for each row
- Begin
- IF new.type=1 then
- insert into user_group(uid,gid) values(new.uid,'578d3369633b47bd9c1fe8bf905cbfb1');
- END IF;
- IF new.type=2 then
- insert into user_group(uid,gid) values(new.uid,'387bcd57fc5a4c3c9de83ee210fef661');
- END IF;
- end;//
- delimiter ;
BEFORE和AFTER参数指定了触发执行的时间,在事件之前或是之后
FOR EACH ROW表示任何一条记录上的操作满足触发事件都会触发该触发器
代码如下:
tips:一般情况下,mysql默认是以 ; 作为结束执行语句,与触发器中需要的分行起冲突
为解决此问题可用DELIMITER,如:DELIMITER ||,可以将结束符号变成||
当触发器创建完成后,可以用DELIMITER ;来将结束符号变成;
mysql> DELIMITER ;
就会执行BEGIN和END中的语句,接着使用||结束
最后使用DELIMITER ; 将结束符号还原
tips:SHOW TRIGGERS语句无法查询指定的触发器
代码如下:
可以使用SELECT语句查询,如果触发器信息过多,最好通过TRIGGER_NAME字段指定查询
同时,也可以使用database.trig来指定某个数据库中的触发器
tips:如果不需要某个触发器时一定要将这个触发器删除,以免造成意外操作