当前位置: 首页 > news >正文

湖南网站建设推广优化php个人网站简洁

湖南网站建设推广优化,php个人网站简洁,没电脑可以建网站吗,数码产品网站模板C 数据库MySQL 学习笔记(3) - 数据库操作 视图操作 视图是从一个或多个表中导出来的表#xff0c;是一种虚拟存在的表。视图就像一个窗口#xff0c;通过这个窗口可以看到系统专门提供的数据#xff0c;这样用户可以不看整个数据库表中的数据#xff0c;而只关心对自己有…C 数据库MySQL 学习笔记(3) - 数据库操作 视图操作 视图是从一个或多个表中导出来的表是一种虚拟存在的表。视图就像一个窗口通过这个窗口可以看到系统专门提供的数据这样用户可以不看整个数据库表中的数据而只关心对自己有用的数据。视图可以使用户的操作更方便而且可以保障数据库系统的安全性。 为什么要使用视图 通过前面章节的知识可以发现数据库中关于数据的查询有时非常复杂例如表连接、子查询等这种查询会让程序员感到非常痛苦因为它的逻辑太复杂、编写语句比较多当这种查询需要重复使用时很难每次都编写正确从而降低了数据库的实用性。 在具体操作表之前有时候要求只能操作部分字段而不是全部字段。例如在学校里学生的智商测试结果一般都是保密的如果因为一时疏忽向查询中多写了关于“智商”的字段则会让学生的智商显示给所有能够查看该查询结果的人这时就需要限制使用者操作的字段。 为了提高复杂的SQL语句的复用性和表的操作的安全性MySQL数据库管理系统提供了视图特性。所谓视图本质上是一种虚拟表其内容与真实的表相似包含一系列带有名称的列和行数据。但是视图并不在数据库中以存储数据值的形式存在行和列数据来自定义视图的查询所引用的基本表并且在具体引用视图时动态生成。 视图使程序员只关心感兴趣的某些特定数据和他们所负责的特定任务。这样程序员只能看到视图中所定义的数据而不是视图所引用表中的数据从而提高数据库中数据的安全性。 创建视图 虽然视图可以被看成是一种虚拟表但是其物理上是不存在的即MySQL并没有专门的位置为视图存储数据。根据视图的概念可以发现其数据来源于查询语句因此创建视图的基本语法为 CREATE[OR REPLACE] VIEW viewname[columnlist] AS SELECT statement 其中CREATE表示创建新的视图REPLACE表示替换已经创建的视图viewname为视图的名称columnlist为属性列SELECT statement表示SELECT语句 注意! 创建视图需要登陆用户有相应的权限 查看权限方法 mysql use school; #选择数据库school mysql select user, Select_priv, Create_view_priv FROM mysql.user;#查询数据库用户创建和选择视图权限 在单表上创建视图 mysql use school; #选择数据库school mysql alter table student add privacy varchar(64);# 增加私隐列 mysql ;#查询数据库用户创建和选择视图权限 mysql CREATE VIEW view_student AS select id, class_id, name from student ;#为学生表创建视图 mysql desc view_student;#查看视图 mysql select * from view_student; #根据视图进行查询 在多表上创建视图 CREATE[OR REPLACE] VIEW viewname[columnlist] AS SELECT statement 其中CREATE表示创建新的视图REPLACE表示替换已经创建的视图viewname为视图的名称columnlist为属性列SELECT statement表示SELECT语句与单表上创建视图不同的是SELECT子句是涉及到多表的联合查询语句。 mysql use school; #选择数据库school mysql alter table student add privacy varchar(64);# 增加私隐列 mysql ;#查询数据库用户创建和选择视图权限 mysql CREATE VIEW view_student_class AS select student.id, student.name, class.name, class.teacher from class inner join student on class.id student.class_id;#为学生表创建视图 mysql desc view_student_class;#查看视图 mysql select * from view_student_class; #根据视图进行查询 查看视图 创建完视图后像表一样我们经常需要查看视图信息。在MySQL中有许多可以实现查看视图的语句如DESCRIBE、SHOW TABLES、SHOW CREATE VIEW。如果要使用这些语句首先要确保拥有SHOW VIEW的权限。本节将详细讲解查看视图的方法。 使用DESCRIBE | DESC语句查看视图基本信息 前面我们已经详细讲解过使用DESCRIBE语句来查看表的基本定义。因为视图也是一张表只是这张表比较特殊是一张虚拟的表所以同样可以使用DESCRIBE语句来查看视图的基本定义。DESCRIBE语句查看视图的语法如下 DESCRIBE | DESC viewname;在上述语句中参数viewname表示所要查看设计信息的视图名称。 使用SHOW TABLES语句查看视图基本信息 从MySQL 5.1版本开始执行SHOW TABLES语句时不仅会显示表的名字同时也会显示视图的名字。 下面演示通过SHOW TABLES语句查看数据库school中的视图和表的功能具体SQL语句如下执行结果如下图所示。 SHOW TABLES;使用show create view/table 语句查看视图创建信息 SHOW CREATE TABLE或VIEW viewname; 更新视图数据 更新视图是指通过视图来插入INSERT、更新UPDATE和删除DELETE表中的数据。因为视图实质是一个虚拟表其中没有数据通过视图更新时都是转换到基本表更新。更新视图时只能更新权限范围内的数据超出范围就不能更新了。 mysql use school; #选择数据库school mysql alter table student add privacy varchar(64);# 增加私隐列 mysql ;#查询数据库用户创建和选择视图权限 mysql CREATE VIEW view_student AS select id, class_id, name from student ;#为学生表创建视图 mysql desc view_student;#查看视图 mysql select * from view_student; #根据视图进行查询 mysql update view_student set name小花花 where name小花; #通过视图更新小花为小花花不能更新的情况 视图中包含SUM()、COUNT()、MAX()和MIN()等函数 视图中包含UNION、UNION ALL、DISTINCT、GROUP BY和HAVING等关键字 视图对应的表存在没有默认值的列而且该列没有包含在视图里 包含子查询的视图 其他特殊情况 修改视图 修改视图是指修改数据库中存在的视图当基本表的某些字段发生变化的时候可以通过修改视图来保持与基本表的一致性。ALTER语句来修改视图。 使用ALTER语句修改视图 ALTER VIEW viewname[columnlist] AS SELECT statement 这个语法中的所有关键字和参数除了alter 外其他都和创建视图是一样的因此不再赘述。 mysql use school; #选择数据库school mysql alter table student add privacy varchar(64);# 增加私隐列 mysql ;#查询数据库用户创建和选择视图权限 mysql ALTER VIEW view_student_class AS select student.id, student.name, class.name, class.id as class_id, class.teacher from class inner join student on class.id student.class_id;#为学生班级表视图增加 class_id 字段 mysql desc view_student_class;#查看视图 mysql select * from view_student_class; #根据视图进行查询 删除视图 删除视图是指删除数据库中已存在的视图。删除视图时只能删除视图的定义不会删除数据。 在MySQL中可使用DROP VIEW语句来删除视图但是用户必须拥有DROP权限。删除视图的语法如下 DROP VIEW viewname [viewname]在上述语句中参数viewname表示所要删除视图的名称可同时指定删除多个视图。 mysql use school; #选择数据库school mysql ;#查询数据库用户创建和选择视图权限 mysql CREATE VIEW view_student_class AS select student.id, student.name, class.name, class.id as class_id, class.teacher from class inner join student on class.id student.class_id;#为学生表创建视图 mysql drop view view_student_class;#删除视图 触发器 触发器TRIGGER是由事件来触发某个操作。这些事件包括INSERT语句、UPDATE语句和DELETE语句。当数据库系统执行这些事件时就会激活触发器执行相应的操作。MySQL从5.0.2版本开始支持触发器。 通过本章的学习我们将了解触发器的含义和作用、如何创建触发器、查看触发器和删除触发器的方法。同时可以了解各种事件的触发器的执行情况。 创建触发器 在MySQL中创建触发器通过SQL语句CREATE TRIGGER来实现其语法形式如下 CREATE trigger trigger_name BEFORE|AFTER trigger_EVENT ON TABLE_NAME FOR EACH ROW trigger_STMT 在上述语句中参数trigger_name表示要创建的触发器名 参数BEFORE和AFTER指定了触发器执行的时间前者在触发器事件之前执行触发器语句后者在触发器事件之后执行触发器语句 参数trigger_EVENT表示触发事件即触发器执行条件包含DELETE、INSERT和UPDATE语句参数TABLE_NAME表示触发事件的操作表名参数FOR EACH ROW表示任何一条记录上的操作满足触发事件都会触发该触发器 参数trigger_STMT表示激活触发器后被执行的语句。执行语句中如果要引用更新记录中的字段对于INSERT语句,只有NEW是合法的表示当前已插入的记录对于DELETE语句只有OLD才合法表示当前删除的记录而UPDATE语句可以和NEW更新后以及OLD更新前同时使用 **注意**不能创建具有相同名字的触发器。另外对于具有相同触发程序动作时间和事件的给定表不能有两个触发器。因此对于有经验的用户在创建触发器之前需要查看MySQL中是否已经存在该标识符的触发器和触发器的相关事件。 **【示例10-1】**执行SQL语句CREATE TRIGGER在数据库school中存在两个表对象学员表student和班级表 class创建触发器实现向学员表中插入记录时就会在插入之后更新班级表中的人数当我们删除某条学员的记录时就会在删除后更新班级表中的人数具体步骤如下 mysql use school; #选择数据库school mysql CREATE TABLE class ( id int NOT NULL AUTO_INCREMENT, name varchar(128) DEFAULT NULL, teacher varchar(64) DEFAULT NULL, count int DEFAULT 0, UNIQUE KEY id (id) ); #创建班级表 class mysql insert into class values(101, 萌新一班, Martin, 0),(102, 萌新二班, Rock, 0),(103, 萌新三班, Janny, 0); #创建成绩表 grade mysql CREATE TABLE student ( id int NOT NULL AUTO_INCREMENT UNIQUE, name varchar(64) DEFAULT NULL, class_id int DEFAULT NULL, sex enum(F,M) DEFAULT NULL ); mysql create trigger tri_insert_student after insert on student for each row update class set countcount1 where class.id NEW.class_id; #创建触发器新增学员班级人数增1mysql insert into student values(1,小花,101,M),(2,小红,102, F),(3,小军,102,F),(4,小白,101,F); #插入多条记录 mysql select count from class ; #查询class 表人数 mysql create trigger tri_delete_student after delete on student for each row update class set countcount-1 where id OLD.class_id; #创建触发器删除学员班级人数减1 触发器包含多条执行语句 CREATE trigger trigger_name BEFORE|AFTER trigger_EVENT ON TABLE_NAME FOR EACH ROW BEGIN trigger_STMT END 在上述语句中比“只有一条执行语句的触发器”语法多出来两个关键字BEGIN和END在这两个关键字之间是所要执行的多个执行语句的内容执行语句之间用分号隔开。 在MySQL中一般情况下用“;”符号作为语句的结束符号可是在创建触发器时需要用到“;”符号作为执行语句的结束符号。为了解决该问题可以使用关键字DELIMITER语句。例如“DELIMITER ”可以将结束符号设置成“$$”。 mysql use school; #选择数据库school mysql create table grade(id int UNIQUE AUTO_INCREMENT, math tinyint unsigned, chinese tinyint unsigned, english tinyint unsigned); #创建成绩表 grade mysql insert into grade values(1, 80, 87, 91),(2, 72, 64, 89),(3, 54, 69, 87),(4, 78, 79, 89); #插入多条记录 mysql DELIMITER $$ mysql create trigger tri_delete_student after delete on student for each row BEGIN Delete from grade where id OLD.id; #删除成绩表中的记录 update class set countcount-1 where id OLD.class_id; #更新班级表中的记录 END; $$ DELIMITER ; 查看触发器 SHOW TRIGGERS语句查看触发器 那么如何查看MySQL软件中已经存在的触发器呢在MySQL软件中查看已经存在的触发器通过SQL语句SHOW TRIGGERS来实现其语法形式如下执行上面的SQL语句执行结果如图9-10所示。 SHOW TRIGGERS ; 通过图9-10的执行结果可以发现执行完“SHOW TRIGGERS”语句后会显示一个列表在该列表中会显示出所有触发器的信息。其中参数Trigger表示触发器的名称参数Event表示触发器的激发事件参数Table表示触发器对象触发事件所操作的表参数Statement表示触发器激活时所执行的语句参数Timing表示触发器所执行的时间。 查看系统表triggers实现查看触发器 在MySQL中在系统数据库information_schema中存在一个存储所有触发器信息的系统表triggers因此查询该表格的记录也可以实现查看触发器功能。系统表triggers的表结构 mysql use information_schema; #选择数据库information_schema mysql select * from triggers; mysql select * from triggers where trigger_name’tri_delete_student’; #查询系统表triggers中的触发器 触发器的删除 在MySQL软件中可以通过DROP TRIGGER语句或通过工具来删除触发器。 在MySQL中删除触发器可以通过SQL语句DROP TRIGGER来实现其语法形式如下 DROP TRIGGER trigger_name; 在上述语句中参数trigger_name表示所要删除的触发器名称。 存储过程和函数 存储过程和函数是在数据库中定义的一些SQL语句的集合然后直接调用这些存储过程和函数来执行已经定义好的SQL语句。存储过程和函数可以避免开发人员重复编写相同的SQL语句。而且存储过程和函数是在MySQL服务器中存储和执行的可以减少客户器端和服务端的数据传输。 创建存储过程 创建存储过程和函数是指将经常使用的一组SQL语句组合在一起并将这些SQL语句当作一个整体存储在MySQL服务器中。存储程序可以分为存储过程和函数。在MySQL中创建存储过程使用的语句CREATE PROCEDURE。其语法形式如下 CREATE PROCEDURE procedure_name([proc_param[,…]]) routine_body 在上述语句中参数procedure_name表示所要创建的存储过程名字参数proc_param表示存储过程的参数参数routine_body表示存储过程的SQL语句代码可以用BEGIN…END来标志SQL语句的开始和结束。 提示: 在具体创建存储过程时存储过程名不能与已经存在的存储过程名重名实战中推荐存储过程名命名为procedure_xxx或者proc_xxx。 proc_param中每个参数的语法形式如下 [IN|OUT|INOUT] param_name type在上述语句中每个参数由三部分组成分别为输入/输出类型、参数名和参数类型。其中输入/输出类型有三种类型分别为IN表示输入类型、OUT表示输出类型、INOUT表示输入/输出类型。param_name表示参数名type表示参数类型可以是MySQL软件所支持的任意一个数据类型。 mysql use school; #选择数据库school mysql DELIMITER $$ mysql create PROCEDURE proc_delete_student (IN sid int ) BEGIN declare cid int ; #定义变量cid Select class_id into cid from student where id sid; #通过查询语句设置变量 delete from grade where id sid; #删除成绩表中的记录 delete from student where id sid; #删除学生表中的记录 update class set countcount-1 where id cid; #更新班级表中的记录 END; $$ DELIMITER ; mysql call proc_delete_student(2); #调用存储过程 在存储过程中使用变量 在存储过程和函数中可以定义和使用变量。用户可以使用关键字DECLARE来定义变量然后为变量赋值。这些变量的作用范围是在BEGIN…END程序段中。 定义变量 在MySQL中可以使用DECLARE关键字来定义变量。定义变量的基本语法如下 DECLARE var_name[,…] type [DEFAULT value] 其中关键字DECLARE是用来声明变量的参数var_name是变量的名称可以同时定义多个变量参数type用来指定变量的类型DEFAULT value子句将变量默认值设置为value没有使用DEFAULT子句时默认值为NULL。 定义变量cid数据类型为INT型默认值为10代码如下 DECLARE cid INT DEFAULT 10; 为变量赋值 在MySQL中可以使用关键字SET来为变量赋值SET语句的基本语法如下 SET var_nameexpr[,var_nameexpr]…其中关键字SET用来为变量赋值参数var_name是变量的名称参数expr是赋值表达式。一个SET语句可以同时为多个变量赋值各个变量的赋值语句之间用逗号隔开。 例如将变量tmp_id赋值为88代码如下 SET tmp_id 88; 在MySQL中还可以使用SELECT…INTO语句为变量赋值。其基本语法如下 SELECT col_name[,…] INTO var_name[,…] FROM table_name WHERE condition 其中参数col_name表示查询的字段名称参数var_name是变量的名称参数table_name指表的名称参数condition指查询条件。 从表student中查询id为4的记录将该记录的id值赋给变量tmp_id代码如下 mysql use school; #选择数据库school mysql drop PROCEDURE if exists query_student_class_info; mysql DELIMITER $$ mysql create procedure query_student_class_info (IN sid int, OUT cname varchar(128), OUT ccount int) BEGIN declare tmp_name varchar(128);declare tmp_count int;declare tmp_cid int;select class_id into tmp_cid from student where id sid; select name, count into tmp_name, tmp_count from class where id tmp_cid;set cname tmp_name, ccount tmp_count;END; $$ DELIMITER ; mysql call query_student_class_info(4, name, count); #调用存储过程 mysql select name, count; 光标的使用 查询语句可能查询出多条记录在存储过程和函数中使用光标来逐条读取查询结果集中的记录。有些书上将光标称为游标。光标的使用包括声明光标、打开光标、使用光标和关闭光标。光标必须声明在处理程序之前并且声明在变量和条件之后 声明光标 在MySQL中可以使用DECLARE关键字来声明光标其基本语法如下 DECLARE cursor_name CURSOR FOR select_statement; 其中参数cursor_name表示光标的名称参数select_statement表示SELECT语句的内容。 **【示例11-2】**下面声明一个名为cur_student的光标代码如下 mysql use school; #选择数据库school mysql DELIMITER $$ mysql create procedure query_student (IN sid int, OUT cname varchar(128), OUT class_id int ) BEGIN DECLARE cur_student CURSOR FOR SELECT name, class_id FROM student; END; $$ DELIMITER ; 在上面的示例中光标的名称为cur_studentSELECT语句部分是从表student中查询出字段name和class_id的值。 打开光标 在MySQL中使用关键字OPEN来打开光标其基本语法如下 OPEN cursor_name;其中参数cursor_name表示光标的名称。 下面代码打开一个名为cur_student的光标代码如下 OPEN cur_student;使用光标 在MySQL中使用关键字FETCH来使用光标其基本语法如下 FETCH cursor_name INTO var_name[,var_name…];其中参数cursor_name表示光标的名称参数var_name表示将光标中的SELECT语句查询出来的信息存入该参数中。var_name必须在声明光标之前就定义好。 **【示例11-3】**下面声明一个名为cur_student的光标代码如下 mysql use school; #选择数据库school mysql DELIMITER $$ mysql create procedure query_student (IN sid int, OUT cname varchar(128), OUT cid int) BEGIN declare tmp_name varchar(128); #必须定义在声明光标之前 declare tmp_cid int; declare done int default 0; declare cur_student CURSOR FOR SELECT name, class_id FROM student where id sid; declare continue handler for not found set done 1; #将结束标志绑定到游标上 open cur_student; select done; fetch cur_student into tmp_name, tmp_cid; select done; select tmp_name, tmp_cid; #打印从光标中获取到的值 close cur_student; set cname tmp_name, cid tmp_cid; END; mysql $$ mysql DELIMITER ; 关闭光标 在MySQL中使用关键字CLOSE来关闭光标其基本语法如下 CLOSE cursor_name;其中参数cursor_name表示光标的名称。 例如: 关闭一个名为cur_student的光标代码如下 CLOSE cur_student;在上面的示例中关闭了这个名称为cur_student的光标。关闭了之后就不能使用FETCH来使用光标了。提示 如果存储过程或函数中执行了SELECT语句并且SELECT语句会查询出多条记录这种情况最好使用光标来逐条读取记录光标必须在处理程序之前且在变量和条件之后声明而且光标使用完毕后一定要关闭。 流程控制的使用 在存储过程和函数中可以使用流程控制来控制语句的执行。在MySQL中可以使用IF语句、CASE语句、LOOP语句、LEAVE语句、ITERATE语句、REPEAT语句和WHILE语句来进行流程控制 if语句 IF语句用来进行条件判断。根据条件执行不同的语句。其语法的基本形式如下: IF search_condition THEN statement_list [ELSEIF search_condition THEN statement_list] ... [ELSE statement_list] END IF 参数search_condition表示条件判断语句参数statement_list表示不同条件的执行语句。 **[示例11-4]**下面是一个IF语句的示例代码如下 IF age20 THEN SET count1count11; ELSEIF age20 THEN count2count21;ELSE count3count31; END IF; 该示例根据age与20的大小关系来执行不同的SET语句。如果age值大于20将count1的值加1如果age值等于20就将count2的值加1其他情况将count3的值加1。IF语句都需要使用END IF来结束。 mysql use school; #选择数据库school mysql DELIMITER $$ mysql create procedure proc_test_if (IN input int, OUT output int)beginif input20 then set inputinput1;elseif input20 then set inputinput2;else set input input3;end if;set output input;end; mysql $$ mysql DELIMITER ; CASE语句 CASE语句可实现比IF语句更复杂的条件判断其语法的基本形式如下: CASE case_value WHEN when_value THEN statement_list [ WHEN when_value THEN statement_list ] [ELSE statement_list] END CASE 其中参数case_value表示条件判断的变量参数when_value表示变量的取值参数statement_list表示不同when_value值的执行语句 **[示例11-5]**下面是一个CASE语句的示例。代码如下 CASE level WHEN 20 THEN SET attack attack 5; WHEN 30 THEN SET attack attack 10; WHEN 40 THEN SET attack attack 15; ELSE SET attack attack 1; END CASE 当级别level值为20时attack值加5当级别level值为30时attack值加10当级别level值为40时attack值加15否则attack 1。CASE语句使用END CASE结束。 LOOP 语句 LOOP语句可以使某些特定的语句重复执行实现一个简单的循环。LOOP语句本身没有停止循环只有遇到LEAVE语句等才能停止循环。LOOP语句的语句形式如下 [begin_label:] LOOP statement_list END LOOP [end_label] 其中参数begin_label和参数end_label分别表示循环开始和结束的标志这两个标志必须相同而且都可以省略参数statement_list表示需要循坏执行的语句。 【示例11-6】下面是一个LOOP语句的示例代码如下 add_num:LOOP SET count count 1; END LOOP add_num; 该示例循环执行count加1的操作。因为没有跳出循环的语句这个循环成了一个死循环。LOOP循环都以END LOOP结束。 LEAVE语句 LEAVE语句主要用于跳出循环控制其语法形式如下 LEAVE label 其中参数label表示循环的标志。 【示例11-7】下面是一个LEAVE语句的示例。代码如下 add_num: LOOP SET countcount 1; Select count; IF count 100 THEN LEAVE add_num; END IF; END LOOP add_num; 该示例循环执行count值加1的操作。当count的值等于100时LEAVE语句跳出循环。 ITERATE 语句 ITERATE语句也是用来跳出循环的语句但是ITERATE语句是跳出本次循环然后直接进入下一次循环ITERATE语句的语法形式如下 ITERATE label 其中参数label表示循环的标志。 【示例11-8】下面是一个ITERATE语句的示例。代码如下 add_num1:LOOP Set count count 1 IF count100 THEN LEAVE add_num1 ELSE IF MOD(count, 3) 0 thenITERATE add_num1; Select * from student; END LOOP add_num1; 该示例循环执行count加1的操作count的值为100时结束循环。如果count的值能够整除3就跳出本次循环不再执行下面的SELECT语句。 注意 LEAVE语句和ITERATE语句都用来跳出循环语句但是两者的功能是不一样的。LEAVE语句是跳出整个循环然后执行循环后面的程序和C break 相似。ITERATE语句是跳出本次循环然后进入下一次循环,和C continue 相似。使用这两个语句时一定要区分清楚。 REPEAT 语句 REPEAT语句是有条件控制的循环语句。当满足特定条件时就会跳出循环语句。REPEAT语句的基本语法形式如下 [begin_label:] REPEAT statement_list; UNTIL search_condition END REPEAT [end_label] 其中参数statement_list表示循环的执行语句参数search_condition表示结束循环的条件满足该条件时循环结束。 【示例11-9】下面是一个REPEAT语句的示例。代码如下 REPEAT SET countcount1; UNTIL count100 END REPEAT; 该示例循环执行count加1的操作count值为100时结束循环。REPEAT循环都用END REPEAT结束。 WHILE 语句 WHILE语句也是有条件控制的循环语句但WHILE语句和REPEAT语句是不一样的。WHILE语句是当满足条件时执行循环内的语句。WHILE语句的基本语法形式如下 [begin_label:] WHILE search_condition DO Statement_list END WHILE [end_label] 其中参数statement_condition表示循环执行的条件满足该条件时循环执行参数statement_list表示循环的执行语句。 【示例11-10】下面是一个WHILE语句的示例。代码如下 WHILE count100 DO SET count count 1; END WHILE; 流程控制综合运用 **【示例11-11】**循环访问光标操作访问光标中的所有记录,代码如下 mysql use school; #选择数据库school mysql DELIMITER $$ mysql create procedure query_all_students (IN sid int, OUT cname varchar(128), OUT cid int) BEGIN declare tmp_name varchar(128); #必须定义在声明光标之前 declare tmp_cid int; declare done int default 0; declare cur_student CURSOR FOR SELECT name, class_id FROM student ; declare continue handler for not found set done 1; #将结束标志绑定到游标上 open cur_student; read_loop:LOOP #循环读取 fetch cur_student into tmp_name, tmp_cid; IF done1 then Leave read_loop; END IF; select tmp_name, tmp_cid; #打印从光标中获取到的值 END LOOP read_loop; close cur_student; set cname tmp_name, cid tmp_cid; END; mysql $$ mysql DELIMITER ; 【示例11-12】在学生表中插入一条记录并返回记录的自增长id mysql use school; #选择数据库school mysql DELIMITER $$ mysql create procedure fetch_insert_student_id (IN p_name varchar(128), in p_class_id int, IN p_sex char(1), OUT rid int) BEGIN Insert into student (name, class_id, sex) values(p_name, p_class_id, p_sex); select last_insert_id() as rid; END; mysql $$ mysql DELIMITER ; 查看存储过程 存储过程创建以后用户可以通过SHOW STATUS语句来查看存储过程的状态也可以通过SHOW CREATE语句来查看存储过程的定义。用户也可以通过查询information_schema数据库下的Routines表来查看存储过程的信息。本节将详细讲解查看存储过程的状态与定义的方法。 SHOW STATUS语句查看存储过程 在MySQL中可以通过SHOW STATUS语句。其基本语法形式如下 SHOW PROCEDURE STATUS [ like ‘pattern’ ] ; 其中参数PROCEDURE表示查询存储过程参数LIKE pattern’用来匹配存储过程的名称。 图11-13的执行结果显示了存储过程的创建时间、修改时间和字符集等信息。 使用SHOW CREATE语句查看存储过程的定义 在MySQL中可以通过SHOW CREATE语句查看存储过程的状态语法形式如下 SHOW CREATE PROCEDURE proc_name 其中参数PROCEDURE表示查询存储过程参数proc_name表示存储过程的名称。 —【示例11-14】查询名为proc_delete_student的存储过程的状态代码如下执行结果如下图所示。 SHOW CREATE PROCEDURE proc_delete_student \G从information_schema.Routine表中查看存储过程的信息 存储过程和函数的信息存储在information_schema数据库下的Routines表中。可以通过查询该表的记录来查询存储过程和函数的信息。其基本语法形式如下 SELECT * FROM information_schema.RoutinesWhere ROUTINE_NAME ‘proc_name’;其中字段ROUTINE_NAME是Routines 存储存储过程和函数的列名称参数proc_name表示存储过程或函数的名称。 —【示例11-15】下面从Routines表中查询名为proc_delete_student的存储过程信息具体SQL代码如下执行结果如下图所示。 select routine_definition from information_schema.Routines where routine_nameproc_delete_student; 存储过程的删除 在MySQL中删除存储过程通过SQL语句DROP完成 DROP PROCEDURE proc_name; 在上述语句中关键字DROP PROCEDURE用来表示实现删除存储过程参数proc_name表示所要删除的存储过程名称。 —【示例11-16】执行SQL语句DROP PROCEDURE删除存储过程对象proc_delete_student具体步骤如下 DROP PROCEDURE proc_delete_student;数据库的存储引擎 MySQL中存在多种存储引擎的概念。简而言之存储引擎就是指表的类型。在具体开发时为了提高MySQL数据库管理系统的使用效率和灵活性可以根据实际需要来选择存储引擎。因为存储引擎指定了表的类型即如何存储和索引数据、是否支持事务等同时存储引擎也决定了表在计算机中的存储方式。 MySQL支持的存储引擎 用户在选择存储引擎之前首先需要确定数据库管理系统支持哪些存储引擎。在MySQL数据库管理系统通过SHOW ENGINES来查看支持的存储引擎语法如下 SHOW ENGINES; 在MySQL中执行SHOW ENGINES的结果如下图12-1所示。 在创建表时若没有指定存储引擎表的存储引擎将为默认的存储引擎。如果需要操作默认存储引擎首先需要查看默认存储引擎。可以使用下面的SQL语句来查询默认存储引擎执行结果如图12-2所示。 SHOW VARIABLES LIKE default_storage_engine; 接下来简单介绍开发中常用的几种常见的存储引擎。 InnoDB存储引擎 InnoDB是MySQL数据库的一种存储引擎。InnoDB给MySQL的表提供了事务、回滚、崩溃修复能力和多版本并发控制的事务安全。MySQL从3.23.34a开始就包含InnoDB存储引擎。InnoDB是MySQL第一个提供外键约束的表引擎而且InnoDB对事务处理的能力也是MySQL对其他存储引擎所无法与之比拟的。 MySQL 5.6版本之后除系统数据库之外默认的存储引擎由MyISAM改为InnoDBMySQL 8.0版本在原先的基础上将系统数据库的存储引擎也改为了InnoDB。 InnoDB存储引擎中支持自动增长列AUTO_INCREMENT。自动增长列的值不能为空且值必须唯一。MySQL中规定自增列必须为主键。在插入值时如果自动增长列不输入值那么插入的值为自动增长后的值如果输入的值为0或空NULL那么插入的值也为自动增长后的值如果插入某个确定的值且该值在前面没有出现过那么可以直接插入。 InnoDB存储引擎中支持外键FOREIGN KEY。外键所在的表为子表外键所依赖的表为父表。父表中被子表外键关联的字段必须为主键。当删除、更新父表的某条信息时子表也必须有相应的改变。 InnoDB存储引擎的优势在于提供了良好的事务管理、崩溃修复能力和并发控制缺点是其读写效率稍差占用的数据空间相对比较大。 MyISAM存储引擎 MyISAM存储引擎是MySQL中常见的存储引擎曾是MySQL的默认存储引擎。MyISAM存储引擎是基于ISAM存储引擎发展起来的。MyISAM增加了很多有用的扩展。 MyISAM存储引擎的表存储成3个文件。文件的名字与表名相同或站名包括frm、MYD和MYI。其中frm为扩展名的文件存储表的结构MYD为扩展名的文件存储数据是MYData的缩写MYI为扩展名的文件存储索引是MYIndex的缩写。 基于MyISAM存储引擎的表支持3种存储格式包括静态型、动态型和压缩型。其中静态型为MyISAM存储引擎的默认存储格式其字段是固定长度的动态型包含变长字段记录的长度不是固定的压缩型需要使用myiampack工具创建占用的磁盘空间较小。 MyISAM存储引擎的优势在于占用空间小处理速度快缺点是不支持事务的完整性和并发性。 MEMORY 存储引擎 MEMORY存储引擎是MySQL中一类特殊存储引擎。其使用存储在内存中的内容来创建表而且所有数据也放在内存中。这些特性都与InnoDB存储引擎、MyISAM存储引擎不同。 每个基于MEMORY存储引擎的表实际对应一个磁盘文件该文件的文件名与表名相同类型为frm类型该文件中只存储表的结构而其数据文件都是存储在内存中的。这样有利于数据的快速处理提供整个表的处理效率。值得注意的是服务器需要有足够的内存来维持MEMORY存储引擎的表的使用。如果不需要使用了可以释放这些内存甚至可以删除不需要的表。 MEMORY存储引擎默认使用哈希HASH索引。其速度要比使用B型树BTREE索引快。如果读者希望使用B型树索引可以在创建索引时选择使用。 MEMORY表的大小是受到限制的。表的大小主要取决于两个参数分别是max_rows和max_heap_table_size。其中max_rows可以在创建表时指定max_heap_table_size的大小默认为16MB可以按需要进行扩大。因此其存在于内存中的特性这类表的处理速度非常快。但是其数据易丢失生命周期短。基于这个缺陷选择MEMORY存储引擎时需要特别小心。 选择存储引擎 在具体使用MySQL数据库管理系统时选择一个合适的存储引擎是非常复杂的问题。因为每种存储引擎都有自己的特性、优势和应用场合所以不能随便选择存储引擎。为了能够正确地选择存储引擎必须掌握各种存储引擎的特性。 下面从存储引擎的事务安全、存储限制、空间使用、内存使用、插入数据的速度和对外键的支持等角度来比较InnoDB、MyISAM和MEMORY如表12-3所示。 C/C访问MySQL数据库 VS2019配置 第一步打开mysql的安装目录默认安装目录如下C:\Program Files\MySQL\MySQL Server 8.0确认 lib 目录和include 目录是否存在。 第二步打开VS2019新建一个空工程,控制台应用程序即可注意解决方案平台选择 X64 第三步右击工程名打开属性页 第四步打开VC目录在包含目录中将mysql安装文件中的include文件的路径添加到这里 **第五步**打开VC目录在库目录中将mysql文件中的lib文件路径添加进来 第六步在属性页的链接器中点击“输入”将mysql安装文件夹中lib目录下的libmysql.lib文件加到“附加依赖项”中注意这里直接把libmysql.lib这个依赖名加进去即可不要加路径。 第七步把mysql安装目录里的lib\libmysql.dll复制到c:\windows\system32下 第八步编译如下代码启动mysql 80, 将代码中连接数据库的用户名和密码改成自己的设定顺利获取到student 表中的结果即表示连接成功 #include stdio.h #include mysql.h // mysql文件 int main(void) {MYSQL mysql; //数据库句柄MYSQL_RES* res; //查询结果集MYSQL_ROW row; //记录结构体//初始化数据库mysql_init(mysql);//设置字符编码mysql_options(mysql, MYSQL_SET_CHARSET_NAME, gbk);//连接数据库if (mysql_real_connect(mysql, 127.0.0.1, root, 123456qweQWE, school, 3306, NULL, 0) NULL) {printf(错误原因 %s\n, mysql_error(mysql));printf(连接失败\n);exit(-1);}//查询数据int ret mysql_query(mysql, select * from student;);printf(ret: %d\n, ret);//获取结果集res mysql_store_result(mysql);//给ROW赋值判断ROW是否为空不为空就打印数据。while (row mysql_fetch_row(res)){printf(%s , row[0]); //打印IDprintf(%s , row[1]); //打印姓名printf(%s , row[2]); //打印班级printf(%s \n, row[3]);//打印性别}//释放结果集mysql_free_result(res);//关闭数据库mysql_close(mysql);system(pause);return 0; }实战项目 数据库表设计 在这里插入图片描述 mysql create database box_man; #创建数据库box_man mysql mysql create table users( #创建用户表 id int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT, username varchar(64) NOT NULL UNIQUE, password varchar(32) NOT NULL , level_id int default 1 ); mysql create table levels( #创建关卡表 id int NOT NULL PRIMARY KEY default 1, name varchar(64) NOT NULL UNIQUE, map_row int NOT NULL, map_column int NOT NULL, map_data varchar(4096) NOT NULL, next_level_id int default 0 ); mysql insert into users values(1000, martin, md5(123456qweQWE), 1); mysql insert into levels values(1, 牛刀小试, 9, 12, 0,0,0,0,0,0,0,0,0,0,0,0|0,1,0,1,1,1,1,1,1,1,0,0|0,1,4,1,0,2,1,0,2,1,0,0|0,1,0,1,0,1,0,0,1,1,1,0|0,1,0,2, 0,1,1,4,1,1,1,0|0,1,1,1,0,3,1,1,1,4,1,0|0,1,2,1,1,4,1,1,1,1,1,0|0,1,0,0,1,0,1,1,0,0,1,0|0,0,0,0,0,0,0,0,0,0, 0,0,0); 推箱子游戏 - 代码优化 登录验证 database.cpp #include database.h #include mysql.h #include stdio.h#define DB_NAME box_man #define DB_HOST 127.0.0.1 #define DB_PORT 3306 #define DB_USER root #define DB_USER_PASSWD 123456qweQWEstatic bool connect_db(MYSQL mysql);/****************************************************功能通过用户名和密码从数据库获取用户信息*输入* user - 用户信息结构体**返回值* 获取成功返回true, 失败false***************************************************/ bool fetch_user_info(userinfo user) {MYSQL mysql;MYSQL_RES* res; //查询结果集MYSQL_ROW row; //记录结构体char sql[256];bool ret false;//1.连接到数据库if (connect_db(mysql) false) {return false;}//2.根据用户名和密码获取用户信息(id, level_id)snprintf(sql, 256, select id, level_id from users where username%s and passwordmd5(%s);, user.username.c_str(), user.passwd.c_str());ret mysql_query(mysql, sql); //成功返回0if (ret) {printf(数据库查询出错%s 错误原因 %s\n, sql, mysql_error(mysql));mysql_close(mysql);return false;}//3.获取结果res mysql_store_result(mysql);row mysql_fetch_row(res);if (row NULL) {//没有查找到记录mysql_free_result(res);mysql_close(mysql);return false;}user.id atoi(row[0]);user.level_id atoi(row[1]);printf(userid: %d level_id: %d\n, user.id, user.level_id); //打印ID//4.返回结果//释放结果集mysql_free_result(res);//关闭数据库mysql_close(mysql);return true; }bool connect_db(MYSQL mysql) {//1.初始化数据库句柄mysql_init(mysql);//2.设置字符编码mysql_options(mysql, MYSQL_SET_CHARSET_NAME, gbk);//3.连接数据库if (mysql_real_connect(mysql, DB_HOST, DB_USER, DB_USER_PASSWD, DB_NAME, DB_PORT, NULL, 0) NULL) {printf(数据库连接出错 错误原因 %s\n, mysql_error(mysql));return false;}return true; } database.h #pragma once#include stringusing namespace std;//用户信息 typedef struct _userinfo{int id; //用户idstring username; //用户名string passwd; //密码int level_id; //关卡id }userinfo;bool fetch_user_info(userinfo user);boxman.cpp bool login(userinfo user) {int times 0;bool ret false;do{cout 请输入用户名: ;cin user.username;cout 请输入密码: ;cin user.passwd;//返回 bool ,成功返回true ,失败返回false .ret fetch_user_info(user);times;if (times MAX_RETRY_TIMES) {break;}if (ret false) {cout 登陆失败请重新输入! endl;}} while (!ret);return ret; }获取关卡 //database.h typedef struct _levelinfo {int id; //关卡的idstring name; //关卡的名字int map_row; //地图总行数int map_column; //地图总列数string map_data; //二维地图数据int next_level; //下一关卡的id }levelinfo;bool fetch_level_info(levelinfo level, int level_id);//database.cpp /****************************************************功能根据关卡id 获取完整的关卡信息(如: 地图下一关等)*输入* level - 保存关卡信息的结构体变量* level_id - 要获取详细关卡信息的关卡id*返回值* 获取成功返回true, 失败false***************************************************/ bool fetch_level_info(levelinfo level, int level_id) {MYSQL mysql;MYSQL_RES* res; //查询结果集MYSQL_ROW row; //记录结构体char sql[256];bool ret false;//1.连接到数据库if (connect_db(mysql) false) {return false;}//2.根据关卡id查询数据库获取关卡地图信息snprintf(sql, 256, select name, map_row, map_column, map_data, next_level_id from levels where id%d;, level_id);ret mysql_query(mysql, sql); //成功返回0if (ret) {printf(数据库查询出错%s 错误原因 %s\n, sql, mysql_error(mysql));mysql_close(mysql);return false;}//3.获取结果res mysql_store_result(mysql);row mysql_fetch_row(res);if (row NULL) {//没有查找到记录mysql_free_result(res);mysql_close(mysql);return false;}level.id level_id;level.name row[0];level.map_row atoi(row[1]);level.map_column atoi(row[2]);level.map_data row[3];level.next_level atoi(row[5]);if(debug) printf(level id: %d name: %s map row: %d map column: %d map data: %s next level: %d\n, level.id, level.name.c_str(), level.map_row, level.map_column, level.map_data.c_str(), level.next_level);//释放结果集mysql_free_result(res);//关闭数据库mysql_close(mysql);return true; }地图适配 //database.h bool transform_map_db2array(levelinfo level, int map[LINE][COLUMN]);//database.cpp bool transform_map_db2array(levelinfo level, int map[LINE][COLUMN]) {if (level.map_row LINE || level.map_column COLUMN) {printf(地图超大请重新设置!\n);return false;}if (level.map_data.length() 1) {printf(地图数据有误请重新设置!\n);return false;}int start 0, end 0;int row 0, column 0;do {end level.map_data.find(|, start);if (end 0) {end level.map_data.length();}if (start end) break;string line level.map_data.substr(start, end - start);printf(get line: %s\n, line.c_str());//对行地图数据进行解析char *next_token NULL;char* item strtok_s((char*)line.c_str(), ,, next_token);column 0;while (item column level.map_column) {printf(%s , item);map[row][column] atoi(item);column;item strtok_s(NULL, ,, next_token);}if (column level.map_column) {printf(地图数据解析出错,终止!\n);return false;}printf(\n);row;if (row level.map_row) {break;}start end 1;} while (1 1);if (row level.map_row) {printf(地图行数少于设定, %d(need: %d),终止!\n, row, level.map_row);return false;}return true; }//boxman.cpp//把数据库中的地图数据转换到map 中ret transform_map_db2array(level, map); 下一关跳转 //database.h bool update_user_level(userinfo user, int next_level_id);//database.cpp bool update_user_level(userinfo user, int next_level_id) {MYSQL mysql;MYSQL_RES* res; //查询结果集MYSQL_ROW row; //记录结构体char sql[256];bool ret false;//1.连接到数据库if (connect_db(mysql) false) {return false;}//2.根据用户id 更新下一关的level_idsnprintf(sql, 256, update users set level_id %d where id%d;, next_level_id, user.id);ret mysql_query(mysql, sql);if (ret) {printf(数据库更新出错%s 错误原因 %s\n, sql, mysql_error(mysql));mysql_close(mysql);return false;}//关闭数据库mysql_close(mysql);return true; }//boxman.cpp//...............前面省略N行代码....................void gameNextScene(IMAGE* bg) {putimage(0, 0, bg);settextcolor(WHITE);RECT rec { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };settextstyle(20, 0, _T(宋体));drawtext(_T(恭喜您~ \n此关挑战成功任意键跳转到下一关), rec, DT_CENTER | DT_VCENTER | DT_SINGLELINE);::system(pause);cleardevice(); }//...............中间省略N行代码....................if (isGameOver()) {if (level.next_level 1) {gameOverScene(bg_img);quit true;break;}gameNextScene(bg_img);//更新用户下一关的关卡信息if (update_user_level(user, level.next_level)) {user.level_id level.next_level;}break;//quit true; }完整代码 boxman.cpp #include graphics.h #include conio.h #include iostream #include string #include database.husing namespace std;#define SCREEN_WIDTH 800 #define SCREEN_HEIGHT 650 #define PROPS_RATIO 50 #define MAX_RETRY_TIMES 4#define START_X 100 #define START_Y 100#define KEY_UP w #define KEY_DOWN s #define KEY_LEFT a #define KEY_RIGHT d #define KEY_QUIT q #define isValid(pos) pos.x0 pos.xLINE pos.y0 pos.y COLUMN /*int map[9][12] {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},{0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0},{0, 1, 4, 1, 0, 2, 1, 0, 2, 1, 0, 0},{0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0},{0, 1, 0, 2, 0, 1, 1, 4, 1, 1, 1, 0},{0, 1, 1, 1, 0, 3, 1, 1, 1, 4, 1, 0},{0, 1, 2, 1, 1, 4, 1, 1, 1, 1, 1, 0},{0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0},{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, };*/int map[LINE][COLUMN] { 0 };enum _PROPS {WALL,FLOOR,BOX_DES,MAN,BOX,HIT,ALL };IMAGE props_img[ALL];enum _DIRECTION {UP,DOWN,LEFT,RIGHT };struct _POS {int x;int y; };typedef enum _DIRECTION DIRECTION; typedef enum _PROPS PROPS; typedef struct _POS POS; POS man; bool step_on_DES false; bool end_flag false;void printWinScreen(IMAGE * bg) {putimage(0, 0, bg);settextcolor(WHITE);RECT rec { 0,0,SCREEN_WIDTH,SCREEN_HEIGHT };settextstyle(20, 0, _T(Arial));drawtext(_T(You win!!! Press any key to move to the next stage!!!), rec, DT_CENTER | DT_VCENTER | DT_SINGLELINE);system(pause);cleardevice();}void printOverScreen(IMAGE* bg) {putimage(0, 0, bg);settextcolor(WHITE);RECT rec { 0,0,SCREEN_WIDTH,SCREEN_HEIGHT };settextstyle(20, 0, _T(Arial));drawtext(_T(You win!!!You finish all the stage for the game!!!), rec, DT_CENTER | DT_VCENTER | DT_SINGLELINE);system(pause); }bool winDefine() {for(int i0; iLINE; i)for (int j 0; j COLUMN; j){if (map[i][j] BOX_DES){return false;}}return true; }void update_map_position(POS position, PROPS props) {map[position.x][position.y] props;putimage(START_X (position.y * PROPS_RATIO), START_Y (position.x * PROPS_RATIO), props_img[map[position.x][position.y]]);}void map_update(DIRECTION direction) {POS next_pos, next_next_pos;next_pos man;next_next_pos man;if (direction UP){next_pos.x man.x - 1;next_next_pos.x man.x - 2;}else if (direction DOWN){next_pos.x man.x 1;next_next_pos.x man.x 2;}else if (direction LEFT){next_pos.y man.y - 1;next_next_pos.y man.y - 2;}else if (direction RIGHT){next_pos.y man.y 1;next_next_pos.y man.y 2;}if (map[next_pos.x][next_pos.y] FLOOR || map[next_pos.x][next_pos.y] BOX_DES){if (isValid(next_pos) map[next_pos.x][next_pos.y] FLOOR){update_map_position(next_pos, MAN);if (step_on_DES false){update_map_position(man, FLOOR);}else{update_map_position(man, BOX_DES);step_on_DES false;}man next_pos;}else if (isValid(next_pos) map[next_pos.x][next_pos.y] BOX_DES){update_map_position(next_pos, MAN);update_map_position(man, FLOOR);step_on_DES true;man next_pos;}}if (isValid(next_pos) map[next_pos.x][next_pos.y] BOX){if (isValid(next_next_pos) map[next_next_pos.x][next_next_pos.y] FLOOR){update_map_position(next_next_pos, BOX);update_map_position(next_pos, MAN);if (step_on_DES false){update_map_position(man, FLOOR);}else{update_map_position(man, BOX_DES);step_on_DES false;}man next_pos;}else if (isValid(next_next_pos) map[next_next_pos.x][next_next_pos.y] BOX_DES){update_map_position(next_next_pos, HIT);update_map_position(next_pos, MAN);update_map_position(man, FLOOR);man next_pos;}}if (isValid(next_pos) map[next_pos.x][next_pos.y] HIT){if (isValid(next_next_pos) map[next_next_pos.x][next_next_pos.y] FLOOR){update_map_position(next_next_pos, BOX);update_map_position(next_pos, MAN);step_on_DES true;update_map_position(man, FLOOR);man next_pos;}}}bool login(userinfo user) {int times 0;bool ret false;do {cout Please enter the username: endl;cin user.username;cout Please enter the password: endl;cin user.password;ret fetch_user_info(user);times;//Return as bool type to determine whether can connect to the userdatabase.if (times MAX_RETRY_TIMES){break;}if (ret false){cout Failed to login, please retry again. endl;}} while (!ret);return ret; }void init_game_graphic(IMAGE bg_img) {initgraph(SCREEN_WIDTH, SCREEN_HEIGHT);loadimage(bg_img, _T(blackground.bmp), SCREEN_WIDTH, SCREEN_HEIGHT, true);putimage(0, 0, bg_img);loadimage(props_img[BOX], _T(box.bmp), PROPS_RATIO, PROPS_RATIO, true);loadimage(props_img[FLOOR], _T(floor.bmp), PROPS_RATIO, PROPS_RATIO, true);loadimage(props_img[MAN], _T(man.bmp), PROPS_RATIO, PROPS_RATIO, true);loadimage(props_img[BOX_DES], _T(des.bmp), PROPS_RATIO, PROPS_RATIO, true);loadimage(props_img[WALL], _T(wall_right.bmp), PROPS_RATIO, PROPS_RATIO, true);loadimage(props_img[HIT], _T(box.bmp), PROPS_RATIO, PROPS_RATIO, true); }int main() {//User verification userinfo user;levelinfo level;bool ret false;IMAGE bg_img;if (!login(user)){cout Failed to login... Please retry again. endl;system(pause);exit(-1);}else{cout Welcome, user.username. You are current at the stage: user.level_id. Enjoy your game : ) endl;system(pause);}//Initialized the stage level for the gameinit_game_graphic(bg_img);do{//Get the stage information from MYSQLret fetch_level_info(level, user.level_id);if (!ret){cout Failed to get the stage information, please retry endl;system(pause);exit(-1);}//Convert the map information that query from MYSQL to MAPret transform_map_db2array(level, map);if (!ret){cout Failed to get the stage information, please retry endl;system(pause);exit(-1);}char keyboard_input;for (int i 0; i level.map_row; i){for (int j 0; j level.map_column; j){if (map[i][j] MAN){man.x i;man.y j;}putimage(START_X (j * PROPS_RATIO), START_Y (i * PROPS_RATIO), props_img[map[i][j]]);}}do{if (_kbhit){keyboard_input _getch();if (keyboard_input KEY_UP){map_update(UP);}else if (keyboard_input KEY_DOWN){map_update(DOWN);}else if (keyboard_input KEY_LEFT){map_update(LEFT);}else if (keyboard_input KEY_RIGHT){map_update(RIGHT);}else if (keyboard_input KEY_QUIT){end_flag true;}}if (winDefine()){if (level.next_level 1){printOverScreen(bg_img);end_flag true;break;}//Update the next stage informationprintWinScreen(bg_img);if (update_user_level(user, level.next_level)){user.level_id level.next_level;}break;//end_flag true}} while (end_flag false);} while (end_flag false);system(pause);return 0;}database.h #pragma once #include iostream #include string#define COLUMN 48 #define LINE 48 using namespace std;typedef struct _userinfo {int id;string username;string password;int level_id; }userinfo;typedef struct _levelinfo {int id;string name;int map_row; //Total Map row numberint map_column; //Total Map column numberstring map_data;int next_level; }levelinfo;bool fetch_user_info(userinfo user); bool fetch_level_info(levelinfo level,int level_id); bool transform_map_db2array(levelinfo level,int map[LINE][COLUMN]); bool update_user_level(userinfo user, int next_level_id);database.cpp #include database.h #include mysql.h #include stdio.h#define DB_NAME box_man #define DB_HOST 127.0.0.1 #define DB_PORT 3306 #define DB_USER root #define DB_USER_PASSD 303771Chew!static int debug 1;static bool connect_db(MYSQL mysql);/*************************************** *Function: Use username and password to get the user info from MYSQL *Input: * user - User information structure * * Return: * sucessfully get info true, if failed return false; ***************************************/ bool fetch_user_info(userinfo user) {MYSQL mysql;MYSQL_RES* res; //MYSQL return resultMYSQL_ROW row; //MYSQL return result in rowchar sql[256];bool ret false;//1. Connect to the databaseif (connect_db(mysql) false){return false;}//2. According to the username and password, get the userinfo(id, level_id)snprintf(sql, 256, select id, level_id from users where username %s and password md5(%s);, user.username.c_str(), user.password.c_str());//cout sql endl;ret mysql_query(mysql, sql); // This port if success will return 0;if (ret){cout Database query have issue. Reason: mysql_error(mysql) endl;mysql_close(mysql);return false;}//3. Get the resultres mysql_store_result(mysql);row mysql_fetch_row(res);if (row NULL){mysql_free_result(res);mysql_close(mysql);return false;}user.id atoi(row[0]);user.level_id atoi(row[1]);if (debug) cout User id: user.id \t User level id: user.level_id endl;//4. Return resultmysql_free_result(res);mysql_close(mysql);return true;}bool connect_db(MYSQL mysql) {//1. Initialized the database MYSQLmysql_init(mysql);//2. Setting character encodingmysql_options(mysql, MYSQL_SET_CHARSET_NAME, latin1);//3. Connect to the MYSQL databaseif (mysql_real_connect(mysql, DB_HOST, DB_USER, DB_USER_PASSD, DB_NAME, DB_PORT, NULL, 0) NULL){cout Connect failed... Reason: mysql_error(mysql);return false;}return true; }/*************************************** *Function: According to the stage id get the completed information for the stage. (Map, next stage...) *Input: * level - level information structure * level_id - the level id that we want to get the information * Return: * sucessfully get info true, if failed return false; ***************************************/ bool fetch_level_info(levelinfo level, int level_id) {MYSQL mysql;MYSQL_RES* res; //MYSQL return resultMYSQL_ROW row; //MYSQL return result in rowchar sql[256];bool ret false;//1. Connect to the databaseif (connect_db(mysql) false){return false;}//2.According with the stage id to search for the information of the mapsnprintf(sql, 256, select name, map_row, map_column, map_data, next_level_id from levels where id%d;, level_id);ret mysql_query(mysql, sql); // This port if success will return 0;if (ret){cout Database query have issue. Reason: mysql_error(mysql) endl;mysql_close(mysql);return false;}//3. Get the resultres mysql_store_result(mysql);row mysql_fetch_row(res);if (row NULL){mysql_free_result(res);mysql_close(mysql);return false;}level.id level_id;level.name row[0];level.map_row atoi(row[1]);level.map_column atoi(row[2]);level.map_data row[3];level.next_level atoi(row[4]);if (debug) cout The level id is: level.id The level name is: level.name The level map row is: level.map_row The level map column is: level.map_column The map data is: level.map_data The level next level is: level.next_level endl;//4. Return resultmysql_free_result(res);mysql_close(mysql);return true; }bool transform_map_db2array(levelinfo level, int map[LINE][COLUMN]) {if(level.map_row LINE || level.map_column COLUMN){cout The map is too big! endl;return false;}if (level.map_data.length() 1){cout The map is abnormal, please reset for the map! endl;return false;}int start 0;int end 0;int row 0;int column 0;do {end level.map_data.find(|, start);if (end 0){end level.map_data.length();}if (start end) break;string line level.map_data.substr(start, end - start);cout line endl;//Seperate the map information from all the ,char* next_token NULL;char* item strtok_s((char*)line.c_str(), ,, next_token);column 0;while (item column level.map_column){cout item ;map[row][column] atoi(item);column;item strtok_s(NULL, ,, next_token);}if (column level.map_column){cout The map information abnormal. Will terminate the program endl;return false;}cout endl;row;if (row level.map_row){break;}start end 1;} while (1);if (row level.map_row){cout The map row is less than the setup. Terminated the program now endl;return false;}return true; }bool update_user_level(userinfo user, int next_level_id) {MYSQL mysql;MYSQL_RES* res; //MYSQL return resultMYSQL_ROW row; //MYSQL return result in rowchar sql[256];bool ret false;//1. Connect to the databaseif (connect_db(mysql) false){return false;}//2. According to the user id, update the next level_idsnprintf(sql, 256, update users set level_id %d where id%d;, next_level_id, user.id);ret mysql_query(mysql, sql);if (ret){cout Database query have issue. Reason: mysql_error(mysql) endl;mysql_close(mysql);return false;}mysql_close(mysql);return true; }实战 - 棋牌游戏数据库开发 (概念)
http://www.zqtcl.cn/news/403665/

