文章目录
前言
本文为学习狂神的mysql做的笔记。
其中前半截参考文章:
狂神说Mysql 和 狂神说MySQL学习笔记
事务部分参考:事务的四个特性和隔离级别;
JDBC参考:MySQL学习笔记(狂神说Java)
1 初识MySQL
-
JavaEE:企业级Java开发 Web
-
前端(页面:展示:数据)
-
后台 (连接点:连接数据库JDBC,连接前端(控制视图跳转,给前端传递数据))
-
数据库(存数据,Txt,Excel,Word)
-
只会写代码,学好数据库,基本混饭吃:
-
操作系统,数据结构与算法!当一个不错的程序猿!
-
离散数学,数字电路,体系结构,编译原理。+实战经验,优秀程序猿
-
1.1 为什么学数据库
-
岗位需求
-
现在的世界,大数据时代,得数据者得天下
-
被迫需求:存数据
-
数据库是所有软件体系中最核心的存在 DBA
1.2 什么是数据库
-
数据库:(DB,DataBase)
-
概念:数据仓库,软件,安装在操作系统之(windows,Linux。mac)上的!SQL,可以存储大量的数据,500万!
-
作用:存储数据,管理数据 Excel
-
1.3 数据库分类
-
关系型数据库:(SQL)
- MySQL, Oracle, sql Server, DB2, SQLite
- 通过表和表之间,行和列之间的关系进行数据的存储
-
非关系型数据库:(NoSQL) Not Only SQL
- Redis, MongDB
- 非关系型数据库,对象存储,通过对象自身的属性来决定。
-
DBMS(数据库管理系统)
- 数据库的管理软件,科学有效的管理我们的数据,维护和获取
MySQL ,数据管理系统!
- 数据库的管理软件,科学有效的管理我们的数据,维护和获取
1.4 MySQL简介
-
MySQL是一个关系型数据库管理系统
-
发展史:
-
前世: 瑞典MySQL AB 公司
-
今身: 属于 Oracle 旗下产品
-
-
MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。
-
开源的数据库软件
-
体积小,速度快,总体拥有成本低,招人成本比较低。
-
中小型网站,或者大型网站,集群
-
官网: https://www.mysql.com/
1.5 安装MySQL
- 具体安装步骤见MySQL安装(MySQL 8.0 zip压缩包版本)
1.6 安装SQLyog
- 安装软件包和安装步骤详见:https://blog.csdn.net/lihua5419/article/details/73881837/
1.7 连接数据库
(这几个命令测试下)
mysql -u 用户名(例:root) -p --连接数据库
show databases -- 查看所有的表
use school;-- 使用数据库
show tables; -- 显示该数据库所有的表
describe student; -- 查看该表的信息
CREATE DATABASE `school`CHARACTER SET utf8 COLLATE utf8_general_ci; -- 创建数据库
-- 这是sql的当行注释
/*
这是sql的多行注释
*/
2 DDL定义数据
- 操作数据库,操作数据库中的表,操作数据库表中的数据
2.1 操作数据库
- 关键字需要背
-- 创建数据库
CREATE DATABASE IF NOT EXISTS school1;
-- 删除数据库
DROP DATABASE IF EXISTS school1;
-- ` 是tab键上面的特殊字符,当出现关键字和名字相同的时候使用。当然,很不建议用关键字做表名或者列名啦。
CREATE DATABASE `CREATE` CHARACTER SET utf8 COLLATE utf8_general_ci;
2.2 数据库的列类型
-
数据类型:
- tinyint:十分小的数据,1个字节
- smallint:教小的数据,2个字节
- mediumint:中等大小的数据,3个字节
- int:标准的使用,4个字节
- bigint:大数据,8个字节
- float:浮点数,4个字节
- double:双精度的浮点数。8个字节
- deciaml:字符串形式的浮点数,常用
-
字符串:
-
char:固定字符串大小,0-255
-
varchar:可变字符串,2^16 - 1,常用**
-
text:文本串,2^16 - 1
-
-
时间类型:
- date:YYYY-MM-DD
- time:HH:mm:ss
-datetime:YYYY-MM-DD HH:mm:ss 最常用的时间格式 - timestamp:时间戳,1970.1.1至今的毫秒数
-
null:
- 代表没有值,注意是不要使用null进行计算,因为结果为null
2.3 数据库的字段属性
-
Unsigned
- 无符号整数,声明了该列不能声明为负数
-
Zerofill:
- 0填充,不足的位数,使用0来填充
-
自增:
- 自动在上一条记录的基础上+1
- 通常用来设计唯一的主键
- 可以在“高级”中更改每次自增的位数
-
null和not null:
- 如果某个字段设置为非空,却在插入或更新时不给它赋值,就会报错
- 如果某个字段设置为可以为空,在插入时不写值,该列会默认为null。
-
默认:
- 如果将sex字段的默认值设置为’男’,那在插入时不写该字段就会默认插入’男’。
-
拓展:根据阿里开发手册,建议每个表都有以下字段:
id :主键
version:乐观锁
is_delete:伪删除
gmt_create:创建时间
gmt_update:修改时间
2.4 创建数据库表
CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号id',
`name` VARCHAR(30) NOT NULL DEFAULT'匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',
`sex` VARCHAR(2) NOT NULL DEFAULT'女' COMMENT'性别',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`)
)ENGINE = INNODB DEFAULT CHARSET =utf8
-- 注意PRIMARY KEY (`id`)后需有()
格式:
CREATE TABLE IF NOT EXISTS `student`(
`列名1` 列类型 [属性1] [属性2],-- 最后一行不用加,
)ENGINE = INNODB DEFAULT CHARSET =utf8
-- 查看创建数据库的语句
SHOW CREATE DATABASE `school`;
-- 查看创建表的语句
SHOW CREATE TABLE `student`;
-- 查看表的结构
DESC `student`;
2.5 数据库引擎
ENGINE = INNODB
- 在物理空间下的区别:
- 所有的文件都在data目录下
- INNODB:在数据库中,只有一个*.frm文件,以及上级目录下的ibata1文件
- MYISAM:
- *.frm:表结构的定义文件
- *.MYD:数据文件(data)
- *.MYI:索引文件(index)
2.6 修改和删除表
- 注意:如果表名和列名不是关键字,那么加在表名或者列名上的``可以去掉。
-- 修改表的名字
ALTER TABLE `student1` RENAME AS `student`;
-- 增加表的字段
ALTER TABLE `student` ADD age1 INT(11);
-- modify修改约束
ALTER TABLE `student` MODIFY `name` VARCHAR(20);
-- change重命名:[旧名] [新名]
ALTER TABLE `student` CHANGE `age1` `age` INT(1);
-- 删除表的字段
ALTER TABLE `student` DROP age;
-- 删除表
DROP TABLE IF EXISTS `student`;
3 DML管理数据
3.1 外键(物理)
- 以下是物理外键(数据库级别的外键,就是在定义表的时候,把某个字段设置为外键),使用麻烦,不推荐使用,了解即可。通常使用逻辑外键(就是在表定义中看不出来这是个外键,但实际逻辑上这列是个外键)。
- 打个比方,学生表(学号,姓名,班号),班级表(班号,班级名称)。如果在定义学生表的时候,把班号设置成外键了,这就叫做物理外键或数据库级别的外键。如果没有特别设置外键,那么学生表的班号就是逻辑外键。
-- constraint 外键名 foreign key (本表列名) reference 其他表名(其他标列名)
ALTER TABLE `student`
ADD CONSTRAINT `FK_gradeId` FOREIGN KEY(`gradeId`) REFERENCES `grade`(`gradeId`);
3.2 DML语言(全背)
- 数据库管理语言:数据存储,数据管理
- insert
- update
- delete
3.3 insert插入数据
-
语法: insert into 表名 (列名1) values (数据1)
-
省略(列名)的话,后面的values必须一一对应,不能少也不能跳
-- 完成插入一个数据
INSERT INTO `grade`(gradeId,gradeName) VALUES(1,'大一');
-- 不写列名就会一一对应,不对应就会报错
INSERT INTO `grade` VALUES(2,'大二');
-- 插入多个数据:(),()
INSERT INTO `grade`(`gradeName`) VALUES('大三'),('大四');
3.4 修改
- where必须有,如果没有where,就会改变全部数据
- where后面的可以有多个条件
UPDATE `student` SET `name`='狂神' WHERE `id `=1;
3.5 删除
-
delete和truncate区别:
- delete删除时候
- InnoDB:自增列会从1开始(存到内存中)
- truncate:自增继续从上一个开始(存到文件中)
- truncate:重要,自增和计数器会归零
- delete删除时候
-- 删除单个数据列
DELETE FROM `student` WHERE `name` = '李四';
-- delete from 清空整个表,但是计数器不会归零。比如原来有2条数据,主键id从1到2,delete后重新插入主键是从3开始的。
DELETE FROM `test`;
-- truncate 清空整个表,自增,计数器会归零,不会影响事务。比如原来有2条数据,主键id从1到2,truncate后重新插入主键是从1开始的。
TRUNCATE `test`;
4 DQL查询数据(重点)
4.1 DQL
数据库中最核心,最重要的语句
select完整的语法:顺序不能出错
在这里插入图片描述
4.2 指定查询字段
-- 查询整张表的数据
SELECT * FROM student;
-- 查询指定数据,使用别名,也可以给表使用别名
SELECT `name` AS '学生姓名' FROM student;
-- 函数 concat(a,b):不影响源数据。
SELECT CONCAT('学生姓名:',`name`) AS '拼接的新名字' FROM `student`;
去重和select一些特殊的用法:
select distinct `gradeid` from `student`;
-- 查询MySQL版本号
SELECT VERSION();
-- 用于计算
SELECT 100*3;
-- select可以用来将int型的列加上某个值显示,但是不要试图对字符串的列使用+,其结果不是字符串的拼接,而是只剩了加的数字。比如:name列值cat,SELECT NAME+10 AS namee FROM student显示10.
SELECT `grade`+10 AS '成绩' FROM `student`;
4.3 where后逻辑表达式
- 与:
- and
- &&
- 或:
- or
- ||
- 非
- not
- !
4.4 模糊查询
-
重点是like结合%和_:
- % : 表示0到任意一个字符
- _:表示一个字符
-- 查询导演名字含有王
SELECT `actor_name` FROM `mtime_actor_t`
WHERE `actor_name` LIKE '%王%';
-- 查询名字姓匿,名一个单汉字或一个字母的。
SELECT * FROM student WHERE NAME LIKE '匿_'
- in的使用:
SELECT * FROM `mtime_field_t`
WHERE `hall_id` IN (1,2);
4.5 联表查询
- 常见的三种:
- 最全的七种:
-- 左查询,返回左边查询的所有值,即使右表没有匹配
SELECT `film_name`,`biography`
FROM `mtime_film_info_t` AS it
LEFT JOIN `mtime_film_t` AS ft
ON ft.`UUID`=it.`film_id`;
-- 右查询,返回右边查询的所有值,即使左表没有匹配
SELECT `film_name`,`biography`
FROM `mtime_film_info_t` AS it
RIGHT JOIN `mtime_film_t` AS ft
ON ft.`UUID`=it.`film_id`;
-- from a left join b
-- from a right join b
-- 永远都是:a是左表,b是右边
- 自连接:
4.6 分页排序
- 第一页:limit 0,5
- 第二页:limit 5,5
- 第n页:limit (n-1)*5,5
- 分页总结:
- n : 当前是第几页
- 页面大小pageSize : 5
- 初始下标:(n-1) pageSize*
- 总页数:查询出来的数据总数/pageSize
-- 排序:order by 字段名 asc/dec;
-- 分页:limit 起始下标,页数
4.7 子查询
- where里面嵌套一个(select查询语句)
4.8 分组和过滤
- 函数分组后使用having,having可以当成是使用了group by后替代where的。
4.9 select小结
5 函数
5.1 常用函数
-- 绝对值:19
select abs(-19);
-- 向上取整:3
select ceiling(2.3);-- 向上取整
-- 向下取整:2
select floor(2.1);-- 向下取整
-- 生成随机数
select rand();
select sign(-10);-- 判断一个数的符号 正数返回1,负数返回-1
-- 字符串长度: 9
select char_length('好好学习,天天向上');
-- 拼接字符串:学习
select concat('学','习');
-- 替换字符串,将第一个参数的字符串从第一个字(或字母)开始,到第二个字或字母结束,替换成第四个字符串:不爱dedeed爱学习
SELECT INSERT('我爱学习',1,1,'不爱dedeed');
-- 替换函数:将第一个参数的字符串里的第二个参数字符串的内容替换成第三个字符串。但如果第二个参数的字符串不是第一个参数字符串的一部分,则替换失败,还是显示第一个参数的字符串。
select replace('我爱学习','学习','java');
-- 反转函数:我爱学习
select reverse('习学爱我');
-- 三种获取当前日期
select current_Date();--2021-03-18
select curdate();--2021-03-18
select now();--2021-03-18 21:38:33
-- 本地时间
select LocalTime();
-- 系统时间
select SYSdate();
-- 年
select year(now());
-- 系统
select system_user();--root@localhost
select user();--root@localhost
select version();--8.0.13
5.2聚合函数
- 常见的聚合函数:count(),sum(),max(),min(),avg()
-- 指定列名去查,是会忽略null值:13
SELECT COUNT(seat_address) FROM `mtime_hall_dict_t`;
-- count(*)和count(1)是不会忽略null值:14
-- 查询条件中没有索引时,count(*)比count(1)查询速度要快些。
-- 查询条件中有索引时,count(1)比count(*)查询速度要快些。
SELECT COUNT(1) FROM `mtime_hall_dict_t`;
SELECT COUNT(*) FROM `mtime_hall_dict_t`;
5.3 MD5加密
-- 修改明文密码为md5加密
update md5_test set pwd= md5(pwd) where id = 1;
-- 插入数据时候,使用md5()
insert into md5_test values(3,'王五',md5('abcdefg'));
-- 如果是用户传入的明文密码,就要先加密成md5()然后与数据库的加密密码比对
select * from md5_test where id =1 and pwd = md5('123456');
6 事务
6.1 什么是事务?
-
概念:要么成功,要么都失败。将一组SQL放在一个批次中去执行。
-
事务原则:ACID原则(面试必问)
-
原子性(Atomicity):针对同一个事务。要么都成功,要么都失败
-
一致性(Consistency):事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。比如,当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统在运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是不一致的状态。
-
隔离性(Isolation):两个事务间的操作不影响。互不干扰。具体见MySQL事务隔离级别详解。该文详细介绍了四种事务隔离级别及其实现方式。
- 脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
- 不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
- 虚读(幻读):系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
- 小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
-
持久性(Durability):表示事务结束后的数据不会随着外界原因导致数据丢失。事务没有提交,就恢复到原状,事务一旦提交,就被持久化到数据库中,不可逆。
-
6.2 常用语法
-- 关闭自动提交
SET autocommit = 0;
-- 一个事务开启
START TRANSACTION;
或者
begin;
-- 写sql:crud
-- 提交事务
COMMIT;
-- 回滚事务
ROLLBACK;
-- 开启自动提交
SET autocommit = 1;
-- 存档
SAVEPOINT 保存名;
-- 回滚到保存点
ROLLBACK TO SAVEPOINT 保存名;
-- 撤销保存点
RELEASE SAVEPOINT;
模拟事务:
-- 创建数据库shop
CREATE DATABASE shop CHARACTER SET utf8 ;
-- 创建数据库表 account
CREATE TABLE account(
`id`INT(3) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) NOT NULL,
`money` DECIMAL(9,2) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE = INNODB DEFAULT CHARSET = utf8;
-- sql语句
INSERT INTO `account` VALUES(1,'张三',2000.00),(2,'李四',10000.00);
-- 模拟转账:
SET autocommit = 0;
-- 开启事务
START TRANSACTION;
UPDATE account SET money = money -500 WHERE id = 1;
UPDATE account SET money = money +500 WHERE id = 2;
-- 提交,数据永久被保存
COMMIT;
-- 回滚,回复默认值
ROLLBACK;
-- 开启自动提交(默认是自动提交)
SET autocommit = 1;
7 索引
- 索引(index)是可以快速提取数据的一种数据结构
7.1 索引的分类
- 主键索引(primary key):primary key(字段名)
- 唯一标志。主键索引只能有一个,不可重复,只能有一列作为主键
- 唯一索引(unique key):unique key 索引名 (字段名)
- 如果将A,B,C三列设置为唯一索引,则表里不能出现ABC三列都相同的记录。
- 可以有多个唯一索引,比如将ABC三列设为唯一索引 index1,将CD设置为唯一索引 index2。
- 常规索引 (key/index):key 索引名 (字段名)
- 默认的,index/key来设置
- 全文索引(FullText)FullText index 索引名 (字段名)
- 在特定的数据库才有,快速定位数据
基础语法:
- 在特定的数据库才有,快速定位数据
/*
索引的使用:
1.在创建表的时候给字段提交索引
2.创建完毕后,添加索引
*/
-- 显示一个表中的全部索引信息
SHOW INDEX FROM school;
-- 添加一个全文索引,大数据量下提高访问速度
ALTER TABLE student ADD FULLTEXT INDEX `index_name`(`name`);
-- explain 分析sql执行的状况
EXPLAIN SELECT * FROM student;-- 非全文索引
EXPLAIN SELECT * FROM student WHERE MATCH(`name`) AGAINST('张三');
7.2 测试索引
- 创建100万数据
- 注意:如果在用下面的函数插入100万条数据前,没有先执行:
SET GLOBAL log_bin_trust_function_creators=TRUE;
的话,会报如下错误:
ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you might want to use the less safe log_bin_trust_function_creators variable)
-- 建表
CREATE TABLE `app_user` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) DEFAULT '',
`eamil` VARCHAR(50) NOT NULL,
`phone` VARCHAR(20) DEFAULT '',
`gender` TINYINT(4) UNSIGNED DEFAULT '0',
`password` VARCHAR(100) NOT NULL DEFAULT '',
`age` TINYINT(4) DEFAULT '0',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4
-- 不执行下面这行的话,在下面用函数插入数据时会报错:
SET GLOBAL log_bin_trust_function_creators=TRUE;
-- 插入一百万条数据,$$写函数前必写
DELIMITER $$
CREATE FUNCTION mock_data()
RETURNS INT
BEGIN
DECLARE num INT DEFAULT 1000000;
DECLARE i INT DEFAULT 0;
WHILE i<num DO
INSERT INTO app_user(`name`,`eamil`,`phone`,`gender`,`password`,`age`)VALUES(CONCAT('用户',i),'1234567@qq.com',CONCAT('18',FLOOR(RAND()*((999999999-100000000)+10000000))),FLOOR(RAND()*2),UUID(),FLOOR(RAND()*100));
SET i = i+1;
END WHILE;
RETURN i;
END;
-- 执行定义的100万条数据函数, 用时48.795 sec
SELECT mock_data();
- 未使用索引时:
- 加索引
CREATE INDEX id_app_user_name ON app_user(`name`);
- 加索引后
-- 0.005 sec
SELECT * FROM app_user ;
-- 0.675 sec
SELECT * FROM app_user WHERE `name` = '用户10';
-- 0.611 sec
SELECT * FROM app_user WHERE `name` = '用户19999';
-- 分析 查了992786条数据才查到
EXPLAIN SELECT * FROM app_user WHERE `name` = '用户19999';
-- 创建索引语法: create index 索引名 on 表名(字段名)
CREATE INDEX id_app_user_name ON app_user(`name`);
-- 使用索引后的速度:查了1条数据,速度巨快
EXPLAIN SELECT * FROM app_user WHERE `name` = '用户19999';
7.3 索引原则
- 索引不是越多越好,索引在百万级以下就不使用
- 索引一般加载常用来查询的字段上。
- 索引是一个数据结构
- INNODB:默认是Btree
- 推荐自己去查找专题观看,学习这个数据结构
8 权限管理和备份
8.1 用户管理
- 使用SQLyog 创建用户,并授予权限演示
- 基本命令
/* 用户和权限管理 */ ------------------
用户信息表:mysql.user
-- 刷新权限
FLUSH PRIVILEGES
-- 增加用户 CREATE USER kuangshen IDENTIFIED BY '123456'
CREATE USER 用户名 IDENTIFIED BY [PASSWORD] 密码(字符串)
- 必须拥有mysql数据库的全局CREATE USER权限,或拥有INSERT权限。
- 只能创建用户,不能赋予权限。
- 用户名,注意引号:如 'user_name'@'192.168.1.1'
- 密码也需引号,纯数字密码也要加引号
- 要在纯文本中指定密码,需忽略PASSWORD关键词。要把密码指定为由PASSWORD()函数返回的混编值,需包含关键字PASSWORD
-- 重命名用户 RENAME USER kuangshen TO kuangshen2
RENAME USER old_user TO new_user
-- 设置密码
SET PASSWORD = PASSWORD('密码') -- 为当前用户设置密码
SET PASSWORD FOR 用户名 = PASSWORD('密码') -- 为指定用户设置密码
-- 删除用户 DROP USER kuangshen2
DROP USER 用户名
-- 分配权限/添加用户
GRANT 权限列表 ON 表名 TO 用户名 [IDENTIFIED BY [PASSWORD] 'password']
- all privileges 表示所有权限
- *.* 表示所有库的所有表
- 库名.表名 表示某库下面的某表
-- 查看权限 SHOW GRANTS FOR root@localhost;
SHOW GRANTS FOR 用户名
-- 查看当前用户权限
SHOW GRANTS; 或 SHOW GRANTS FOR CURRENT_USER; 或 SHOW GRANTS FOR CURRENT_USER();
-- 撤消权限
REVOKE 权限列表 ON 表名 FROM 用户名
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 用户名 -- 撤销所有权限
- 权限解释
-- 权限列表
ALL [PRIVILEGES] -- 设置除GRANT OPTION之外的所有简单权限
ALTER -- 允许使用ALTER TABLE
ALTER ROUTINE -- 更改或取消已存储的子程序
CREATE -- 允许使用CREATE TABLE
CREATE ROUTINE -- 创建已存储的子程序
CREATE TEMPORARY TABLES -- 允许使用CREATE TEMPORARY TABLE
CREATE USER -- 允许使用CREATE USER, DROP USER, RENAME USER和REVOKE ALL PRIVILEGES。
CREATE VIEW -- 允许使用CREATE VIEW
DELETE -- 允许使用DELETE
DROP -- 允许使用DROP TABLE
EXECUTE -- 允许用户运行已存储的子程序
FILE -- 允许使用SELECT...INTO OUTFILE和LOAD DATA INFILE
INDEX -- 允许使用CREATE INDEX和DROP INDEX
INSERT -- 允许使用INSERT
LOCK TABLES -- 允许对您拥有SELECT权限的表使用LOCK TABLES
PROCESS -- 允许使用SHOW FULL PROCESSLIST
REFERENCES -- 未被实施
RELOAD -- 允许使用FLUSH
REPLICATION CLIENT -- 允许用户询问从属服务器或主服务器的地址
REPLICATION SLAVE -- 用于复制型从属服务器(从主服务器中读取二进制日志事件)
SELECT -- 允许使用SELECT
SHOW DATABASES -- 显示所有数据库
SHOW VIEW -- 允许使用SHOW CREATE VIEW
SHUTDOWN -- 允许使用mysqladmin shutdown
SUPER -- 允许使用CHANGE MASTER, KILL, PURGE MASTER LOGS和SET GLOBAL语句,mysqladmin debug命令;允许您连接(一次),即使已达到max_connections。
UPDATE -- 允许使用UPDATE
USAGE -- “无权限”的同义词
GRANT OPTION -- 允许授予权限
/* 表维护 */
-- 分析和存储表的关键字分布
ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE 表名 ...
-- 检查一个或多个表是否有错误
CHECK TABLE tbl_name [, tbl_name] ... [option] ...
option = {QUICK | FAST | MEDIUM | EXTENDED | CHANGED}
-- 整理数据文件的碎片
OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...
8.2 MySQL备份
-
数据库备份必要性
- 保证重要数据不丢失
- 数据转移
-
MySQL数据库备份方法
- 使用命令行导出:命令:mysqldump
- 数据库管理工具,如SQLyog
- 直接拷贝数据库文件和相关配置文件
-
mysqldump客户端
-
作用 :
- 转储数据库
- 搜集数据库进行备份
- 将数据转移到另一个SQL服务器,不一定是MySQL服务器
注意:如果直接在mysqldump命令中输入密码,则-p和密码间不要空格,否则会报错的。
-
-- 导出
1. 导出一张表 -- mysqldump -hlocalhost -uroot -proot school1 student > D:/a.sql或者命令中不带密码mysqldump -hlocalhost -uroot -p school1 student > D:/aa.sql,待提示输入密码时再输入,这样安全。
mysqldump -h主机 -u用户名 -p密码 库名 表名 > 文件名(带路径的)(例如:D:/a.sql)
2. 导出多张表 -- mysqldump -uroot -proot school1 student teacher > D:/bb.sql
mysqldump -u用户名 -p密码 库名 表1 表2 表3 > 文件名(D:/a.sql)
3. 导出某个库所有表 -- mysqldump -uroot -proot school1 > D:/cc.sql
mysqldump -u用户名 -p密码 库名 > 文件名(D:/a.sql)
4. 导出一个库 -- >mysqldump -uroot -proot -B school1 > D:/e.sql
mysqldump -u用户名 -p密码 -B 库名 > 文件名(D:/a.sql)
5.可以-w携带备份条件:
mysqldump -hlocalhost -uroot -proot school1 student -w "id<4" > D:/m.sql
-- 导入
1. 在登录mysql的情况下:-- source D:/a.sql
source 备份文件
2. 在不登录的情况下
mysql -uroot -p < D:/e.sql命令
mysql -u用户名 -p密码 [库名] < 备份文件
注意:导入库里的表时该命令要加库名,如果是导入库,则不需要加库名。
- 注意1:再用sqlyog导入备份脚本时,需要选中一个数据库,如果是全库导入一个原本不存在的库的话,随便选一个库就好。否则会报1064错。
- 注意2:sqlyog用打开表看表里数据是会有缓存现象的,比如待条件备份表里部分数据,删表,重新导入备份数据,这时候如果用“打开表”查看数据,会发现是备份前的全量数据,而select查则只有备份的部分数据。在“打开表”那里点一下刷新,会发现只剩备份后恢复的数据了。估怀疑“打开表”有缓存。
9 规范化数据库设计
9.1 为什么需要数据库设计
-
当数据库比较复杂时我们需要设计数据库
-
糟糕的数据库设计 :
- 数据冗余,存储空间浪费
- 数据更新和插入的异常
- 程序性能差
-
良好的数据库设计 :
- 节省数据的存储空间
- 能够保证数据的完整性
- 方便进行数据库应用系统的开发
-
软件项目开发周期中数据库设计 :
- 需求分析阶段: 分析客户的业务和数据处理需求
- 概要设计阶段:设计数据库的E-R模型图 , 确认需求信息的正确和完整.
-
设计数据库步骤
-
收集信息
- 与该系统有关人员进行交流 , 座谈 , 充分了解用户需求 , 理解数据库需要完成的任务。
-
标识实体[Entity]
- 标识数据库要管理的关键对象或实体,实体一般是名词
- 标识每个实体需要存储的详细信息[Attribute]
- 标识实体之间的关系[Relationship]
-
9.2 三大范式
9.2.1 问题 : 为什么需要数据规范化?
-
不合规范的表设计会导致的问题:
-
信息重复
-
更新异常
-
插入异常
-
删除异常
- 丢失有效信息
-
9.2.2 三大范式的规定
-
第一范式 (1st NF)
- 第一范式的目标是确保每列的原子性,如果每列都是不可再分的最小数据单元,则满足第一范式
-
第二范式(2nd NF)
-
第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。
-
第二范式要求每个表只描述一件事情
-
-
第三范式(3rd NF)
-
如果一个关系满足第二范式,并且除了主键以外的其他列都不传递依赖于主键列,则满足第三范式.
-
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
-
9.2.3 规范化和性能的关系
- 关联查询的表,不得超过三张表,超过会影响查询效率。
- 考虑商业化的需求和目标(成本和用户体验), 数据库的性能更加重要。
- 在符合性能要求的前提下,需要适当的考虑一下规范性
- 为了提高性能,有时会故意给某些表加一些冗余的字段(从多表,变成单表),故意增加一些计算列
JDBC
10.1 数据库驱动
- 我们的程序会通过数据库驱动,和数据库打交道!
10.2 JDBC
-
SUN 公司为了简化开发人员(对数据库的统一)的操作,提供了一个(Java操作数据库的)规范:JDBC
-
这些规范的实现由具体的厂商去做,比如mysql、oracle
-
对于开发人员来说,我们只需要掌握JDBC的接口操作即可
- 需要导入的包有
- java.sql
- javax.sql
- 数据库驱动包:mysql-connector-java
10.3 第一个JDBC程序
- 创建测试数据库
CREATE DATABASE jdbcStudy CHARACTER SET utf8 COLLATE utf8_general_ci;
USE jdbcStudy;
CREATE TABLE `users`(
id INT PRIMARY KEY,
NAME VARCHAR(40),
PASSWORD VARCHAR(40),
email VARCHAR(60),
birthday DATE
);
INSERT INTO `users`(id,NAME,PASSWORD,email,birthday)
VALUES(1,'zhansan','123456','zs@sina.com','1980-12-04'),
(2,'lisi','123456','lisi@sina.com','1981-12-04'),
(3,'wangwu','123456','wangwu@sina.com','1979-12-04')
- 编写Java代码
- 1.创建一个普通项目
- 2.导入数据库驱动
- 3.编写测试代码
package mysql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class FirstJDBC {
public static void main(String[] args) throws Exception {
//1. 加载驱动
Class.forName("com.mysql.jdbc.Driver");//固定写法
//2. 用户信息和url
//useUnicode=true&characterEncoding=utf8&&useSSL=true
String url ="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&&useSSL=false";
String name = "root";
String password = "root";
//3. 连接成功,返回数据库对象 connection代表数据库
Connection connection= DriverManager.getConnection(url,name,password);
//4. 执行SQL的对象 statement 执行SQL的对象
Statement statement = connection.createStatement();
//5. 执行SQL的对象 去执行SQL 可能存在结果,查看返回结果
String sql="SELECT * FROM users";
ResultSet resultSet = statement.executeQuery(sql);//返回的结果集,结果集中封装了我们全部查询的结果
while(resultSet.next()){
System.out.println("id+"+resultSet.getObject("id"));
System.out.println("name+"+resultSet.getObject("NAME"));
System.out.println("password+"+resultSet.getObject("PASSWORD"));
System.out.println("email+"+resultSet.getObject("email"));
System.out.println("birthday+"+resultSet.getObject("birthday"));
}
//6. 释放连接
resultSet.close();
statement.close();
connection.close();
}
}
-
步骤总结:
-
1.加载驱动
-
2.连接数据库 DriverManager
-
3.获取执行SQL的对象 Statement
-
4.获得返回的结果集
-
5.释放连接
-
-
分解:
- 1.驱动:DriverManager
Class.forName("com.mysql.jdbc.Driver");//固定写法
Connection connection= DriverManager.getConnection(url,name,password);
//connection代表数据库
//数据库设置自动提交
connection.setAutoCommit();
//事务提交
connection.commit();
//事务回滚
connection.rollback();
-
- 2.URL
String url ="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&&useSSL=false";
-
- 3.获取执行SQL的对象 Statement
Statement statement = connection.createStatement();
-
- 4.执行SQL的对象
statement.executeQuery();
statement.execute();
statement.executeUpdate();//更新,插入,删除,返回一个受影响的行数
-
- 5.获得指定的数据类型
ResultSet resultSet = statement.executeQuery(sql);//返回的结果集,结果集中封装了我们全部查询的结果
resultSet.getObject();//在不知道列类型下使用
resultSet.getString();//如果知道则指定使用
resultSet.getInt();
-
- 6.遍历,指针
resultSet.previous();//移动到前一行
resultSet.next(); //移动到下一个
resultSet.beforeFirst();//移动到最前面
resultSet.afterLast();//移动到最后
resultSet.absolute(row);//移动到指定行
-
- 7.释放内存
resultSet.close();
statement.close();
connection.close();//耗资源
10.4 statement对象
- Jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
10.4.1 tatement对象的三种常用方法
- Statement对象的executeUpdate方法:用于向数据库发送增、删、改的sq|语句, executeUpdate执行完后, 将会返回一个整数(即增删改语句导致了数据库几行数据发生了变化)。也可以用来做create和drop,不过比较少,create和drop常用excute()方法。
- Statement.executeQuery多用来做select查询,executeQuery方法返回代表查询结果的ResultSet对象。
- Statement.execute:多用来做create和drop,也可以用来做insert、delete、update,不过比较少,insert、delete、update常用executeUpdate方法。
10.4.2 tatement对象的常用方法示例
- 使用executeUpdate(String sql)方法完成数据添加操作
Statement statement = connection.createStatement();
String sql = "insert into user(...) values(...)";
int num = statement.executeUpdate(sql);
if(num>0){
System.out.println("插入成功");
}
- 使用executeUpdate(String sql)方法完成数据删除操作
Statement statement = connection.createStatement();
String sql = "delete from user where id =1";
int num = statement.executeUpdate(sql);
if(num>0){
System.out.println("删除成功");
}
- 使用executeUpdate(String sql)方法完成数据修改操作
Statement statement = connection.createStatement();
String sql = "update user set name ='' where name = ''";
int num = statement.executeUpdate(sql);
if(num>0){
System.out.println("修改成功");
}
- 使用executeQuery(String sql)方法完成数据查询操作
Statement statement = connection.createStatement();
String sql = "select * from user where id =1";
ResultSet rs= statement.executeQuery(sql);
if(rs.next()){
System.out.println("");
}
10.4.3 tatement实战
10.4.3.1 提取工具类
- 编写配置文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&&useSSL=false
username = root
password = root
package mysql;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
private static String driver = null;
private static String url = null;
private static String username = null;
private static String password = null;
static {
try{
InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(in);
driver=properties.getProperty("driver");
url=properties.getProperty("url");
username=properties.getProperty("username");
password=properties.getProperty("password");
//1.驱动只用加载一次
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
//2.获取连接
public static Connection getConnection() throws Exception{
return DriverManager.getConnection(url, username, password);
}
//3.释放资源
public static void release(Connection conn, Statement st, ResultSet rs) throws SQLException {
if(rs!=null){
rs.close();
}
if (st!=null){
st.close();
}
if(conn!=null){
conn.close();
}
}
}
10.4.3.1 测试exectueUpdate
package com.kuang.lesson02.utils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import static com.kuang.lesson02.utils.JdbcUtils.*;
public class TestInnsert {
public static void main(String[] args){
Connection conn =null;
Statement st = null;
ResultSet rs =null;
try {
conn = getConnection();//获取连接
st = conn.createStatement();//获取SQL执行对象
String sql = "INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`)" +
"VALUES(5,'sanjin','123456','233223@qq.com','2020-01-01')";
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("插入成功");
}
JdbcUtils.release(conn,st,rs);
} catch (Exception e) {
e.printStackTrace();
}
}
}
10.4.3.1 测试executeQuery
package mysql;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import mysql.JdbcUtils;
public class TestSelect {
public static void main(String[] args) throws SQLException {
Connection conn =null;
Statement st = null;
ResultSet rs =null;
try {
conn = JdbcUtils.getConnection();//获取连接
st = conn.createStatement();//获取SQL执行对象
String sql = "select * from users";
rs=st.executeQuery(sql);//查询完毕返回结果集
while (rs.next()){
System.out.println(rs.getString("NAME"));
}
JdbcUtils.release(conn,st,rs);
} catch (Exception e) {
e.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
10.4.4 SQL注入问题
- sql存在漏洞,会被攻击导致数据泄露,例如:如下代码可以在不知道用户名和密码的情况下绕过用户名和密码校验:
package mysql;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import mysql.JdbcUtils;
public class TestSQLInjection {
public static void main(String[] args) {
//SQL注入
login("' or '1=1","' or '1=1");
}
public static void login(String name,String password){
Connection conn =null;
Statement st = null;
ResultSet rs =null;
try {
conn = JdbcUtils.getConnection();//获取连接
st = conn.createStatement();//获取SQL执行对象
String sql = "select * from users where `NAME`='"+ name +"' AND `PASSWORD`='"+ password +"'" ;
rs=st.executeQuery(sql);//查询完毕返回结果集
while (rs.next()){
System.out.println(rs.getString("NAME"));
}
JdbcUtils.release(conn,st,rs);
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
JdbcUtils.release(conn,st,rs);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
正是因为有者这样的问题,才有了下面的PreparedStatement对象
10.5 PreparedStatement
- PreparedStatement优点:
- 防止SQL注入:之所以PreparedStatement能防止SQL注入,是因为它把单引号转义了,变成了’
- 效率更高。
- PreparedStatement作用
- 作用和Statement大体相同:
- 新增
- 删除
- 查询
package mysql;
import mysql.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestPreparedStatement {
public static void main(String[] args) {
Connection connection= null;
PreparedStatement pstm=null;
try {
connection = JdbcUtils.getConnection();
//区别
//使用问好占位符代替参数
String sql = "insert into users(id,`NAME`) values(?,?)";
pstm = connection.prepareStatement(sql);//预编译sql,先写sql然后不执行
//手动赋值
pstm.setInt(1,8);
pstm.setString(2,"SANJIN");
//执行
int i = pstm.executeUpdate();
if (i>0){
System.out.println("插入成功");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
JdbcUtils.release(connection,pstm,null);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
10.6 使用IDEA连接数据库
- 设置中的问题:
- 测试连接时会提示没有下驱动文件,按提示下载即可。
- 测试连接时会提示:Server returns invalid timezone. Need to set ‘serverTimezone’ property.这是让设置时区的,选一个就好
- GMT(Greenwich Mean Time):格林威治标准时间
- UTC:世界标准时间
- CST(China Standard Time):中国标准时间
- GMT + 8 = UTC + 8 = CST
- 连接上后发现有属性选的不对,比如说连错数据库了,可以右击连接名,在属性里修改:
- 双击表名查询
- 修改
- 编写sql代码的地方(如何打开SQL编辑器)
10.7 JDBC事务
10.7.1 JDBC事务
-
要么都成功,要么都失败
-
ACID原则
-
原子性:要么全部完成,要么都不完成
-
一致性:结果总数不变
-
隔离性:多个进程互不干扰
-
持久性:一旦提交不可逆,持久化到数据库了
-
-
隔离性的问题:
-
脏读: 一个事务读取了另一个没有提交的事务
-
不可重复读:在同一个事务内,重复读取表中的数据,表发生了改变
-
10.7.2 代码实现
-
开启事务conn.setAutoCommit(false);
-
一组业务执行完毕,提交事务
-
可以在catch语句中显示的定义回滚,但是默认失败会回滚
package mysql;
import mysql.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
//测试事务
public class TestAction {
public static void main(String[] args) {
Connection conn =null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
//关闭数据库的自动提交功能, 开启事务
conn.setAutoCommit(false);
//自动开启事务
String sql = "update account set money = money-500 where id = 1";
ps =conn.prepareStatement(sql);
ps.executeUpdate();
int a= 1/0;
String sql2 = "update account set money = money+500 where id = 2";
ps=conn.prepareStatement(sql2);
ps.executeUpdate();
//业务完毕,提交事务
conn.commit();
System.out.println("操作成功");
} catch (Exception e) {
try {
//如果失败,则默认回滚
conn.rollback();//如果失败,回滚
} catch (SQLException throwables) {
throwables.printStackTrace();
}
e.printStackTrace();
}finally {
try {
JdbcUtils.release(conn,ps,rs);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
10.8 数据库连接池
-
数据库连接–执行完毕–释放
-
连接–释放:这两个动作十分浪费资源
-
池化技术: 准备一些预先的资源,过来就连接预先准备好的连接
-
参数如下:
- 常用连接数 100
- 最少连接数:100
- 最大连接数 : 120 业务最高承载上限
- 等待超时:100ms
-
编写连接池,实现一个接口DataSource
-
流行的开源数据源实现,使用了下面的数据库连接池后,我们在项目开发中就不需要编写连接数据库的代码了。
- DBCP
- C3P0
- Druid:阿里巴巴
10.8.1 DBCP代码实现
- 需要用到的jar包
- commons-dbcp-1.4
- commons-pool-1.6
- 1.在pom里导入依赖
<!-- https://mvnrepository.com/artifact/commons-dbcp/commons-dbcp -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-pool/commons-pool -->
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.6</version>
</dependency>
- 2.编写配置文件
配置文件全文如下:
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&&useSSL=false
username=root
password=root
#<!-- 初始化连接 -->
initialSize=10
#最大连接数量
maxActive=50
#<!-- 最大空闲连接 -->
maxIdle=20
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000
#JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;]
#注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=gbk
#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true
#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED
- 3.编写DBCP工具类
package mysql.jdbc;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils_DBCP {
private static DataSource dataSource = null;
static {
try{
InputStream in = mysql.JdbcUtils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
Properties properties = new Properties();
properties.load(in);
//创建数据源 工厂模式--》创建
dataSource = BasicDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws Exception{
return dataSource.getConnection(); //从数据源中获取连接
}
//释放资源
public static void release(Connection conn, Statement st, ResultSet rs) throws SQLException {
if(rs!=null){
rs.close();
}
if (st!=null){
st.close();
}
if(conn!=null){
conn.close();
}
}
}
- 4.编写测试类
package mysql.jdbc;
import mysql.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
public class TestDBCPInnsert {
public static void main(String[] args){
Connection conn =null;
Statement st = null;
ResultSet rs =null;
try {
conn = JdbcUtils_DBCP.getConnection();//获取连接
st = conn.createStatement();//获取SQL执行对象
String sql = "INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`)" +
"VALUES(7,'dog','123456','233223@qq.com','2020-01-01')";
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("插入成功");
}
JdbcUtils.release(conn,st,rs);
} catch (Exception e) {
e.printStackTrace();
}
}
}
10.8.2 C3P0代码实现
- 需要用到的jar包:
- c3p0-0.9.5.5
- mchange-commons-java-0.2.19
- 1.导入依赖
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
- 2.编写配置
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!--
C3P0的缺省(默认)配置,
如果在代码中“ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();”
这样写表示用的是C3P0的默认配置
-->
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">
jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
</default-config>
<!--
C3P0的命名配置:
如果在代码中“ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource(“mySource”);”
这样写表示使用的是name为mySource的配置
-->
<named-config name="mySource">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/school1</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
</named-config>
</c3p0-config>
- 编写工具类
package mysql.c3p0;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JdbcUtils_C3P0 {
private static DataSource dataSource = null;
static {
try{
//xml配置文件不需要读取,会自动加载
//创建数据源 工厂模式--》创建
dataSource = new ComboPooledDataSource();
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws Exception{
return dataSource.getConnection(); //从数据源中获取连接
}
//释放资源
public static void release(Connection conn, Statement st, ResultSet rs) throws SQLException {
if(rs!=null){
rs.close();
}
if (st!=null){
st.close();
}
if(conn!=null){
conn.close();
}
}
}
- 4.编写测试类
package mysql.c3p0;
import mysql.JdbcUtils;
import mysql.jdbc.JdbcUtils_DBCP;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
public class TestC3P0Insert {
public static void main(String[] args){
Connection conn =null;
Statement st = null;
ResultSet rs =null;
try {
conn = JdbcUtils_C3P0.getConnection();//获取连接
st = conn.createStatement();//获取SQL执行对象
String sql = "INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`)" +
"VALUES(9,'pig','123456','233223@qq.com','2020-01-01')";
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("插入成功");
}
JdbcUtils.release(conn,st,rs);
} catch (Exception e) {
e.printStackTrace();
}
}
}
10.8.3 总结
- 无论用什么数据源,本质还是一样的,都是实现的DataSource接口,所以方法不会变。