数据库(DataBase):指长期保存在计算机的存储设备上,按照一定规则组织起来,可以被各种用户或应用共享的数据集合。
用户通过数据库管理系统(DataBase Management System)访问数据库中的数据。
常见数据库管理系统:Oracle(甲骨文)、MySQL、DB2、Microsoft SQL Server。
什么是三大范式?
第一范式(1NF):无重复的列。
第二范式(2NF):属性完全依赖于主键[消除部分子函数依赖]。
第三范式(3NF):属性不依赖于其它非主属性[消除传递依赖]。
(面试)
SQL分类
DDL数据定义语言,用来定义数据库对象:库、表、列等。
DML数据操作语言,用来定义数据库记录。
DCL数据控制语言,用来定义访问权限和安全级别。
DQL数据查询语言,用来查询记录。
SQL以分号结尾(不区分大小写,关键字建议使用大写)
mysql -u (账号root) -p (密码123456)
DDL数据定义语言
创建数据库:create database if not exists 数据库名;(不存在时才创建)
创建库时,设置编码(UTF-8在MYSQL中使用:UTF8MC4替代):
Create database 数据库名 character set UTF8MB4;
查看所有数据库:show databases;
删除数据库:drop database if exists 数据库名;(表存在时才删除)
查看当前使用的数据库:select database();
切换数据库:user 数据库名;
创建表:create table 表名(列名1 数据类型,列名2 数据类型...);
查看当前数据库的表:show tables;
查看表的字段信息:desc 表名;
查看表的创建细节:show create table 表名;
alter table 表名 add 列名 数据类型;
alter table 表名 change 列名 新列名 新的数据类型;
alter table 表名 rename 新表名;
alter table 表名 drop 列名;
alter table 表名 character set 编码方式;修改表的字符集(默认为UTF-8)
常用的数据类型:
- int整形数字
- bigint大整形数字
- double浮点型数字
定义的格式:score double(5,2)--小数点前5位,小数点后2位。
- date日期,只有年月日,使用时的格式:yyyy-MM-dd HH-mm-ss
- datetime日期+时间,包含年月日时分秒,使用时的格式(同上)
- timestamp时间戳,13位数字,从1970-1-1到现在的额毫秒数
- varchar变长字符串
定义的格式:name varchat(20)--姓名最大使用20个字符
在oracle中,varchar被废弃了,建议使用varchar2
(面试)
char(定长字符串)与varchar的区别在于:先扩充空间,在存放数据,即使用不完也要占着。
DML数据操作语言
插入操作:insert(非数值的列值两侧需要加上单引号)
insert into 表名(列名) values(数据值);
当给所有列添加数据的时候,可以将列名省略(值必须按顺序添加)。
多行新增:insert into 表名(列名..) values(数据值),(数据值),(数据值);
查询表的所有数据:select * from 表名;
修改操作:update
整列修改:update 表名 set 列1=值1,列2=值2...;
修改符合条件的数据:update 表名 set 列1=值1 where 列1=值2 and ...;
(面试)
清空表格的删除方式:
delete from 表名 where 列名=值;(表删除后可以找回)
不建议使用,原因时记录过多时,效率很低。
truncate from 表名;(表删除后不能找回)
先删除表格文件,再创建,效率较高。
DCL数据控制语言
创建用户:
create user 用户名@localhost(当前电脑IP) identified by ‘密码’;
指定IP才能登录:
create user 用户名@‘客户端IP’ identified by ‘密码’;
任意IP均可登录:
create user 用户名@‘%’ identified by ‘密码’;
给指定用户授权指定数据库的指定权限:
grant 权限1、权限2~权限n on 数据库名.* to 用户名@‘IP’;
开放所有数据库权限:grant all on *.* to 用户名@‘IP’;
用户权限查询:show grants for 用户名@‘IP’;
删除用户:drop user 用户名@‘IP’;
撤销用户权限:revoke 权限1~权限n on 数据库名.* from 用户名@‘IP’;
DQL数据查询语言
范围查询:
select * from 表名 where 列名 (加not取反) in (列值1,列值2);
区间查询:
select * from 表名 where 列名 between 开始值 and 结束值;
模糊查询:
select * from 表名 where 列名 like ‘表达式’;(表达式必须是字符串)
通配符:_(下划线)代表任意一个字符 %代表0~n个字符
字段控制查询
去除重复记录:Select distinct 列名 from 表名;
查两列之和(横向运算,若列2的的值为null,则赋值为0):
select *,列1+ifnull(列2,0) as 自定义列名 from 表名;
null的比较运算不是通过=和!=来判断,而是用is null/is not null。
创建或覆盖视图
格式一:create or replace view 视图名称 as 查询语句;
格式二:create view 视图名称 as 查询语句;
排序
select * from 表名 order by 列名 asc(默认升序,可省略)/desc(降序);
多列排序:当前面的列值相同时,才会按后面的列值进行排序。
select * from 表名 order by 列1 asc,列2 desc;
聚合函数是用来做纵向运算的函数
select count(*) from 表名; 纵向统计排除null值
总和sum(*) 平均值avg(*) 计算数量count(*) 最大值max(*) 最小值min(*)
分组查询
select 可加列名,用作区分 sum(*) from 表名 group by 列名;
注意:如果查询语句中有分组操作,则select后面只能添加聚合函数和被分组的列名。
分组之前用where判定,分组之后用having进行过滤(分组条件)。
limit 开始下标,显示条数;
分页查询:limit (pageindex页码值-1) * pagesize每页显示条数,pagesize;
数据库的完整性:用来保证存放到数据库中的数据是有效的,即数据的有效性和准确性。(确保数据的完整性 = 在创建表时给表中添加约束)
完整性的分类:
实体完整性(行完整性)
主键约束:primary key:每个表中要有一个主键,且数据唯一,不能为null。
唯一约束:unique:数据不能重复。
自动增长:auto_increment:给主键添加自动增长的数值,列只能是整数类型。
域完整性(列完整性)
非空约束:not null 默认约束:default
引用完整性(关联表完整性)
外键约束:foreign key
create table 表名(字段列表,constraint 自定义外键名称 foreign key(外键字段) references 主键表名(主键字段));
建议:这些约束应该在创建表的时候设置,多个约束条件之间使用空格间隔。
追加约束:modify
alter table 表名 modity 字段名称 数据类型 约束关键字;
一对多关系建表原则:
在多的一方创建一个字段,字段作为外键指向一的一方的主键。
多对多关系建表原则:
需要创建第三张表,中间表中至少有两个字段,这两个字段分别作为外键指向各自一方的主键。
一对一关系建表原则:
唯一外键对应:假设一对一是一个一对多的关系,在多的一方创建一个外键指向一的一方的主键,将外键设置为unique。
主键对应:让一对一的双方的主键进行建立关系。
多表关系处理数据:
1、数据库通过外键建立两表关系
2、实体类通过属性的方式建立两表关系
实体类要求:类名=表名,列名=属性名
多表查询:
1.合并结果集:把两个select语句的查询结果合并到一起。
UNION(去重)、 UNION ALL(注意:列数、列类型必须相同才能合并)
2.连接查询:求多个表的乘积。
连接查询会产生笛卡尔积,假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1), (a,2),(b,0),(b,1),(b,2)}。
使用主外键关系作为条件去除无用信息
内连接 INNER JOIN ON
select 字段列表 from 表1 inner join 表2 on 消除笛卡尔积的条件;
外连接 OUTER JOIN ON
左外连接 LEFT [OUTER] JOIN
右外连接 RIGHT [OUTER] JOIN
全外连接 FULL JOIN(MySQL不支持)
自然连接 NATURAL JOIN
3.子查询:一个select语句中包含另一个完整的select语句。
三表联查:
select 列名 from 表1,表2,表3 where 表1.列名=表2.列名 and 表1/表2.列名=表3.列名;
now();获得当前系统时间
year(日期值);获得日期值中的年份
date_add(日期,inserval 计算值 计算的字段);
注意:计算值大于0表示往后推日期,小于0表示往前推日期。
数据库优化:
1.对查询进行优化,要尽量避免全表扫描,首先应考虑在where及order by涉及的列上建立索引。
2.应尽量避免在where子句中对字段进行null值判断,否则将导致引擎放弃使用索引而进行全表扫描。
3.应尽量避免在where子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描。
4.应尽量避免在where子句中使用or来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描。
5.in和not in也要慎用,否则会导致全表扫描。
事务:将多条SQL语句看作一个整体,要么一起成功,要么一起失败。
SQL语句
开启事务:start transaction;或 begin;
提交事务:commit;使得当前的修改确认
回滚事务:rollback;事务在未提交之前都是可以回滚的
java操作:
java是通过链接对象使用事务的,事务之间的隔离是基于链接描述的,默认情况下,JDBC的事务是自动提交的。
开启事务:Connection对象.setAutoCommit(false);
提交事务:Connection对象.commit();
回滚事务:Connection对象.rollback();
(面试)
事务的ACID特性:
原⼦性(Atomicity)事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。
⼀致性(Consistency)事务在执⾏之前和执行之后,数据库都必须处于⼀致性状态。
隔离性(Isolation)并发执行的各个事务是不能互相干扰的。
持久性(Duration)事务⼀旦提交,数据必须被永久保存。
(面试)
事务的并发问题
脏读:读取到了没有提交的数据,事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。
不可重复读:同⼀条命令返回不同的结果集(更新)。事务A多次读取同一数据,事务B在事务A多次读取的过程中,对数据做了更新并提交,导致事务A多次读取同一数据时,结果不一致。
幻读:重复查询的过程中,数据就发⽣了量的变化(insert,delete)。
(面试)
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交READ_UNCOMMITTED | 允许 | 允许 | 允许 |
读已提交READ_COMMITTED | 禁止 | 允许 | 允许 |
可重复读REPEATABLE_READ | 禁止 | 禁止 | 可能会 |
顺序读SERIALIZAB | 禁止 | 禁止 | 禁止 |
从上往下,级别越高,并发性越差,安全性就越来越高。⼀般数据默认级别是读已提交或可重复读。
(面试)
查看当前会话中事务的隔离级别:select @@tx_isolation;
修改隔离级别:set global transaction isolation level 隔离级别;
JDBC是一种用于执行SQL语句的java API,可以为多种关系数据库提供统一访问,它由一组用java语言编写的类和接口组成。
1.连接数据库。
2.创建SQL或MySQL语句。
3.在数据库中执行SQL或MySQL查询。
4.查看和修改生成的记录。
JDBC核心组件
DriverManager:此类管理数据库驱动程序列表,使用通信子协议将来自java应用程序的连接请求与适当的数据库驱动程序匹配。
Driver:此接口处理与数据库服务器的通信,我们很少会直接与Driver对象进行交互,而是使用DriverManager对象来管理这种类型的对象。
Connection:该界面具有用于联系数据库的所有方法,连接对象表示通信上下文即与数据库的所有通信仅通过连接对象。
Statement:使用从此接口创建的对象将SQL语句提交到数据库,除了执行存储过程之外,一些派生接口还接受参数。
ResultSet:在使用Statement对象执行SQL查询后,这些对象保存从数据库检索的数据。它作为一个迭代器,允许我们移动其数据。
SQLException:此类处理数据库应用程序中发生的任何错误。
Create、Read、Update and Delete通常称为CRUD操作。
RDBMS | JDBC驱动程序名称 | 网址格式 |
MYSQL8 | com.mysql.cj.jdbc.Driver | jdbc:mysql://hostname:3306/databaseName?serverTimezone=UTC |
MySQL | com.mysql.jdbc.Driver | jdbc:mysql://hostname:3306/databaseName |
ORACLE | oracle.jdbc.driver.OracleDriver | jdbc:oracle:thin:@hostname:port Number:databaseName |
DB2 | COM.ibm.db2.jdbc.net.DB2Driver | jdbc:db2:hostname:port Number / databaseName |
SYBASE | com.sybase.jdbc.SybDriver | jdbc:sybase:Tds:hostname:port Number / databaseName |
JDBC的连接步骤:
1、引入jar文件
2、加载数据库驱动(JavaSE项目中可以省略,JavaWeb项目必须编写此步骤)
Class.forName(“JDBC驱动程序名称”);
3、获取链接
Connection conn = DriverManger.getConnection(“jdbc:mysql://本机地址localhost:端口号3306/库名demo?useSSL=false&时区serverTimezone=UTC”,“账号”,“密码”);
4、创建状态通道
Statement state = conn.createStatement();
int resultSet = state.executeQuery(查);//.executeUpdate(增删改);
5、取出结果集信息
while(resultSet.next()){
//判断是否有下一条数据}
6、非空则关闭资源
if(conn/state/resultSet!=null){ conn/state/resultSet.close();}
SQL注入是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。
批处理:将多条SQL语句放在一起批量处理,每一条语句的成功和失败都与其它语句无关。
Statement的批处理使用:
将一条SQL语句加入批处理:Statement对象.addBatch(SQL语句);
执行批处理:Statement对象.executeBatch();
清空批处理:Statement对象.clearBatch();
PreparedStatement的批处理使用:
预编译时,存在?的话,可以通过多次的填充?来完成对多条相同语句的批处理添加。前提:
得到PreparedStatement对象:conn.prepareStatement(带有?的预编译语句);
填充预编译的参数:PreparedStatement对象.SetXXX(填充?);
把上面填充完毕?的内容添加到批处理:PreparedStatement对象.addBatch();
如需再次填充和添加,重复以上两步即可,最后执行、清空(同Statement)。
(面试)
对比Statement和PreparedStatement:
- Statement属于状态通道,PreparedStatement属于预状态通道。
- 预状态通道会先编译sql语句,再去执行,比statement执行效率高。
- 预状态通道支持占位符?,给占位符赋值的时候,位置从1开始。
- 预状态通道可以防止sql注入,原因:预状态通道在处理值的时候以字符串的方式处理。
数据连接池原理:连接池基本的思想是在系统初始化的时候,将数据库连接作为对象存储在内存中,当用户需要访问数据库时,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象;当使用完毕后,用户也并非将连接关闭,而是将连接放回连接池中,以供下一个请求访问使用。
最小连接数:数据库一直保持的数据库连接数,如果应用程序对数据库连接的使用量不大,将有大量的数据库资源被浪费。
初始化连接数:连接池启动时创建的初始化数据库连接数量。
最大连接数:连接池能申请的最大连接数,如果数据库连接请求超过此数,后面的数据库连接请求被加入到等待队列中。
最大等待时间:当没有可用连接时,连接池等待连接被归还的最大时间,超过时间则抛出异常,可设置参数为0或者负数使得无限等待(根据不同连接池配置)。
DBCP连接池
在项目的src文件夹下添加配置文件info.properties:
driverClassName = com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/demo
username=root
password=123456
initialSize=10 //初始化连接数
maxActive=50 //最大连接数
maxIdle=20 //最大空闲连接
minIdle=5 //最小空闲连接
maxWait=6000 //最大等待时间
public void test() throws SQLException{
// 硬编码,使用DBCP连接池
BasicDataSource source = new BasicDataSource();
// 设置连接的信息
source.setDriverClassName("com.mysql.jdbc.Driver");
source.setUrl("jdbc:mysql://localhost:3306/demo");
source.setUsername("root");
source.setPassword("123456");
Connection conn = source.getConnection();
String sql = "select * from student";
Statement state = conn.createStatement();
ResultSet rs = state.executeQuery(sql);
while (rs.next()) {
System.out.println(rs.getString(2));
}
conn.close(); //回收 }
C3P0连接池
C3P0是在外部添加配置文件,工具直接进行应用,因为直接引用,所以要求固定的命名和文件位置。
文件位置:src
文件命名:c3p0-confifig.xml/c3p0-confifig.properties
<?xml version="1.0" encoding="utf-8"?>
<c3p0-config>
<!-- 默认配置,如果没有指定则使用这个配置 -->
<default-config>
<!-- 基本配置 -->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/demo</pr
zoperty>
<property name="user">root</property>
<property name="password">123456</property>
<!--扩展配置-->
<!-- 连接超过30秒报错-->
<property name="checkoutTimeout">30000</property>
<!--30秒检查空闲连接 -->
<property name="idleConnectionTestPeriod">30</property>
<property name="initialPoolSize">10</property>
<!-- 30秒不适用丢弃-->
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
</default-config>
<!-- 命名的配置 -->
<named-config name="abc">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/demo</pr
operty>
<property name="user">root</property>
<property name="password">123456</property>
<!-- 如果池中数据连接不够时一次增长多少个 -->
<property name="acquireIncrement">5</property>
<property name="initialPoolSize">20</property>
<property name="minPoolSize">10</property>
<property name="maxPoolSize">40</property>
<property name="maxStatements">20</property>
<property name="maxStatementsPerConnection">5</property>
</named-config>
</c3p0-config>
定义代码:
Connection con=null;
ComboPooledDataSource db=new ComboPooledDataSource("abc");
public Connection getCon(){
try {
con=db.getConnection();
System.out.println("初始化的链接数量:"+db.getInitialPoolSize());
} catch (SQLException e) {
e.printStackTrace();
}
return con; }
C3P0与DBCP区别:
1、DBCP没有自动回收空闲连接的功能,C3P0有自动回收空闲连接功能。
2、DBCP需要手动设置配置文件,C3P0不需要手动设置。
Druid连接池
/**
* 阿里的数据库连接池
* 是目前比较流行的、高性能的分布式列存储的OLAP框架(具体来说是MOLAP)
* Druid(德鲁伊)
**/
public class DruidUtils {
//声明连接池对象
private static DruidDataSource ds;
static{
//实例化数据库连接池对象
ds = new DruidDataSource();
//实例化配置对象
Properties properties = new Properties();
try {
//加载配置文件内容
properties.load(DruidUtils.class.getResourceAsStream("dbcpconfig.properties"));
//设置驱动类全称
ds.setDriverClassName(properties.getProperty("driverClassName"));
//设置连接的数据库
ds.setUrl(properties.getProperty("url"));
//设置用户名
ds.setUsername(properties.getProperty("username"));
//设置密码
ds.setPassword(properties.getProperty("password"));
//设置最大连接数量
ds.setMaxActive(Integer.parseInt(properties.getProperty("maxActive")));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//获取连接对象
public static Connection getConnection() {
try {
return ds.getConnection();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null; } }