本帖最后由 小石姐姐 于 2018-1-12 10:49 编辑
数据库笔记
- 数据库
- 概念: 存储数据的仓库. 本质是一个文件系统, 数据按照指定的格式将数据存储起来, 用户可以对数据库中的数据进行增删改查
- DBMS: Database Management System, 数据库管理系统. 是操作和管理数据库的大型软件, 用于建立, 使用和维护数据库, 对数据库进行统一管理和控制, 以保证数据库的安全性和完整性. 用户通过数据库管理系统访问数据库中表内的数据
- 常见数据库
- 数据库: 存储数据表
- 数据表: 存储记录
- DBMS: 操作数据库
- 表和Java类的对应关系
- 表名: Java类名
- 列名: 成员属性名
- 记录: 类对象
- MySQL
- 安装
- 配置和遇到的问题
- 命令行的登录和退出
- 登录: mysql -u 用户名 -
- 退出: exit
- SQL基本语言
- SQL的概念: Structured Query Language, 结构化查询语言
- 结构: 数据表是由行和列组成的, 是有结构的, 从这种结构中查询
- SQL的4中分类
- DDL: Data Defination Language, 数据定义语言, 用来定义数据库对象(库, 表等)
- DML: Data Manipulation Language, 数据操作语言, 对表中的记录进行增, 删, 改
- DQL: Data Query Language, 数据查询语言, 对表中的记录进行查
- 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 库名
- 指定字符集: CREATE DATABASE 库名 CHARACTER SET '字符集';
- 删除库
- 查看所有库
- 使用库
- 查看当前使用的库
- 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...: 在一个范围内(包含头和尾)
- IN (): 在列表中, 满足列表中一个即可
- IS NULL: 是空
- LIKE '通配符': 模糊查询
- %: 一个百分号可以表示任意个字符. 比如'王%', 王大锤, 王五
- _: 一个下划线可以表示一个字符. 比如'王_', 只能匹配王五
- 逻辑运算符
- AND: 与. 两边条件同时成立才成立
- OR: 或. 两边条件只要有一个成立就成立
- NOT: 非, 取相反结果
- NOT BETWEEN ... AND ...: 不在范围内
- NOT IN: 不在列表中
- NOT LIKE: 不匹配
- IS NOT NULL: 非空
- 去重: SELECT DICTINCT 列名1, 列名2 ... FROM 表名 WHERE 条件;
- 别名:
- 高级SQL
- 排序
- ORDER BY 列名 ASC|DESC;
- 注意:
- 默认顺序为升序ASC
- WHERE在前, ORDER BY在后
- 聚合函数
- 用在SELECT后或HAVING后
- COUNT(列名): 计算记录数量
- SUM(列名): 将该列的值求总和
- MAX(列名): 求该列值中的最大值
- MIN(列名): 求该列值中的最小值
- AVG(列名): 求该列所有值的平均值
- 分组
- 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)
- 执行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
- 导包
- 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: 操作数据库的类
- 什么是设计模式
- 对问题处理方式的总结经验, 形成了一种代码设计的模式, 按这种模式不会再出问题, 所以叫做设计模式
- 所有的设计模式都源于面向对象的思想
- Java有23种设计模式
- 单例:
- 单一实例, single instance, singleton, 目的是保证这个类只存在一个唯一的对象
- 为什么叫饿汉式:
- 因为类一加载, 对象就已经创建了, 像一个饿汉见到吃的马上就吃
- 3个要点
- 把构造方法私有化
- 在类中定义一个静态的本类对象, 并且要初始化
- 提供一个静态的方法getInstance(), 获取单例对象
- 用于解决创建对象的问题
- 我们以前在创建对象时, 需要根据每个类的构造方法创建对象
|
|