黑马程序员技术交流社区
标题:
【石家庄JavaEE就业六期]】数据库笔记
[打印本页]
作者:
信仰°
时间:
2018-1-11 15:27
标题:
【石家庄JavaEE就业六期]】数据库笔记
本帖最后由 小石姐姐 于 2018-1-12 10:49 编辑
数据库笔记
数据库
概念: 存储数据的仓库. 本质是一个文件系统, 数据按照指定的格式将数据存储起来, 用户可以对数据库中的数据进行增删改查
DBMS: Database Management System, 数据库管理系统. 是操作和管理数据库的大型软件, 用于建立, 使用和维护数据库, 对数据库进行统一管理和控制, 以保证数据库的安全性和完整性. 用户通过数据库管理系统访问数据库中表内的数据
常见数据库
MySQL
Oracle
数据库: 存储数据表
数据表: 存储记录
由行和列组成的
DBMS: 操作数据库
表和Java类的对应关系
表名: Java类名
列名: 成员属性名
记录: 类对象
MySQL
安装
配置和遇到的问题
命令行的登录和退出
登录: mysql -u 用户名 -
退出: exit
SQL基本语言
SQL的概念: Structured Query Language, 结构化查询语言
结构: 数据表是由行和列组成的, 是有结构的, 从这种结构中查询
SQL的4中分类
DDL: Data Defination Language, 数据定义语言, 用来定义数据库对象(库, 表等)
CREATE
ALTER
DROP
DML: Data Manipulation Language, 数据操作语言, 对表中的记录进行增, 删, 改
INSERT
UPDATE
DELETE
DQL: Data Query Language, 数据查询语言, 对表中的记录进行查
SELECT
FROM
WHERE
DCL: Data Control Language, 数据控制语言, 创建修改用户, 权限
SQL特点
SQL不区分大小写
一条SQL语句以;分号结尾, 一条语句可以多行书写
单词之间通过空格分隔, 参数之间通过,逗号分隔
字符串和日期要用''或""引起来, 建议单引号
SQL注释(2+1种)
2种单行注释
#单行注释
-- 单行注释: 减号后必须有一个空格
1种多行注释: /* 注释内容 */
SQL的数据类型
INT: 整数
`DOUBLE: 小数
`VARCHAR: 可变长度字符
`CHAR: 固定长度字符
其他看文档
VARCHAR和CHAR的区别:
VARCHAR(200), 可变长度字符, 存储占用的内存空间是可变的, 如果你的数据容量小于我们指定的空间大小, 那么就会按照实际的数据空间来开辟内存大小
优点: 节省内存
缺点: 因为每次存入数据时都会判断数据的实际大小, 来动态修改内存空间, 所以需要占用资源, 效率低
CHAR(200), 固定长度字符, 存储占用的内存空间是不可变的. 无论实际存入的数据容量是多大, 都占用这么大的空间
优点: 插入数据时不需要额外操作, 效率高
缺点: 可能会浪费空间
SQL对库的操作
创建库
使用默认字符集创建库: CREATE DATABASE 库名
默认是UTF-8编码
指定字符集: CREATE DATABASE 库名 CHARACTER SET '字符集';
删除库
DROP DATABASE 库名;
查看所有库
SHOW DATABASES;
使用库
USE 库名;
查看当前使用的库
SELECT DATABASE();
SQL对表的操作
创建表: CREATE TABLE 表名 (列名1 数据类型 约束, 列名2 数据类型 约束);
删除表: DROP TABLE 表名;
查看当前库中的所有表: SHOW TABLES;
修改表的结构: ALTER TABLE 表名 操作关键字 列名 数据类型 约束;
增加列: ALTER TABLE 表名 ADD 新列名 新数据类型 新约束;
删除列: ALTER TABLE 表名 DROP 列名
修改列的数据类型和约束(不能修改列名): ALTER TABLE 表名 MODIFY 列名 新数据类型 新约束;
修改列的列名, 数据类型, 约束: ALTER TABLE 表名 CHANGE 旧列名 新列名 新数据类型 新约束;
修改表名: RENAME TABLE 旧表名 TO 新表名;
SQL对记录的操作
增
一次插入一条记录: INSERT INTO 表名 (列1, 列2) VALUES (值1, 值2);
一次性插入一条记录(省略自增主键): INSERT INTO 表名 (非主键自增列1, 非主键自增列2) VALUES (值1, 值2);
一次插入所有列的记录(省略列名): `INSERT INTO 表名 VALUES (值1, 值2);
值的数量和顺序必须和表的列一致
一次插入多个记录(指定列): INSERT INTO 表名 (列1, 列2) VALUES (记录1值1, 记录1值2), (记录2值1, 记录2值2);
一次插入多个记录(省略列): INSERT INTO 表名 VALUES (记录1值1, 记录1值2), (记录2值1, 记录2值2);
删
删除符合条件的记录: DELETE FROM 表名 WHERE 条件;
删除所有记录: DELETE FROM 表名;
清空表: TRUNCATE TABLE 表名;
DELETE FROM 表名;和TRUNCATE TABLE 表名;的区别
DELETE, 逐条删除记录, 不会重置自增计数器
TRUNCATE, 删除表再重建, 会重置自增计数器
改
修改符合条件的记录: UPDATE 表名 SET 列名1=新值, 列名2=新值 WHERE 条件;
修改所有记录: UPDATE 表名 SET 列名1=新值, 列名2=新值;
查
查询指定列: SELECT 列名1, 列名2 FROM 表名;
查询所有列: SELECT * FROM 表名;
条件查询: SELECT 列名1, 列名2 FROM 表名 WHERE 条件;
运算符
比较运算符
=: 相等
<>或!=: 不等
>: 大于
<: 小于
>=: 大于等于
<=: 小于等于
BETWEEN...AND...: 在一个范围内(包含头和尾)
如: BETWEEN 0 AND 10
IN (): 在列表中, 满足列表中一个即可
如: IN (1, 3, 5)
IS NULL: 是空
LIKE '通配符': 模糊查询
%: 一个百分号可以表示任意个字符. 比如'王%', 王大锤, 王五
_: 一个下划线可以表示一个字符. 比如'王_', 只能匹配王五
逻辑运算符
AND: 与. 两边条件同时成立才成立
OR: 或. 两边条件只要有一个成立就成立
NOT: 非, 取相反结果
NOT BETWEEN ... AND ...: 不在范围内
NOT IN: 不在列表中
NOT LIKE: 不匹配
IS NOT NULL: 非空
去重: SELECT DICTINCT 列名1, 列名2 ... FROM 表名 WHERE 条件;
别名:
字段名 AS 别名
表名 AS 别名
高级SQL
排序
ORDER BY 列名 ASC|DESC;
注意:
默认顺序为升序ASC
WHERE在前, ORDER BY在后
聚合函数
用在SELECT后或HAVING后
COUNT(列名): 计算记录数量
NULL值不会被算入数量
SUM(列名): 将该列的值求总和
如果不是数字类型, 则结果为0
MAX(列名): 求该列值中的最大值
MIN(列名): 求该列值中的最小值
AVG(列名): 求该列所有值的平均值
如果不是数字类型, 则结果为0
分组
GROUP BY 列名 HAVING 条件;: 对查询结果集分组, 然后再按条件过滤
注意:
聚合函数与分组的使用效果
使用聚合函数后再进行分组, 才相当于汇总统计
SELECT zname, SUM(zmoney) FROM zhangwu GROUP BY zname;
不使用聚合函数的分组, 只有第一条记录的值
SELECT zname, zmoney FROM zhangwu GROUP BY zname;
HAVING和WHERE的区别
过滤时机不同
WHERE是在分组前先对查询结果进行过滤
HAVING是在查询结果分组后再次过滤
是否可跟随聚合函数不同
WHERE条件中不可使用聚合函数
HAVING条件中可以使用聚合函数
条件可用列名不同
HAVING条件中的列名必须是SELECT或GROUP BY中使用过的列名
WHERE条件中可以使用表的所有列名
JDBC
JDBC: Java数据库连接. SUN公司提供的接口, 用来让数据库厂商实现数据库操作的功能
数据库驱动: 就是JDBC的实现
JDBC开发步骤:
前提: 导包(数据库驱动)
步骤:
注册驱动
DriverManager.registerDriver(): 是真实的注册驱动的方法
因为驱动中实现了这个方法, 推荐我们使用:
Class.forName("数据库驱动的Driver实现类全类名")
获取连接:
Connection conn = DriverManager.getConnection(url, username, password)
获取执行平台:
Statement s = conn.createStatement();: 不安全的
PreparedStatement ps = conn.prepareStatement(String sql);: 可以防范SQL注入
设置参数:
占位符: ?, 即使是字符串, 也不要给问号加引号
void setObject(int index, Object obj)
index从1开始
执行SQL语句
Statement
增删改:int s.executeUpdate(String sql)
判断操作是否成功: 判断返回值是否>0则生效, 否则不成功
查:ResultSet rs = s.executeQuery(String sql)
思考: 判断操作是否成功: 是返回null呢还是调用.next()用是否为true判断?
PreparedStatement
增删改: int ps.executeUpdate();
判断操作是否成功: 判断返回值是否>0则生效, 否则不成功
查: ResultSet rs = ps.executeQuery();
处理结果
ResultSet
boolean next();: 将指针向后移动, 如果有下一个记录则true, 否则false
默认不执行的之后, 指针在第一条记录之前; 只有调用一次才能指向第一条: while (rs.next()) {}
String getString(String 列名): 获取指定列的值, 以String类型
Object getObject(String 列名): 获取指定列的值, 以Object类型
释放资源
resultSet.close()
preparedStatement.close()
statement.close()
connection.close()
SQL注入
原理: 拼接SQL导致用户的输入可以改变SQL的意义, Statement无法避免注入
超级密码: 1' OR '1=1
如何避免: 使用PreparedStatement替换Statement
JDBCUtils工具类的自定义
在静态代码块中初始化连接对象
定义方法获取连接对象, 释放资源
使用Properties配置文件
作用: 将配置信息从源代码中隔离, 达到可以直接修改配置文件, 而不用修改源代码的目的
配置文件的创建
在src目录下创建, 会自动在bin目录下生成
以.properties后缀结尾
配置文件的格式: 键值对, 一行一个键值对
读取配置文件
通过类加载器, 去加载bin目录下的配置文件
类加载器的获取:
获取类的字节码对象: 类名.class
通过类的字节码对象获取类加载器:ClassLoader 字节码对象.getClassLoader()
通过类加载器对象读取资源文件:InputStream getResourceAsStream(String 配置文件路径)
创建Properties对象:Properties p = new Properties();
通过该对象加载流(此时Properties对象才有数据):p.load(inputStream)
通过Properties对象获取属性值:String p.getProperty(String key)
DbUtils
是什么: 是Apache的Commons项目中的一个组件, 开源的工具类(第三方库)
三个核心类/接口
QueryRunner类: 提供操作SQL语句的API
QueryRunner(): 创建对象
int update(Connection conn, String sql, Object... param): 执行INSERT, DELETE, UPDATE语句, 同时传入占位符的参数值, 是可变参数
<T> T query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params): 执行SELECT查询, 并根据传入的结果集处理器来处理结果
ResultSetHandler接口: 定义SELECT操作后对结果集的操作方法, 可以将结果集转换为Java类
ArrayHandler类: 将结果集的第一条记录封装到一个Object[]数组中, 数组中的每一个元素就是该条记录中的每一列的值
ArrayListHandler类: 将结果集中的每一条记录都封装到一个Object[]数组中, 再将这些数组封装到List<Object[]>集合中
BeanHandler类: 将结果集中的第一条记录封装到一个指定的JavaBean中
BeanListHandler类: 将结果集中的每一条记录都封装到一个指定的JavaBean中, 再将这些JavaBean封装到List<T>集合中
ColumnListHandler类: 将结果集中指定的列的字段值, 封装到一个List集合. 用于竖向查一个列
ScalarHandler类: 获取单一结果, 用于聚合函数如SELECT COUNT(*) FROM 表的操作
MapHandler类: 将结果集的第一条记录封装到一个Map中. key是列名, value是第一条记录的每个字段的值
MapListHandler类: 将结果集的每一条记录封装到一个Map中. key是列名, value是第一条记录的每个字段的值. 然后再将这些Map封装到一个List中
DbUtils类: 用于关闭资源和事务处理
static void closeQuietly(Connection conn): 关闭连接, 内部处理了异常
DBCP连接池
Apache commons项目中的一个组件
作用: 提供连接池, 替代连接. 连接池可以存放多个连接, 反复使用, 而不用每次创建销毁, 提高效率, 节省资源
普通连接的弊端: 获取连接, 释放资源太消耗资源.
Sun公司提供了接口: javax.sql.DataSource接口: 连接池规范
连接池的实现:
DBCP
C3P0
Druid
DBCP
导包
commons-dbcp-x.x.jar
commons-pool-x.x.x.jar
BasicDataSource: 是DataSource接口的实现类
必选
BasicDataSource BasicDataSource(): 创建对象
void setDriverClassName(String name): 设置驱动类名
void setUrl(String url): 设置连接地址
void setUsername(String username): 设置用户名
void setPassword(String password): 设置密码
Connection getConnection(): 获取连接对象
可选
void setMaxActive(int n): 最大连接数量. 程序能够连接数据库的最大连接数量
void setMinIdle(int n): 最小空闲连接. 连接池中允许存在的最小空闲数量, 如果小于该数量, 则会创建新的连接, 直到满足该最小空闲连接数
void setMaxIdle(int n): 最大空闲连接. 连接池中允许存在的最大空闲数量, 如果超出该数量, 则超出的空闲连接会被真实关闭
void setInitialSize(int size): 初始化连接数. 连接池中最初的连接数
改写JDBCUtils
将注册驱动, 获取连接的代码修改为必选4项
将getConnection()方法替换为getDataSource()方法
用户登录注册案例
理解如何分析需求, 将其转换为不同的步骤
注册:
先检查用户名是否存在(SELECT)
如果存在: 注册失败, 提示更换用户名
如果不存在: 直接注册(INSERT INTO)
登录
查询用户表中是否有匹配的用户名和密码(SELECT)
如果存在: 用户已经注册且密码匹配, 登录成功
如果用户名不存在: 用户没有注册或, 登录失败
如果用户名存在, 密码不匹配: 登录失败
dao: 操作数据库的类
类名: XxxDao.java
什么是设计模式
对问题处理方式的总结经验, 形成了一种代码设计的模式, 按这种模式不会再出问题, 所以叫做设计模式
所有的设计模式都源于面向对象的思想
Java有23种设计模式
单例:
单一实例, single instance, singleton, 目的是保证这个类只存在一个唯一的对象
为什么叫饿汉式:
因为类一加载, 对象就已经创建了, 像一个饿汉见到吃的马上就吃
3个要点
把构造方法私有化
在类中定义一个静态的本类对象, 并且要初始化
提供一个静态的方法getInstance(), 获取单例对象
线程不安全的懒汉式单例
用于解决创建对象的问题
我们以前在创建对象时, 需要根据每个类的构造方法创建对象
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2