文章目录
基本概念
一、数据库的产品
1、 中小型数据管理:mysql
2、 大型数据管理:oracle;DB2;Sysbase;Informax
3、 小型数据库:sql server(只能运行在windows平台,安全性差)
二、 数据库的分类
关系型数据库:oracle;DB2;Mysql
非关系型数据库(NoSql):
数据库类型 | 特性 | 优点 | 缺点 |
---|---|---|---|
关系型数据库 SQLite、Oracle、mysql | 1、关系型数据库,是指采用了关系模型来组织数据的数据库; 2、关系型数据库的最大特点就是事务的一致性; 3、简单来说,关系模型指的就是二维表格模型,而一个关系型数据库就是由二维表及其之间的联系所组成的一个数据组织。 | 1、容易理解:二维表结构是非常贴近逻辑世界一个概念,关系模型相对网状、层次等其他模型来说更容易理解; 2、使用方便:通用的SQL语言使得操作关系型数据库非常方便; 3、易于维护:丰富的完整性(实体完整性、参照完整性和用户定义的完整性)大大减低了数据冗余和数据不一致的概率; 4、支持SQL,可用于复杂的查询。 | 1、为了维护一致性所付出的巨大代价就是其读写性能比较差; 2、固定的表结构; 3、高并发读写需求; 4、海量数据的高效率读写; |
非关系型数据库 MongoDb、redis、HBase | 1、使用键值对存储数据; 2、分布式; 3、一般不支持ACID特性; 4、非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合。 | 1、无需经过sql层的解析,读写性能很高; 2、基于键值对,数据没有耦合性,容易扩展; 3、存储数据的格式:nosql的存储格式是key,value形式、文档形式、图片形式等等,文档形式、图片形式等等,而关系型数据库则只支持基础类型。 | 1、不提供sql支持,学习和使用成本较高; 2、无事务处理,附加功能bi和报表等支持也不好; |
Mysql
一、Mysql简介
1、 mysql下载:oracle官网(半收费)
2、基本概念
1、create建表建库、drop删除表、alter修改表结构、select查询、insert插入、
update更新数据、delete删除数据、grant授权、revoke权限回收
2、 Varchar:字符串 auto_increment:自动添加
3、不等于!=和<>
4、sql:结构化查询语言
3、连接MySQL数据库
public class DButil {
//数据库的地址、用户名、密码
private static String url="jdbc:mysql://localhost:3306/school";
private static String user="root";
private static String password="root";
public static Connection getConnection() {
Connection conn=null;
try {
//注册JDBC驱动
Class.forName("com.mysql.jdbc.Driver");
//获得与数据库的连接
conn=DriverManager.getConnection(url, user, password);
}catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
一般在开发项目时,都会在工具类所对应的包下新建DB.properties(Java的配置文件) 注意:此方法中的DButil不能是静态的工具类
driver = JDBC驱动
url=数据库所在的地址
use=用户名
pwd=密码
在DButil类中新建构造方法
public DButil(){
InputStream is =this.getClass().getReaourceAsStream(“DB.properties”);//获得一个输入流
// this.getClass():获得该对象所对应的类
Properties prop= new Properties();//键值对对应的集合
prop.load(is)://将输入流转换成Properties形式的键值对
this.driver = prop.getProperty(“driver”);//读取driver键所对应的值,并赋值给
}
二、 mysql命令
1、 连接数据库:mysql -h数据库所在的主机名 -u用户名 -p密码
出现mysql>表示链接成功
2、 查看mysql数据库中有多少数据库: use databases;
3、 选择某个数据库执行命令:use 数据库名;
4、 查看某个数据库中有多少数据表: show tables;
5、 查看数据表的结构: desc 数据表名;
6、 查看数据表中的数据: select * from 表名;
7、 新建数据库:create database 数据库的名字;
8、 断开数据库:exit;
三、Mysql常用的数据类型
结构化数据:
整型:
Int 整型 11位 ; SmallInt 短整型 ;BigInt 长整型 ;
byte 字节型(使用0和1,当作布尔型来使用)
浮点型:
Float(7,2)单精度浮点型,一共7位其中2位为小数位;
double()双精度浮点型
字符型:
Char(5)固定长度字符串 ,长度不够自动补齐,最大长度为255
Varchar(5)可变长度字符串,长度不够不自动补齐,最大长度为255
text大文本类型,不允许指定长度,默认为64kb
日期:不允许设置大小默认为8位
date日期类型(年 月 日)
datetime时间类型(年 月 日 时 分 秒)
timestamp时间类型,精确到毫秒,可以自动获取当前服务器数据库系统时间
非结构化数据:
bolb:大二进制对象类型 默认为4GB(用于电影,图片,压缩文件等大型文件)
四、新建数据表:
create table 数据表名(
数据表的字段名 数据类型(数据的长度) 是否为空(null/not null)
是否为主键(primary key) auto_increment(设置是该字段值否自动增加)
default 设置该字段的默认值 逗号
………
)
补充 :1、设置外键:foreign key(pid) references 表名(外键) 2、unique:唯一 注意:1、与sql sever一样除最后一行外每一行结束加逗号, 2、主键唯一且不能为空 其中information_schema、 mysql、 performance_schema 、test 由系统创建不可更改
五、数据操作(crud)增删改查
数据库包含的表
学生表Student(Sno , Sname , Sage Ssex Sdept)
课程表 Course(Cno , Cname ,Cpno, Ccredit)
选课表 Sc(Sno Cno Garde)
1、插入数据
insert into 数据表明(字段名, ....)values(值, ....)
注意:1、不能违反字段的约束条件
2、值与字段名一一对应(包括数量和数据类型),字符串用单引号括住
2、修改数据
update 表名
set 字段名=新的值[,字段名=新的值]
where 条件1 and条件2
3、删除数据
delete from 表名 where 条件
4、查询数据:不会改变数据库中的数据
查询语句的执行
语法顺序:select--from--where--group by--having--order by
执行顺序:from--where--group by--having--select--order by
其中select和from是必须的,其他则是可选的。
having表示已经分组的数据进行过滤~ having可以使用聚合函数(sum, count等),而where不行。
1、查询语句的基本组成
select 字段名
from 表名
where 条件1 and或者or 条件2
group by 字段名 having 设置条件 count(*)>0
order by 字段名 asc(升序)|desc(降序)
limit 10,5 ;从第10行开始,查询5行结束(将来用于分页)
2、常用的函数和一些关键字
1、关键字
关键字as:as 别名(as可以省略)
关键字distinct:去除重复
关键字exists:带有exists的子查询不反回数据,只产生逻辑真或假
2、分组函数:group by:分组主要用于统计分析
3、聚合函数:sum avg平均数 max min count
count(*):聚合函数,求某一字段一共有多少个
4、处理字符串的函数:
函数substr(‘abcde’,1,3):截取的abcde的前三个字符
函数instr(’abcde’,’a’):求a在abcde字符串中的索引并返回
函数concat(字符串1,字符串2):将字符串进行拼接
函数left(字符串,2):从左边开始截取前两个字符并返回
函数right(字符串,2):从右边开始截取前两个字符并返回
函数replace(s,s1,s2):将字符串s中的s1替换为s2
5、函数now():返回当前系统的时间,返回值为data类型
3、范围查询 : between……and……(数值和时间)
select * from 表 where 字段名 between…and…
4、模糊查询 like%
%代表任意多个字符,一个下划线只代表一个字符
例子: select * from 表 where name like ’ %刚 % ’ ;
5、列表查询关键字in
字段名 in(‘条件1’,‘条件2’,‘条件3’)相当于条件1或条件2或条件3
6、多表联合查询
1、内联查询:两张表都有的记录才能查询出来(求两张表的交集)
语法:
- 第一种:inner join…on…
select Sname Grade
from student (as 别名)inner join sc (as 别名)
on student.Sno=sc.Sno (表a的主键=表b的外键)inner join 表三
on 连接条件……
- 第二种:where
select Sname Grade
from student (as 别名), sc (as 别名)
where student.Sno=sc.Sno
例子:筛选出同时选过1号课程和4号课程的学生
select sno
from course a inner join course b
on a.Sno=b.Sno (表a的主键=表b的外键)
where cno=1 and cno=2
2、外联查询
语法
- 1、左外联接:优先显示左边表的全部记录和右边表的相关联记录
select Sname Grade
from student (as 别名) left join sc (as 别名)
on student.Sno=sc.Sno left join 表三
on 连接条件
优先显示student的记录,将student表中的所有记录都显示出来,sc表中与student有关的才显示出来,无关的显示默认值
- 2、右外联接:有显示右边的表,将left join 改为right join
注意:左右联接可以配合使用,内联和外联也可以混合使用
7、嵌套查询
- 语法: in关键字和not in关键字
select Sname Grade
from student , sc
where student.Sno in (
select sc.Sno
form sc where 条件
)
六、数据表的操作
1、修改表的结构alter
添加新字段:alter table 表名 add 字段名 数据类型(长度)
删除旧字段:alter table 表名 drop column字段名
2、删除数据表/数据库drop
drop table 数据表名
drop database 数据库名
七、mysql集合运算符
1、union all求两个集合的并集:
select * from student where sex=男
union all
select * from student where sex=女
2、union求两个集合的并集,重复过滤
select * from student where sex=男
union all
select * from student where sex=女
八、三大范式
1、基本概念
第一范式:所有字段的值都是不可再分的最小数据单元也称为原子性
第二范式: 除主键以外的列都完全依赖于主键,不存在部分依赖
第三范式:主键以外的字段必须直接依赖于主键不存在传递依赖
-
第三范式的例子:
学生表Student(Sno , Sname , Sage Ssex Sdept) 课程表 Course(Cno , Cname ,Cpno, Ccredit) 选课表 Sc(Sno Cno Garde)
-
部分依赖:
学生表Student(Cno ,Sno , Sname , Sage Ssex Sdept Garde)
在学生表中 (Cno ,Sno)---- Sdept,院系由学号决定与课程号无关所以是部分依赖
解决办法是:投影法分解为两个表,分别是学生表和课程表
- 传递依赖:
学生表Student(Sno , Sname , Sage Ssex Smajor Sdept)
Sno决定Sdept,Sdept决定Smajor即Sno决定Smajor,存在传递关系
解决:学生表Student(Sno , Sname , Sage Ssex Sdept)和 表2(Sdept Smajor)
九、事务(面试)
一、事务概念
1、事务:解决多用户并发访问的问题
- 局部事物 vs. 全局事务
局部事务是特定于一个单一的事务资源,如一个 JDBC 连接,而全局事务可以跨多个事务资源事务,如在一个分布式系统中的事务。局部事务管理在一个集中的计算环境中是有用的,该计算环境中应用程序组件和资源位于一个单位点,而事务管理只涉及到一个运行在一个单一机器中的本地数据管理器。局部事务更容易实现。
全局事务管理需要在分布式计算环境中,所有的资源都分布在多个系统中。在这种情况下事务管理需要同时在局部和全局范围内进行。分布式或全局事务跨多个系统执行,它的执行需要全局事务管理系统和所有相关系统的局部数据管理人员之间的协调。
二、数据库事务处理
数据库
数据库的更新通常都是由客观世界的所发生的事件引起的。为保证数据库内容的一致,就要将数据库的一组操作作为一个整体来进行,要么全部成功完成,要么全部失败退出。如果由于故障或其它原因而使一组操作中有一些完成,有一些未完成,则必然会使得数据库中的数据出现不一致,从而使得数据库的完整性受到破坏。因此,更新操作序列必须作为一个整体在DBMS执行时出现,即“要么全做,要么全不做”。SQL提供了事务处理的机制,来帮助DBMS实现上述的功能。
事务处理
事务处理(TRANSACTION)是由一个或多个SQL语句序列结合在一起所形成的一个逻辑处理单元。事务处理中的每个语句都是完成整个任务的一部分工作,所有的语句组织在一起能够完成某一特定的任务。DBMS在对事务处理中的语句进行处理时,是按照下面的约定来进行的,这就是“事务处理中的所有语句被作为一个原子工作单位,所有的语句既可成功地被执行,也可以没有任何一个语句被执行”。DBMS负责完成这种约定,即使在事务处理中应用程序异常退出,或者是硬件出现故障等各种意外情况下,也是如此。在任何意外情况下,DBMS都负责确保在系统恢复正常后,数据库内容决不会出现“部分事务处理中的语句被执行完”的情况
两个重要的SQL语句
- 1、执行commit方法,将内存中的结果插入到数据表中
- 2、执行 rollback方法,将内存中的结果删除,数据表中的数据不会改变
COMMIT语句用于告诉DBMS,事务处理中的语句被成功执行完成了。被成功执行完成后,数据库内容将是完整的。而ROLLBACK语句则是用于告诉DBMS,事务处理中的语句不能被成功执行。这时候,DBMS将恢复本次事务处理期间对数据库所进行的修改,使之恢复到本次事务未处理的状态。
三、事务具有特征:简称 ACID
原子性:事务的不可再分
原子性属性用于标识事务是否完全地完成,一个事务的任何更新要在系统上完全完成,如果由于某种原因出错,事务不能完成它的全部任务,系统将返回到事务未开始的状态。
让我们再看一下银行转帐的例子。如果在转帐的过程中出现错误,整个事务将会回滚。只有当事务中的所有部分都成功执行了,才将事务写入磁盘并使变化永久化。
为了提供回滚或者撤消未提交的变化的能力,许多数据源采用日志机制。例如,SQL Server使用一个预写事务日志,在将数据应用于(或提交到)实际数据页面前,先写在事务日志上。但是,其他一些数据源不是关系型数据库管理系统(RDBMS),它们管理未提交事务的方式完全不同。只要事务回滚时,数据源可以撤消所有未提交的改变,那么这种技术应该可用于管理事务。
隔离性:两个事务之间不互相影响
在隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。
这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。
重要的是,在隔离状态执行事务,系统的状态有可能是不一致的,在结束事务前,应确保系统处于一致状态。但是在每个单独的事务中,系统的状态可能会发生变化。如果事务不是在隔离状态运行,它就可能从系统中访问数据,而系统可能处于不一致状态。通过提供事务隔离,可以阻止这类事件的发生。
在银行的示例中,这意味着在这个系统内,其他过程和事务在我们的事务完成前看不到我们的事务引起的任何变化,这对于终止的情况非常重要。如果有另一个过程根据帐户余额进行相应处理,而它在我们的事务完成前就能看到它造成的变化,那么这个过程的决策可能建立在错误的数据之上,因为我们的事务可能终止。这就是说明了为什么事务产生的变化,直到事务完成,才对系统的其他部分可见。
隔离性不仅仅保证多个事务不能同时修改相同数据,而且能够保证事务操作产生的变化直到变化被提交或终止时才能对另一个事务可见,并发的事务彼此之间毫无影响。这就意味着所有要求修改或读取的数据已经被锁定在事务中,直到事务完成才能释放。大多数数据库,例如SQL Server以及其他的RDBMS,通过使用锁定来实现隔离,事务中涉及的各个数据项或数据集使用锁定来防止并发访问。
持久性:事务执行完毕,数据将永久的保存到数据表中
持久性意味着一旦事务执行成功,在系统中产生的所有变化将是永久的。应该存在一些检查点防止在系统失败时丢失信息。甚至硬件本身失败,系统的状态仍能通过在日志中记录事务完成的任务进行重建。持久性的概念允许开发者认为不管系统以后发生了什么变化,完成的事务是系统永久的部分。
在银行的例子中,资金的转移是永久的,一直保持在系统中。这听起来似乎简单,但这,依赖于将数据写入磁盘,特别需要指出的是,在事务完全完成并提交后才写入磁盘的。
所有这些事务特性,不管其内部如何关联,仅仅是保证从事务开始到事务完成,不管事务成功与否,都能正确地管理事务涉及的数据。
一致性:事务提交前与提交之后保持一致
事务在系统完整性中实施一致性,这通过保证系统的任何事务最后都处于有效状态来实现。如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态。如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态。因为事务开始时系统处于一致状态,所以现在系统仍然处于一致状态。
再让我们回头看一下银行转帐的例子,在帐户转换和资金转移前,帐户处于有效状态。如果事务成功地完成,并且提交事务,则帐户处于新的有效的状态。如果事务出错,终止后,帐户返回到原先的有效状态。
记住,事务不负责实施数据完整性,而仅仅负责在事务提交或终止以后确保数据返回到一致状态。理解数据完整性规则并写代码实现完整性的重任通常落在开发者肩上,他们根据业务要求进行设计。
当许多用户同时使用和修改同样的数据时,事务必须保持其数据的完整性和一致性。
四、什么时候需要应用事务
1、同一张表可以同时被多个用户访问时
2、当涉及到一次业务对应多个表的增删改操作
开发技巧:一般数据库的操作都需要增加事务,即使是单表的一次操作(单表操作)
五、事务在框架中的应用
1、在mybatis框架中,需要自己写代码来进行事务处理
2、在spring中提供了事务的处理模式
-
编程式事务:
自己写代码,这意味着你在编程的帮助下有管理事务。这给了你极大的灵活性,但却很难维护 -
宣称式事务:
在写方法之前,进行声明,靠xml来执行,现在添加注解即可添加注解:@Transcational(“参数”)是用来指定接口、类或方法必须拥有事务语义的元数据。
总结:声明式事务管理比编程式事务管理更可取,尽管它不如编程式事务管理灵活,但它允许你通过代 码控制事务。但作为一种横切关注点,声明式事务管理可以使用 AOP 方法进行模块化。Spring 支持使用 Spring AOP 框架的声明式事务管理。
-
Spring 声明式事务管理
声明式事务管理方法允许你在配置的帮助下而不是源代码硬编程来管理事务。这意味着你可以将事务管理从事务代码中隔离出来。你可以只使用注释或基于配置的 XML 来管理事务。 bean 配置会指定事务型方法。下面是与声明式事务相关的步骤:
• 我们使用标签,它创建一个事务处理的建议,同时,我们定义一个匹配所有方法的切入点,我们希望这些方法是事务型的并且会引用事务型的建议。
• 如果在事务型配置中包含了一个方法的名称,那么创建的建议在调用方法之前就会在事务中开始进行。
• 目标方法会在 try / catch 块中执行。
• 如果方法正常结束,AOP 建议会成功的提交事务,否则它执行回滚操作
六、Transcational参数介绍:
1、 isolation :事务的隔离级别(解决多用户并发访问时产生的一些逻辑错误)
- 一些逻辑错误:
脏读(针对未提交的数据) : 一个事务在更新一条记录,未提交前,第二个事务读到了第一个事务更新后的记录,那么第二个事务就读到了脏数据,会产生对第一个未提交 数据的依赖。一旦第一个事务回滚,那么第二个事务读到的数据,将是错误的脏数据
不可重复读 (读取数据本身的对比): 一个事务在读取某些数据后的一段时间后,再次读取这个数据,发现其读取出来的数据内容已经发生了改变,就是不可重复读。(解决方法:在查询的这个记录上加一把锁)
幻读(读取结果集条数的对比) :一个事务按相同的查询条件查询之前检索过的数据,确发现检索出来的结果集条数变多或者减少(由其他事务插入、删除的),类似产生幻觉。
- 事务隔离级别:
@Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读, 不可重复读) 基 本不使用
@Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读) 解决脏读
@Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读) 解决不可重复读和脏读
@Transactional(isolation = Isolation.SERIALIZABLE):串行化事务(让访问的用户一个一个的执行)解决幻读,不可重复读,脏读,最高级别,但是效率最低
一些数据库默认级别:
MYSQL: 默认为REPEATABLE_READ级别
SQLSERVER: 默认为READ_COMMITTED
2、propagation:事务的传播行为()提供嵌套式事务在执行过程中的解决方案,必须存在
- 事物传播行为介绍:
1、@Transactional(propagation=Propagation.REQUIRED) :如果有事务, 那么加入事务, 没有的话新建一个(默认情况下,最经常使用) 即必须在事务中运行
2、@Transactional(propagation=Propagation.REQUIRES_NEW) :不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务(相当于VIP)
3、@Transactional(propagation=Propagation.NEVER) :必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
4、@Transactional(propagation=Propagation.NOT_SUPPORTED) :这个方法不支持事务
5、@Transactional(propagation=Propagation.SUPPORTS) :如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.(支持事务但是没有能力创建事务)
@Transactional(propagation=Propagation.MANDATORY) :必须在一个已有的事务中执行,否则抛出异常
-
图解
-
理解
B方法在A方法内执行:
首先B方法要检测A方法有没有开启事务,方案如下:
1、在A事务内执行,将受A事务的影响
2、B自己开启新的独立事务,不受A事务的影响
3、B方法执行之前,挂起A事务,开启自己新的独立事务(相当于VIP)
4、B方法检测到自己是在A事务内运行,直接抛出异常(这种情况比较少见)
3、rollbackFor:(sql exception)回滚原则(出现什么异常时进行回滚)
4、timeOut:(int)超时时间(以秒为单位)
5、readOnly:(true)只读状态(将业务用的数据表设为只读状态)
十、数据库优化
数据库的优化,包括合理的事务隔离级别、SQL语句优化、索引优化;使用缓存、尽量减少数据库IO;分布式数据库、分布式缓存等
1)用PreparedStatement(预编译)
一般来说比Statement性能高:一个sql 发给服务器去执行,涉及步骤:语法检查、语义分析, 编译,缓存
2)减少外键的使用
有外键约束会影响插入和删除性能,也不利于项目的运维,如果程序能够保证数据的完整性,那在设计数据库时就去掉外键。——尽量减少外键
3)索引
建立索引,提高效率
避免对索引字段进行计算操作
避免在索引字段上使用not,<>,!=
避免在索引列上使用IS NULL和IS NOT NULL
避免在索引列上出现数据类型转换
避免在索引字段上使用函数
避免建立索引的列中使用空值。
4)避免select *的出现
因为select * 会在解析的过程中将通配符*转换成所有列名,是通过查询数据字典完成的。
5)避免出现IN/NOT IN 的出现
用EXISTS替代IN、用NOT EXISTS替代NOT IN (因为in和not in都会对子查询的表进行全表遍历),eg:
(高效)SELECT * FROM EMP (基础表) WHERE EMPNO > 0 AND EXISTS (SELECT ‘X’ FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = ‘MELB’)
(低效)SELECT * FROM EMP (基础表) WHERE EMPNO > 0 AND DEPTNO IN(SELECT DEPTNO FROM DEPT WHERE LOC = ‘MELB’)
6) 用UNION替换WHERE子句中的OR
通常情况下, 用UNION替换WHERE子句中的OR将会起到较好的效果. 对索引列使用OR将造成全表扫描. 注意, 以上规则只针对多个索引列有效(没有索引反而是OR效率高).
7)union all替代union(如果可以的话,因为union会去重)
8)在where子句中应把最具限制性的条件放在最前面。
where子句中字段的顺序应和索引中字段顺序一致。