相关文章:

  • 做淘客网站需要营业执照吗制作网站公
  • 手机网站开发的目的鲁班设计远程工作
  • 宿迁网站建设要多少钱高密市住房和城乡建设局网站
  • 咸阳网站建设公司哪家好wordpress访客ip记录
  • 厦门建设银行网站那个网站做效果图电脑配置
  • 人才网站建设医院网站建设的好处
  • 房屋装修网站模板html5做网站
  • 网站建设需要的硬件网站建设知名公司排名
  • 绥化网站建设私自搭建vps犯法吗
  • 建设专业网站哪家比较好小程序源码是什么意思
  • 网站设计一般包括什么给公司做网站数据分析
  • 网站根目录在哪里1024cctvcom戊人影祝
  • wordpress转发微信南宁seo企业优化
  • 红旗渠建设集团网站昭通网络推广
  • 海陵区建设局网站计算机网站建设考试试卷
  • 佛山做网站3lue网站开发招标网
  • 粘贴以下代码到网站首页代码的与标签之间渭南软件开发
  • 企业网站建设必要性上海网站建设报价表
  • 陕西省建设厅申报网站一个主体如何添加网站
  • 做网站业务员提成几个点wordpress 地图导航代码
  • 软件下载网站排行住房和城乡建设部办公厅网站
  • 贵阳网站建设需要多少钱百度资源搜索平台
  • 做安全防护信息的网站wordpress初始密码
  • 广东企业网站seo哪里好微信公众号怎么创建文章
  • 建行网站登录不了wordpress好主题
  • 南屏网站建设湖北省建设厅的网站
  • 有没有做花卉种子的网站啊正规网站建设服务
  • 长沙网站建设公司招聘那个建设网站好
  • 网站开发视频下载网站优化关键词排名自己怎么做
  • 网站建设 流程咸宁网站建设哪家好