博客
电影
宝箱
友链
关于
<
sass之scss心得
CSS变形matrix与动画cubic-bezier
>
SQL快速运用指南
作者:
Cifer
类别: 技术
时间:2016-12-20 11:51:17
字数:17492
版权所有,未经允许,请勿转载,谢谢合作~
#### 前言 SQL( Structured Query Language )是一种关系式数据库管理系统的标准语言,同时它需要数据库作为载体使用,为了达到“快速运用”的效果,这里不对数据库系统展开,只是讲几个概念与实例,使得简单的SQL可以复制即用。 #### 增删改查 记得在学生时期,老师给[西法](http://www.boatsky.com "太空船博客")上的第一个关于数据库的课程竟然是“数据库原理”,一言不合,就开讲范式、存储引擎以及性能瓶颈……巴拉巴拉,对于当时SQL都不会写的我们,真是一脸懵逼。 增加记录 ```sql INSERT INTO table_name (column1, column2,...) VALUES (value1, value2,....); ``` 删除记录 ```sql DELETE FROM table_name WHERE column = value; ``` 修改记录 ```sql UPDATE table_name SET column1 = value1 WHERE column2 = value2; ``` 查找记录 ```sql SELECT * FROM table_name WHRER column = value; ``` 是不是很简单?那了解一下常见概念 #### 了解概念 SQL,1974年开始发展,而1986年才形成统一规范,由RDBMS(Relational Database Management System)实现,RDBMS代表性产品有Oracle、MySQL、SQL Server、db2等,与之对应的还有非关系型数据库NoSQL,常用的如MongoDB、Redis等 。 SQL主要有几种分类: 数据定义语言 DDL (Data Definition Language),如CREATE, ALTER and DROP 数据查询语言 DQL (Data Query Language),如SELECT, SHOW and HELP 数据操作语言 DML (Data Manipulation Language),如INSERT, UPDATE and DELETE 数据控制语言 DCL (Data Control language),如GRANT and REVOKE 不同的数据库支持不同的存储引擎(表类型),常见的有: InnoDB :优势事务管理、并发控制等。劣势占空间、读写略慢。 MylSAM:优势占空间小、读写较快。劣势并发性差,完整性弱。 MEMORY:优势读写极快。劣势因数据都数据库类似于内存的地方,数据量不能太大,且安全性不高。 各有千秋,适者为王。 范式是符合某一种级别的关系模式的集合,可能理解为规范,是显而易见,就算某人不了解范式,他设计多数的数据库也会按照范式的规则来。 第一范式(1NF):列中的完整性,独立性,即每列都是不可分割基本数据,且不能出现重复的列 第二范式(2NF):在1NF基础上,每条记录应该有一个唯一标识它的属性,且其他列不能只依赖于它的一部分,应该完全函数依赖。 第三范式(3NF):在2NF基础上,一个表的不能包括其他表已经包含的非主属性。 BC范式(BCNF):在3NF基础上,不可传递函数依赖,比如不可关键字决定关键字。 第四范式(4NF):在BCNF基础上,不允许有非平凡且非函数依赖的多值依赖。 第五范式(5NF):在4NF基础上,每一个连接依赖均由R的候选码所隐含。 不知有没注意到,上面写法都是大写?其实SQL的关键字不区分大小写,但为了便于区分关键字与非关键字,一般关键字大写。同理,为了阅读,建议: t_ 命名表 v_ 命名视图 p_ 命名存储过程 不同的数据库在SQL上写法会有所差异,本文主要是用MySQL为例。MySQL是瑞典人1995开发,是市场占用率稳占前列,并且是开源的!MySQL默认的存储引擎便是InnoDB。 #### 学校实例 为了减少业务的理解,以大家熟悉的学校为实例。 本例中,使用的id是guid,即一个格式类似于849194cc-c68c-11e6-83a9-64006a45c8a3的36位全局标识符,它的可能性为6*10^49,就算有10000亿条数据,id重复的概率也只有6*10^37,可以认为不可重复。它与自增id(auto_increment)做主键,便于并发以及多库情况,并且对外id不像数字一样可猜测。缺点是存储较大,不易记忆。在速度上,据说相差并不明显。本文把4个-去除.只需32位。 显示所有数据库: ```sql SHOW DATABASES; ``` 创建“学校”数据库: ```sql CREATE DATABASES school; ``` 使用该数据库: ```sql USE school; ``` 查看该数据库存储引擎: ```sql SHOW ENGINES; ``` 查看该数据库的所有表: ```sql SHOW TABLES; ``` 创建一个学生测试表: ```sql CREATE TABLE t_student_test ( id CHAR(32) PRIMARY KEY, code INT UNIQUE, name VARCHAR(30), en_name VARCHAR(30), id_number VARCHAR(18), describle VARCHAR(4000), birthday DATE, gender INT, start_time DATE, create_time DATETIME, status INT DEFAULT 1 ); ``` 显示该表结构: ```sql DESC t_student_test; ``` 创建索引: ```sql CREATE INDEX index_id_number ON t_student_test; ``` 索引是用来给查询增速,给读写减速的。而主键是一种特殊的索引。(索引包括普通索引,唯一性索引,全文索引,单引索引,多列索引,空间索引等) 修改该表结构(分别是增加deletetime行,更改许名字deletetime为delete_time,删除行delete_time) ```sql ALTER TABLE t_student_test ADD deletetime DATETIME; ALTER TABLE t_student_test CHANGE deletetime delete_time DATETIME; ALTER TABLE t_student_test DROP delete_time; ``` 给该表添加一条学生记录: ```sql INSERT INTO t_student_test (id,code,name,birthday,gender,start_time,create_time) VALUES ('xsde0287c2b411e6b5d764006a45c8yf',201600001,'赵一芳',STR_TO_DATE('1998/12/15','%Y/%m/%d'),0,STR_TO_DATE('2016/09/01','%Y/%m/%d'),STR_TO_DATE('2016/12/15 10:35:24','%Y/%m/%d %H:%i:%s') ); ``` 查询该表所有记录所有字段,最多1000条: ```sql SELECT * FROM t_student_test limit 1000; ``` 更新该表中学生学号为201600001的的生日: ```sql UPDATE t_student_test SET birthday = STR_TO_DATE('1999/10/20','%Y/%m/%d') WHERE code = '201600001'; ``` 删除该表: ```sql DROP TABLE t_student_test; ``` 正式环境中,我们一般不会在像上面一样在物理上把数据删除,而是在表里定义一个标置位,比如这里是status 默认是1,如果删除则改为0 为了有相关的测试数据,这里分别创建以下表及插入相关数据 添加《学生》表及数据: ```sql DROP TABLE IF EXISTS t_student; CREATE TABLE t_student( id CHAR(32) PRIMARY KEY, code INT UNIQUE, name VARCHAR(30), en_name VARCHAR(30), id_number VARCHAR(18), describle VARCHAR(4000), birthday DATE, gender INT, start_time DATE, create_time DATETIME, status INT DEFAULT 1 ); INSERT INTO t_student (id,code,name,birthday,gender,start_time,create_time) VALUES ('xsde0287c2b411e6b5d764006a45c8yf',201600001,'赵一芳',STR_TO_DATE('1998/12/15','%Y/%m/%d'),0,STR_TO_DATE('2016/09/01','%Y/%m/%d'),STR_TO_DATE('2016/12/15 10:35:24','%Y/%m/%d %H:%i:%s') ); INSERT INTO t_student (id,code,name,birthday,gender,start_time,create_time) VALUES ('xs2f4b7ec2b411e6b5d764006a45c8eq',201600002,'钱二奇',STR_TO_DATE('1997/11/16','%Y/%m/%d'),1,STR_TO_DATE('2016/09/01','%Y/%m/%d'),now()); INSERT INTO t_student (id,code,name,birthday,gender,start_time,create_time) VALUES ('xs2f4b7ec2b411e6b5d764006a45c8sw',201600003,'孙三文',STR_TO_DATE('1997/11/16','%Y/%m/%d'),0,STR_TO_DATE('2016/09/01','%Y/%m/%d'),now()); INSERT INTO t_student (id,code,name,birthday,gender,start_time,create_time) VALUES ('xs2f4b7ec2b411e6b5d764006a45c8sh',201600004,'李四辉',STR_TO_DATE('1997/11/16','%Y/%m/%d'),1,STR_TO_DATE('2016/09/01','%Y/%m/%d'),now()); INSERT INTO t_student (id,code,name,birthday,gender,start_time,create_time) VALUES ('xs2f4b7ec2b411e6b5d764006a45c8wm',201600005,'陈五明',STR_TO_DATE('1999/02/16','%Y/%m/%d'),1,STR_TO_DATE('2016/09/01','%Y/%m/%d'),now()); INSERT INTO t_student (id,code,name,birthday,gender,start_time,create_time) VALUES ('xs2f4b7ec2b411e6b5d764006a45c8ly',201600006,'刘六亦',STR_TO_DATE('2000/02/16','%Y/%m/%d'),1,STR_TO_DATE('2016/09/01','%Y/%m/%d'),now()); INSERT INTO t_student (id,code,name,birthday,gender,start_time,create_time) VALUES ('xs2f4b7ec2b411e6b5d764006a45c8qx',201600007,'王七兮',STR_TO_DATE('2000/02/16','%Y/%m/%d'),0,STR_TO_DATE('2016/09/01','%Y/%m/%d'),now()); ``` 添加《专业》表及数据: ```sql DROP TABLE IF EXISTS t_profession; CREATE TABLE t_profession( id CHAR(32) PRIMARY KEY, name VARCHAR(30), describle VARCHAR(4000), start_time DATE, create_time DATETIME, status INT DEFAULT 1 ); INSERT INTO t_profession (id,name,start_time,create_time) VALUES ('zy560e87c2b411e6b5d764006a45c8js','计算机',STR_TO_DATE('2000/09/01','%Y/%m/%d'),now()); INSERT INTO t_profession (id,name,start_time,create_time) VALUES ('zyf53607c2b411e6b5d764006a45c8jj','经济学',STR_TO_DATE('1988/09/01','%Y/%m/%d'),now()); ``` 添加《班级》表及数据: ```sql DROP TABLE IF EXISTS t_class; CREATE TABLE t_class( id CHAR(32) PRIMARY KEY, name VARCHAR(30), profession_id CHAR(32), describle VARCHAR(4000), start_time DATE, create_time DATETIME, status INT DEFAULT 1 ); INSERT INTO t_class (id,name,profession_id,start_time,create_time) VALUES ('bj560e87c2b411e6b5d764006a45cjs1','计算机161班','zy560e87c2b411e6b5d764006a45c8js',STR_TO_DATE('2016/09/01','%Y/%m/%d'),now()); INSERT INTO t_class (id,name,profession_id,start_time,create_time) VALUES ('bjf53607c2b411e6b5d764006a45cjj1','经济学161班','zyf53607c2b411e6b5d764006a45c8jj',STR_TO_DATE('2016/09/01','%Y/%m/%d'),now()); INSERT INTO t_class (id,name,profession_id,start_time,create_time) VALUES ('bjf53607c2b411e6b5d764006a45cjj2','经济学162班','zyf53607c2b411e6b5d764006a45c8jj',STR_TO_DATE('2016/09/01','%Y/%m/%d'),now()); INSERT INTO t_class (id,name,profession_id,start_time,create_time) VALUES ('bj560e87c2b411e6b5d764006a45cjs2','计算机162班','zy560e87c2b411e6b5d764006a45c8js',STR_TO_DATE('2016/09/01','%Y/%m/%d'),now()); INSERT INTO t_class (id,name,profession_id,start_time,create_time) VALUES ('bj560e87c2b411e6b5d764006a45cjs3','计算机163班','zy560e87c2b411e6b5d764006a45c8js',STR_TO_DATE('2016/09/01','%Y/%m/%d'),now()); ``` 添加《学生-班级关系》表及数据,因为学生与班级,是多对多的关系,所以需要一个关系表: ```sql DROP TABLE IF EXISTS t_student_class CREATE TABLE t_student_class( student_id CHAR(32), class_id CHAR(32), status INT DEFAULT 1 ); INSERT INTO t_student_class (student_id,class_id) VALUES ('xsde0287c2b411e6b5d764006a45c8yf','bj560e87c2b411e6b5d764006a45cjs1'); INSERT INTO t_student_class (student_id,class_id) VALUES ('xs2f4b7ec2b411e6b5d764006a45c8eq','bj560e87c2b411e6b5d764006a45cjs1'); INSERT INTO t_student_class (student_id,class_id) VALUES ('xs2f4b7ec2b411e6b5d764006a45c8sw','bjf53607c2b411e6b5d764006a45cjj1'); INSERT INTO t_student_class (student_id,class_id) VALUES ('xs2f4b7ec2b411e6b5d764006a45c8sh','bjf53607c2b411e6b5d764006a45cjj2'); INSERT INTO t_student_class (student_id,class_id) VALUES ('xs2f4b7ec2b411e6b5d764006a45c8wm','bj560e87c2b411e6b5d764006a45cjs2'); INSERT INTO t_student_class (student_id,class_id) VALUES ('xs2f4b7ec2b411e6b5d764006a45c8qx','bj560e87c2b411e6b5d764006a45cjs3'); INSERT INTO t_student_class (student_id,class_id) VALUES ('xsde0287c2b411e6b5d764006a45c8yf','bjf53607c2b411e6b5d764006a45cjj2'); ``` 添加《学科》表及数据: ```sql DROP TABLE IF EXISTS t_subject; CREATE TABLE t_subject( id CHAR(32) PRIMARY KEY, code VARCHAR(30) UNIQUE, name VARCHAR(30), describle VARCHAR(2000), start_time DATE, create_time DATETIME, status INT DEFAULT 1 ); INSERT INTO t_subject (id,code,name,describle,start_time,create_time) VALUES ('xk7a90e9c29d11e6b5d764006a45c8jj','economics','经济学基础','讲述经济学规律',STR_TO_DATE('1988/12/16','%Y/%m/%d'),now()); INSERT INTO t_subject (id,code,name,describle,start_time,create_time) VALUES ('xk131b29c29d11e6b5d764006a45c8sj','database','数据库原理','讲述数据库的原理及使用',STR_TO_DATE('2000/02/18','%Y/%m/%d'),now()); ``` 添加《课程》表及数据: ```sql DROP TABLE IF EXISTS t_course; CREATE TABLE t_course( id CHAR(32) PRIMARY KEY, code VARCHAR(30), name VARCHAR(30), describle VARCHAR(2000), subject_id CHAR(32), class_id CHAR(32), tearcher_id CHAR(32), start_time DATE, create_time DATETIME, status INT DEFAULT 1 ); INSERT INTO t_course (id,code,name,subject_id,tearcher_id,start_time,create_time) VALUES ('kc32fe0ac2b811e6b5d764006a45c8a3','database2016','数据库原理(李老师)','xk131b29c29d11e6b5d764006a45c8sj','ls52b0dbc2b511e6b5d764006a45c8li',STR_TO_DATE('2016/09/01','%Y/%m/%d'), now()); INSERT INTO t_course (id,code,name,subject_id,tearcher_id,start_time,create_time) VALUES ('kc32fe0ac2b811e6b5d764006a45c8a4','database2016','经济学基础(张老师)','xk7a90e9c29d11e6b5d764006a45c8jj','lsa559f9c2b511e6b5d764006a45c8zh',STR_TO_DATE('2016/09/01','%Y/%m/%d'), now()); ``` 添加《教师》表及数据: ```sql DROP TABLE IF EXISTS t_teacher; CREATE TABLE t_teacher( id CHAR(32) PRIMARY KEY, code INT UNIQUE, name VARCHAR(30), describle VARCHAR(4000), birthday DATE, gender INT, create_time DATETIME, status INT DEFAULT 1 ); INSERT INTO t_teacher (id,code,name,birthday,gender,create_time) VALUES ('ls52b0dbc2b511e6b5d764006a45c8li',20160001,'李老师',STR_TO_DATE('1997/11/16','%Y/%m/%d'),1, now()); INSERT INTO t_teacher (id,code,name,birthday,gender,create_time) VALUES ('lsa559f9c2b511e6b5d764006a45c8zh',19910001,'张老师',STR_TO_DATE('1998/12/16','%Y/%m/%d'),1, now()); ``` 添加《分数》表及数据: ```sql DROP TABLE IF EXISTS t_score; CREATE TABLE t_score( id CHAR(32) PRIMARY KEY, student_id CHAR(32), course_id CHAR(32), score INT, start_time DATE, create_time DATETIME, status INT DEFAULT 1 ); ``` (字数太多,一些数据放到一个sql上<http://res.boatsky.com/demo/sql/school_demo.sql>) 五个小问题: 教师与课程是多对多的,为什么这里没有加上教师-课程关联表? 为什么不需要学生-专业多对多关联表? 为什么不需要学生-课程多对多关联表? 在实际中,我们一般关注你学科的分数,但这里分数表里,是学生与课程对应关系,而不是学生与学科对应关系? 上述表设计中,有什么不合理之处? 基于上述数据,写一些简单实例SQL了: ##### 查询2016年上学期的所有学生 ```sql SELECT * FROM t_student WHERE start_time BETWEEN '2016/09/01' AND '2016/12/31'; SELECT * FROM t_student WHERE start_time BETWEEN STR_TO_DATE('2016/09/01','%Y/%m/%d') AND STR_TO_DATE('2016/12/31','%Y/%m/%d'); SELECT * FROM t_student WHERE start_time >= '2016/09/01' AND start_time <= '2016/12/31'; ``` ##### 使用正则,查询2016级所有学生 ```sql SELECT * FROM t_student WHERE code REGEXP '^2016'; ``` ##### 查询学号为201600001的班级id ```sql SELECT t_class.id FROM t_student,t_class,t_student_class WHERE t_student.code = '201600002' AND t_student.id = t_student_class.student_id AND t_student_class.class_id = t_class.id; ``` ##### 查询所有学生及他们的班级 ```sql SELECT t_class.name,t_student.name,t_student.code FROM t_student,t_class,t_student_class WHERE t_student.id = t_student_class.student_id AND t_student_class.class_id = t_class.id; ``` 相当于INNER JOIN,相当于左右表匹配 ```sql SELECT t_class.name AS class_name,t_student.name,t_student.code FROM t_student INNER JOIN t_student_class ON t_student.id = t_student_class.student_id INNER JOIN t_class ON t_student_class.class_id = t_class.id; ``` 相关LEFT JOIN,表示左表显示所有行,无论是否右表匹配 ```sql SELECT t_class.name AS class_name,t_student.name,t_student.code FROM t_student LEFT JOIN t_student_class ON t_student.id = t_student_class.student_id LEFT JOIN t_class ON t_student_class.class_id = t_class.id; ``` 相关RIGHT JOIN,表示右表显示所有行,无论左表是否匹配 ```sql SELECT t_class.name AS class_name,t_student.name,t_student.code FROM t_student RIGHT JOIN t_student_class ON t_student.id = t_student_class.student_id RIGHT JOIN t_class ON t_student_class.class_id = t_class.id; ``` 但是在MySQL中,没有FULL JOIN,所以如果要做类似的处理,可以用UNION ```sql SELECT t_class.name AS class_name,t_student.name,t_student.code FROM t_student LEFT JOIN t_student_class ON t_student.id = t_student_class.student_id LEFT JOIN t_class ON t_student_class.class_id = t_class.id UNION SELECT t_class.name AS class_name,t_student.name,t_student.code FROM t_student RIGHT JOIN t_student_class ON t_student.id = t_student_class.student_id RIGHT JOIN t_class ON t_student_class.class_id = t_class.id; ``` ##### 查询学号为201600001的所有同班同学,同时去重 ```sql SELECT DISTINCT t_student.code,t_student.name FROM t_student,t_class,t_student_class WHERE t_student.id = t_student_class.student_id AND t_student_class.class_id = t_class.id AND t_class.id IN ( SELECT t_class.id FROM t_student,t_class,t_student_class WHERE t_student.code = '201600002' AND t_student.id = t_student_class.student_id AND t_student_class.class_id = t_class.id ); ``` ##### 查询2016级上学期学科《数据库原理》各个同学的成绩及班级,并按学号从小到大排序 ```sql SELECT t_student.name,t_student.code,t_class.name AS class_name,t_course.name AS course_name,t_student.gender,t_score.score FROM t_student,t_course,t_score,t_class,t_student_class WHERE t_course.subject_id = 'xk131b29c29d11e6b5d764006a45c8sj' AND t_course.start_time >= STR_TO_DATE('2016/09/01','%Y/%m/%d') AND t_course.start_time <= STR_TO_DATE('2016/12/31','%Y/%m/%d') AND t_score.course_id = t_course.id AND t_score.student_id = t_student.id AND t_class.id = t_student_class.class_id AND t_student.id = t_student_class.student_id ORDER BY t_score.score DESC ``` 看到结果,会发现数据重复了,因为“赵一芳”这位同学同时在“计算机161班”及“经济学162班”,这班级又是多对多关联表,当显示成绩的时候,无法确定她是哪个班级的,只能在每个班都显示一次,所以得注意不能查询无法确定的行,如果我们不考虑她的班级,则改成: ```sql SELECT DISTINCT t_student.name,t_student.code,t_course.name AS course_name,t_student.gender,t_score.score FROM t_student,t_course,t_score WHERE t_course.subject_id = 'xk131b29c29d11e6b5d764006a45c8sj' AND t_course.start_time >= STR_TO_DATE('2016/09/01','%Y/%m/%d') AND t_course.start_time <= STR_TO_DATE('2016/12/31','%Y/%m/%d') AND t_score.course_id = t_course.id AND t_score.student_id = t_student.id ORDER BY t_score.score DESC ``` #### 函数 SQL像很多语言一样,有很多内置函数,不过不同的数据库不太一样,读者最好还是去相差的数据库官网查看。 像上文用到的内置ID获取函数uuid(),同时去除-: ```sql select replace(uuid(),'-',''); ``` ##### COUNT()计算学生总数 ```sql SELECT COUNT(id) FROM t_student; ``` ##### MAX()各个科目的的最高分及学生姓名与科目名字 ```sql SELECT t_student.name,t_course.name AS course_name,MAX(t_score.score) FROM t_student,t_score,t_course WHERE t_student.id = t_score.student_id AND t_course.id = t_score.course_id GROUP BY t_course.id; ``` ##### AVG()计算每个班级的平均分 ```sql SELECT t_class.name,AVG(t_score.score) FROM t_student,t_class,t_student_class,t_score WHERE t_student.id = t_score.student_id AND t_student.id = t_student_class.student_id AND t_student_class.class_id = t_class.id GROUP BY t_class.id; ``` ##### HAVING()找到那些平均分超过80的人 ```sql SELECT t_student.name,AVG(t_score.score) FROM t_student,t_score WHERE t_student.id = t_score.student_id GROUP BY t_student.id HAVING AVG(t_score.score) >= 80; ``` #### 视图 视图没有物理数据,是一种储存SQL的定义,可以理解为一种虚拟表,只显示你想显示的信息给用户且无法修改,甚至对数据库外来说,无可得知其相关表信息。所以它简单、安全,独立。 学生与班级的关系创建一个视图: ```sql CREATE OR REPLACE VIEW v_student AS SELECT t_student.id,t_student.name,t_class.name AS class_name,t_student.code FROM t_student,t_class,t_student_class WHERE t_student.id = t_student_class.student_id AND t_student_class.class_id = t_class.id; ``` #### 存储过程 存储过程是一个SQL集,一次编译后直接保存在数据库,无需再编译,提高了执行效率(JAVA编译成class的思想也是这样,一次编译,处处运行)。存储过程与函数类似,一般来说,存储过程可以实现更复杂强大的功能,而函数相对简单,但是函数可以嵌入SQL中使用,而存储过程不行。 学生与班级的关系创建一个存储过程: ```sql DROP PROCEDURE IF EXISTS p_student; CREATE PROCEDURE p_student() BEGIN SELECT t_student.id,t_student.name,t_class.name AS class_name,t_student.code FROM t_student,t_class,t_student_class WHERE t_student.id = t_student_class.student_id AND t_student_class.class_id = t_class.id; END ; CALL p_student(); ``` 比如可以写一个相加的存储过程: ```sql DROP PROCEDURE IF EXISTS p_add; CREATE PROCEDURE p_add(IN a INT, IN b INT) BEGIN DECLARE val INT DEFAULT 0; if a IS NULL THEN SET a = 0; END if; if b IS NULL THEN SET b = 0; END if; SET val = a + b; SELECT val; END; ``` #### 触发器 触发器是由像增删改等操作时自动触发的操作。 创建一个触发器,在插入学生数据时,另外记录一下日志: ```sql CREATE TRIGGER save_student_add_time BEFORE INERT ON t_student FOR EACH ROW INERT INTO t_student_log(option_time) VALUES(NOW()) ``` 这种场景一般是在银行转账等较重要的操作时,会进行一个日志记录。 #### 事务 事务是为了保持数据一致的事情处理 还是以转账为例吧,比如A给B转账10000元,显然不能先给A减10000,再给B增加10000,以免在A减少钱后,B又没收到钱的情况: ```sql START TRANSACTION; UPDATE t_user set account = account - 10000 where id = 1; UPDATE t_user set account = account + 10000 where id = 2; COMMIT TRANSACTION; ``` #### SQL注入 SQL注入,XSS,CSRF 可谓是网站草丛三基佬,虽然说没有绝对安全的系统,但不意味相对的安全不重要,写健壮的代码是一个合格程序员基本功。 SQL注入就是在参数中传入SQL语句,这里只是简单介绍下,不做展开。 如果某个用户查询自己的成绩,他需要传入个人code = 201600001, 即参数是201600001,可他传的是201600001 or 1 = 1 ```sql SELECT * FROM t_student WHERE code = 201600001 or 1 = 1; ``` 那么,所有用户的信息都可获得,同理,用户登录一样的。 找到该数据库所有表名: ```sql SELECT * FROM t_student WHERE name like '1"' ;SHOW TABLES;'"' ``` 查找该表有多少列,有哪些列: ```sql SELECT * FROM t_student WHERE name like '1"' ;DESC t_student;'"' ``` 查找名字像 x 的用户,故意传参数为 x'";select database()"'之类的,可以查找出数据库名: ```sql SELECT * FROM t_student WHERE name like "1'";SELECT database();"'"; ``` 同理查询数据库用户,数据名,数据库版本,操作系统,数据目录,数据库安装目录,操作系统用户: ```sql SELECT * FROM t_student WHERE name like '1"' union select USER(),database(),VERSION(),@@version_compile_os,@@datadir,@@basedir,system_user(),8,9,10,11'"' ``` 在程序中应该避免使用管理员账号连接,同时对用户输入进行转换、过滤,加密敏感信息等,以CI框架为例它的$this->db->query()查询相对安全,因为其做了字符串处理。 一个小小的SQL漏洞而已!可能有的程序员存在侥幸心理,认为数据与服务器账号不同,也不允许上传可执行等多种控制,然而,如果坏事有可能发生,不管这种可能性多小,它总会发生。
如果觉得有帮忙,您可以在本页底部留言。
相关推荐:
从youtube观看记录分析时长
Webpack深入浅出plugin
Webpack自动更新php静态资源文件名hash
Webpack构建流程之源码分析
Webpack基于scss生成css独立文件
Webpack深入浅出loader
移动端浏览器真机调试的几种方法
接入台湾超商门店地址选择
ember入门教程
Ember之Handlebars模板引擎
Mac高频快捷键之前端篇
简述浏览器缓存之cookie
浏览器打开页面的过程中发生了什么
Git命令简化笔记
PHP实现微信JS-SDK权限验证
如何用正确的姿势写HTML
正则表达式实例解析
……
更多
<
sass之scss心得
CSS变形matrix与动画cubic-bezier
>
全部留言
我要留言
内容:
网名:
邮箱:
个人网站:
发表
全部留言