SELECT [DISTINCT | DISTINCTROW | ALL] select_expression,...
[FROM table_references
[WHERE where_definition]
[GROUP BY col_name,...]
[HAVING where_definition]
[ORDER BY {unsigned_integer | col_name | formula} [ASC | DESC] ,...]
[LIMIT [offset,] rows]
[PROCEDURE procedure_name]]
from子句:指定查询数据的表
where子句:查询数据的过滤条件
group by子句:对匹配where子句的查询结果进行分组
having子句:对分组后的结果进行条件限制
order by子句:对查询结果结果进行排序,后面跟desc降序或asc升序(默认)。
limit子句:对查询的显示结果限制数目
1、查询全体学生的学号与姓名。
select sno,sname from student;
2、查询全体学生的详细记录。
select sno,sname,ssex,sage,sdept from student;
或select * from student;
查询性别为男的全部学生信息
select *from t_student t where t.stu_sex=‘男’;
查询年龄在18岁到20之间的所有学生
select * from t_student where sage>=18 and sage<=23;
查询年龄不在18~20岁的所有学生
select * from t_student where sage<18 or sage>23;
查询非计算机系的学生信息
select * from t_student where not dept=‘计算机系’
或 select * from t_student where sclass<>‘计算机系’
在WHERE子句中使用谓词
BETWEEN AND :在两数之间
NOT BETWEEN AND :不在两数之间
IN <值表> :是否在特定的集合里(枚举)
NOT IN <值表> :与上面相反
LIKE :是否匹配于一个模式
IS NULL(为空的)或 IS NOT NULL(不为空的)
查询10号前课程成绩在60~80分的成绩记录
select * from t_score where sno like ‘9500_’ and score between 60 and 80
说明:选取该列数据属于between… and区间,包含边界值的
可以使用如下语句替代:
select * from t_score where sno like ‘9500_’
and score>=60 and score<=80
1、查询’信息系’、‘美术系’学生的姓名和性别。
select sname,ssex from student where sdept in (‘信息系’,‘美术系’);
2、查询学生的“JAVA”成绩和"C"成绩记录
select * from score where cid in(select cid from course where cname=“JAVA” or cname=“C”);
通常与LIKE关键字一起来使用
可以用在检查约束中使用LIKE
在后面的查询语句中还会经常使用到
Where子句通配符
查询姓名以欧开头的所有学生
select * from t_student where name like ‘欧%’
查询姓名中含欧的的所有学生
select * from t_student where name like ‘%欧%’
查询学号95010 前的所有学生
select * from t_student where no like ‘9500_‘;
查询学号95005 前(包含5)的所有学生
select * from t_student where no regexp‘9500[1-5]’;
【orber by】–排序
.查询选修了4号课程的学生的学号及其成绩,查询结果按分数降序排列。
select studentid,grade from sc where courseid=4 orber by grade desc;
【group by】–分组
查询有哪些系?
select dept from student group by dept;
【distinct】–去掉重复
查询有课程成绩的学生学号(去掉重复的记录)
select distinct studentid from sc;
【limit】–限制条数
查询年龄最大的前3个学生的姓名和年龄,或第4、5个学生
select sname,sage from student order by sage desc limit 3;
要求每页显示5条成绩信息,查询第2页的成绩信息?
SQL提供的统计函数称为集函数.
主要的集函数:
记数函数: count(列名) 计算元素的个数
求和函数: sum(列名) 对某一列的值求和,但属性必须是整型
计算平均值:avg(列名)对某一列的值计算平均值
求最大值: max(列名) 找出某一列的最大值
求最小值: min(列名) 找出某一列的最小值
案例
1、查询学生总数。
select count(*) from student;
2、查询选修了课程的学生人数。
select count(distinct studentid) from sc;
3、查询1号课程的学生平均成绩。
select avg(grade) from sc where courseid=1;
4、查询1号课程的学生最高分和最低分。
select max(grade) as ‘最高分’,min(grade) as ‘最低分’ from sc where courseid=1;
5、查询每个学生的平均成绩。
select studentid,avg(grade) as ‘平均成绩’ from sc group by studentid;
6、查询学生的平均成绩在70分以上的。
select studentid,avg(grade) as ‘平均成绩’ from sc group by studentid having avg(grade)>70;
学员内部测试成绩查询的每次显示的都是学员的编号信息,
因为该表中只存储了学员的编号;
实际上最好显示学员的姓名,而姓名存储在学员信息表;
如何同时从这两个表中取得数据?
连接
连接查询
同时涉及多个表的查询称为连接查询
用来连接两个表的条件称为连接条件
内连接(INNER JOIN)
外连接
——左外联结 (LEFT JOIN)
——右外联结 (RIGHT JOIN)
外连接与普通连接的区别
普通连接操作只输出满足连接条件的元组
外连接操作以指定表为连接主体,将主体表中不满足连接条件的元组一并输出:
内连接:inner join
1、查询有成绩的所有学生信息
select *from tbl_stu,tbl_score where tbl_stu.stu_id=tbl_score.stu_id;
select *from tbl_stu inner join tbl_score on a.stu_id=b.stu_id;
没有成绩的学生就没有查询出来
左外连接:left join
嵌套子查询
in子查询
查询有成绩的学生信息
select * from tab_student
where stu_id in (select stu_id from tab_score)
查询1课程有成绩的学生信息
select * from t_student where sno in (select sno from t_score where cno='1')
事务和锁是两个联系非常紧密的概念。
事务很重要,可以保证多用户并发系统中的数据的完整性。在数据库中,存在多个用户同时对某一数据进行读写操作的情况,为了确保数据的并行性和一致性,可以使用事务。
锁是MySQL数据库引擎用来同步多个用户,同时对同一个数据块访问的一种机制。
锁可以消除多用户操作同一个资源产生的隐患。
事务的概念
事务(transaction)在数据库中主要用于保证数据的一致性,防止出现错误数据。
在数据库中数据的完整性是一个广义概念,它包括数据的并行性和一致性。
事务是单个的工作单元。
如果某一事务成功,则在该事务中进行的所有数据修改均会提交,称为数据库中的永久组成部分;
如果事务遇到错误且必须取消或回滚,则所有的数据均会被清除。
事务(transaction)是用户定义的一个数据库操作序列,是一个不可分割的整体。这些操作要么全做,要么全不做。事务是对数据库进行操作的最基本的逻辑单位,它可以是一组SQL语句或整个程序。通常情况下,一个应用程序里包含多个事务。此外,事务还是恢复和并发控制的基本单位。
事务和程序不同,一条语句或者多条语句甚至一段程序都可能在一个事务中,而一段程序又可以包含多个事务。事务可以根据自己的需要把一段程序分成多个组,然后把每个组都当成一个单元,而这个单元就可以理解为一个事务。
事务的特性
事务:事务由一个或多个动作绑定起来作为一个单独的工作单元,要么一起成功,要么一起失败。
Atomic(原子性):原子性保证事务中所有的操作要么都执行,或者都不执行。如果所有的动作都执行了,那么事务就是成功的,如果其中有一个动作失败了,那么整个事务都失败,而且要执行回滚操作。
Consistent(一致性):一旦事务结束(可能成功了也可能失败了),那么系统所模拟的业务逻辑要处于一致的状态。数据不应该被实体关系破坏。
Isolated(隔离性):事务应该允许多个用户操作一个数据,一个用户的操作应该不受另一个用户操作的影响。因此事务之间应该是相互隔离的,以阻止他们在操作中同时读写同一数据。(一般是以乐观锁来实现这一特性的)
Durable(持久性):一旦事务完成,事务执行的结果就应该被保存到数据库中,这样即使因为某一原因系统崩了,数据还能保存下来。传统上是把结果保存到数据库或者其他某种格式的持久化介质中。
MySQL事务操作
事务在没有提交之前可以回滚,而且在提交前,当前用户可以查看已经修改的数据,但其他用户看不到该数据,一旦事务提交就不能再撤销修改了。MySQL数据库的事务基本控制语句有如下几种:
set transaction,设置事务的属性。
commit,提交事务。
savepoint,设置保存点。
rollback,回滚事务。
rollback to savepoint,回滚至保存点。
注意:
在 MySQL 命令行的默认设置下,事务都是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT 操作。因此要显式地开启一个事务务须使用命令 BEGIN 或 START TRANSACTION,或者执行命令 SET AUTOCOMMIT=0,用来禁止使用当前会话的自动提交。
事务类型
操作事务可分为两种方式:显示操作方式和隐示管理方式。
1.显示操作方式
显式操作方式是对事务的提交或回滚,需要用户利用脚本来完成。
Sql statements
Commit | rollback;
2.隐示管理方式
隐示管理方式没有明确的开始和结束标志,它同样由数据库自动开启。当一个程序正常结束或执行DDL语句时会自动提交,例如create table语句。而操作失败时就会自动回退,这些都是被动完成的,不需要开发者的参与。
利用语句可以设置事务是否自动提交。
set autocommit = 0;
JDBC事务
JDBC操作事务过程:
connection.setAutoCommit(false);//打开事务。
……操作语句
connection.commit();//提交事务。
或connection.rollback();//回滚事务。
SavePoint保存点的操作:
只想撤销事务中的部分操作时可以使用SavePoint
SavePoint sp=ct.setSavepoint();
…….
connection.rollerbak(sp);
或 connection.commit();
锁
锁是计算机协调多个进程或线程并发访问某一资源的机制。锁保证数据并发访问的一致性、有效性;锁冲突也是影响数据库并发访问性能的一个重要因素。锁是Mysql在服务器层和存储引擎层的的并发控制。
加锁是消耗资源的,锁的各种操作,包括获得锁、检测锁是否是否已解除、释放锁等。
锁机制
共享锁与排他锁
共享锁(读锁):其他事务可以读,但不能写。
排他锁(写锁) :其他事务不能读取,也不能写。
粒度锁
MySQL 不同的存储引擎支持不同的锁机制,所有的存储引擎都以自己的方式显现了锁机制,服务器层完全不了解存储引擎中的锁实现:
MyISAM 和 MEMORY 存储引擎采用的是表级锁(table-level locking)
BDB 存储引擎采用的是页面锁(page-level locking),但也支持表级锁
InnoDB 存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。
默认情况下,表锁和行锁都是自动获得的, 不需要额外的命令。
但是在有的情况下, 用户需要明确地进行锁表或者进行事务的控制, 以便确保整个事务的完整性,这样就需要使用事务控制和锁定语句来完成。
不同粒度锁的比较
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
这些存储引擎通过总是一次性同时获取所有需要的锁以及总是按相同的顺序获取表锁来避免死锁。
表级锁更适合于以查询为主,并发用户少,只有少量按索引条件更新数据的应用,如Web 应用
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
最大程度的支持并发,同时也带来了最大的锁开销。
在 InnoDB 中,除单个 SQL 组成的事务外,
锁是逐步获得的,这就决定了在 InnoDB 中发生死锁是可能的。
行级锁只在存储引擎层实现,而Mysql服务器层没有实现。 行级锁更适合于有大量按索引条件并发更新少量不 同数据,同时又有并发查询的应用,如一些在线事务处理(OLTP)系统
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
MyISAM 表锁
MyISAM表级锁模式:
表共享读锁 (Table Read Lock):不会阻塞其他用户对同一表的读请求,但会阻塞对同一表的写请求;
表独占写锁 (Table Write Lock):会阻塞其他用户对同一表的读和写操作;
MyISAM 表的读操作与写操作之间,以及写操作之间是串行的。当一个线程获得对一个表的写锁后, 只有持有锁的线程可以对表进行更新操作。 其他线程的读、 写操作都会等待,直到锁被释放为止。
默认情况下,写锁比读锁具有更高的优先级:当一个锁释放时,这个锁会优先给写锁队列中等候的获取锁请求,然后再给读锁队列中等候的获取锁请求。
这也正是 MyISAM 表不太适合于有大量更新操作和查询操作应用的原因,因为,大量的更新操作会造成查询操作很难获得读锁,从而可能永远阻塞。同时,一些需要长时间运行的查询操作,也会使写线程“饿死” ,应用中应尽量避免出现长时间运行的查询操作(在可能的情况下可以通过使用中间表等措施对SQL语句做一定的“分解” ,使每一步查询都能在较短时间完成,从而减少锁冲突。如果复杂查询不可避免,应尽量安排在数据库空闲时段执行,比如一些定期统计可以安排在夜间执行)。
MyISAM加表锁方法
MyISAM 在执行查询语句(SELECT)前,会自动给涉及的表加读锁;在执行更新操作(UPDATE、DELETE、INSERT 等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预,因此,用户一般不需要直接用 LOCK TABLE 命令给 MyISAM 表显式加锁。
在自动加锁的情况下,MyISAM 总是一次获得 SQL 语句所需要的全部锁,这也正是 MyISAM 表不会出现死锁(Deadlock Free)的原因。
MyISAM存储引擎支持并发插入,以减少给定表的读和写操作之间的争用:
如果MyISAM表在数据文件中间没有空闲块,则行始终插入数据文件的末尾。 在这种情况下,你可以自由混合并发使用MyISAM表的INSERT和SELECT语句而不需要加锁——你可以在其他线程进行读操作的时候,同时将行插入到MyISAM表中。 文件中间的空闲块可能是从表格中间删除或更新的行而产生的。 如果文件中间有空闲快,则并发插入会被禁用,但是当所有空闲块都填充有新数据时,它又会自动重新启用。 要控制此行为,可以使用MySQL的concurrent_insert系统变量。
如果你使用LOCK TABLES显式获取表锁,则可以请求READ LOCAL锁而不是READ锁,以便在锁定表时,其他会话可以使用并发插入。
当concurrent_insert设置为0时,不允许并发插入。
当concurrent_insert设置为1时,如果MyISAM表中没有空洞(即表的中间没有被删除的行),MyISAM允许在一个线程读表的同时,另一个线程从表尾插入记录。这也是MySQL的默认设置。
当concurrent_insert设置为2时,无论MyISAM表中有没有空洞,都允许在表尾并发插入记录。
查询表级锁争用情况
可以通过检查 table_locks_waited 和 table_locks_immediate 状态变量来分析系统上的表锁的争夺,如果 Table_locks_waited 的值比较高,则说明存在着较严重的表级锁争用情况:
InnoDB行级锁和表级锁
InnoDB 实现了以下两种类型的行锁:
共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
排他锁(X):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。
为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB 还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁:
意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的 IS 锁。
意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的 IX 锁。
锁模式的兼容情况:
InnoDB加锁方法
意向锁是 InnoDB 自动加的, 不需用户干预。
对于 UPDATE、 DELETE 和 INSERT 语句, InnoDB
会自动给涉及数据集加排他锁(X);
对于普通 SELECT 语句,InnoDB 不会加任何锁;
事务可以通过以下语句显式给记录集加共享锁或排他锁:
共享锁(S):SELECT * FROM table_name WHERE … LOCK IN SHARE MODE。 其他 session 仍然可以查询记录,并也可以对该记录加 share mode 的共享锁。但是如果当前事务需要对该记录进行更新操作,则很有可能造成死锁。
排他锁(X):SELECT * FROM table_name WHERE … FOR UPDATE。其他 session 可以查询该记录,但是不能对该记录加共享锁或排他锁,而是等待获得锁
InnoDB 行锁实现方式:
InnoDB 行锁是通过给索引上的索引项加锁来实现的,这一点 MySQL 与 Oracle 不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB 这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB 才使用行级锁,否则,InnoDB 将使用表锁!
不论是使用主键索引、唯一索引或普通索引,InnoDB 都会使用行锁来对数据加锁。
只有执行计划真正使用了索引,才能使用行锁:即便在条件中使用了索引字段,但是否使用索引来检索数据是由 MySQL 通过判断不同执行计划的代价来决定的,如果 MySQL 认为全表扫描效率更高,比如对一些很小的表,它就不会使用索引,这种情况下 InnoDB 将使用表锁,而不是行锁。因此,在分析锁冲突时,
别忘了检查 SQL 的执行计划(可以通过 explain 检查 SQL 的执行计划),以确认是否真正使用了索引。(更多阅读:MySQL索引总结)
由于 MySQL 的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然多个session是访问不同行的记录, 但是如果是使用相同的索引键, 是会出现锁冲突的(后使用这些索引的session需要等待先使用索引的session释放锁后,才能获取锁)。 应用设计的时候要注意这一点。
获取 InnoDB 行锁争用情况:
可以通过检查 InnoDB_row_lock 状态变量来分析系统上的行锁的争夺情况:
死锁(Deadlock Free)
死锁产生:
死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环。
当事务试图以不同的顺序锁定资源时,就可能产生死锁。多个事务同时锁定同一个资源时也可能会产生死锁。
锁的行为和顺序和存储引擎相关。以同样的顺序执行语句,有些存储引擎会产生死锁有些不会——死锁有双重原因:真正的数据冲突;存储引擎的实现方式。
检测死锁:数据库系统实现了各种死锁检测和死锁超时的机制。InnoDB存储引擎能检测到死锁的循环依赖并立即返回一个错误。
死锁恢复:死锁发生以后,只有部分或完全回滚其中一个事务,才能打破死锁,InnoDB目前处理死锁的方法是,将持有最少行级排他锁的事务进行回滚。所以事务型应用程序在设计时必须考虑如何处理死锁,多数情况下只需要重新执行因死锁回滚的事务即可。
外部锁的死锁检测:发生死锁后,InnoDB 一般都能自动检测到,并使一个事务释放锁并回退,另一个事务获得锁,继续完成事务。但在涉及外部锁,或涉及表锁的情况下,InnoDB 并不能完全自动检测到死锁, 这需要通过设置锁等待超时参数 innodb_lock_wait_timeout 来解决
死锁影响性能:死锁会影响性能而不是会产生严重错误,因为InnoDB会自动检测死锁状况并回滚其中一个受影响的事务。在高并发系统上,当许多线程等待同一个锁时,死锁检测可能导致速度变慢。 有时当发生死锁时,禁用死锁检测(使用innodb_deadlock_detect配置选项)可能会更有效,这时可以依赖innodb_lock_wait_timeout设置进行事务回滚。
一些优化锁性能的建议
尽量使用较低的隔离级别;
精心设计索引, 并尽量使用索引访问数据, 使加锁更精确, 从而减少锁冲突的机会
选择合理的事务大小,小事务发生锁冲突的几率也更小
给记录集显示加锁时,最好一次性请求足够级别的锁。比如要修改数据的话,最好直接申请排他锁,而不是先申请共享锁,修改时再请求排他锁,这样容易产生死锁
不同的程序访问一组表时,应尽量约定以相同的顺序访问各表,对一个表而言,尽可能以固定的顺序存取表中的行。这样可以大大减少死锁的机会
尽量用相等条件访问数据,这样可以避免间隙锁对并发插入的影响
不要申请超过实际需要的锁级别
除非必须,查询时不要显示加锁。 MySQL的MVCC可以实现事务中的查询不用加锁,优化事务性能;MVCC只在COMMITTED READ(读提交)和REPEATABLE READ(可重复读)两种隔离级别下工作
对于一些特定的事务,可以使用表锁来提高处理速度或减少死锁的可能