一基本概念
-
关系型数据库和非关系型数据库
sql 和NoSql(not only sql)
-
MySql
是一个软件,是关系型数据库管理系统RDBMS Relational Database Management System
二安装
1、MySql 5.0版本的安装
-
下载压缩版本的安装包
-
配置系统变量,并在根目录下配置ini文件
[mysqld] basedir=D:\Program Files\mysql-5.7\ datadir=D:\Program Files\mysql-5.7\data\ port=3306 skip-grant-tables
-
以管理员模式运行cmd,并到bin目录下
-
安装mysql
mysqld -install
-
初始化数据文件
mysqld --initialize-insecure --user=mysql
-
启动mysql,并进入管理界面
net start mysql
mysql –u root –p
-
修改root密码
update mysql.user set authentication_string=password('123456') where user='root'and Host = 'localhost';
-
刷新权限
flush privileges;
-
修改 my.ini文件删除最后一句skip-grant-tables
-
重启
exit net stop mysql net start mysql
2、安装SQLyog或Navicat
字符集:utf-8
字符核对集:utf-8_general_ci
三数据库实操
1、基本sql语句在cmd的使用
net start mysql --启动数据库服务
net stop mysql -- 关闭数据库服务
exit --退出服务
mysql -u(root) -p(password) --进入管理界面
-------------------------------------------------
--所有的sql语句后面都要加分号“;”
show databases; --显示所有数据库
mysql> use onlinemall --使用某一个数据库
Database changed
mysql> show tables; --把某一个数据库中所有表显示
describe 某个表名 --描述某一个表
create database xxx --创建一个数据库
2、操作数据库
-
创建数据库
CREATE DATABASE [IF NOT EXISTS] school CHARACTER SET utf8 COLLATE utf8_general_ci --创建一个的数据库
-
删除数据库
DROP DATABASE [IF EXISTS] school -- 删除一个数据库
-
使用数据库
USE school
-
查看数据库
SHOW DATABASES
3、(列)数据类型
-
数值类型
- tinyint 相当于byte 1个字节
- smallint 相当于short 2个字节
- mediumint 3个字节
- int 相当于普通int 4个字节
- bigint 相当于long 8个字节
- float 4个字节
- double 8个字节
- decimal 字符串形式的浮点数, 金融计算
-
字符串类型
- char 字符串固定大小的 0~255
- varchar 可变字符串 0~65535 个字节
- tinytext 微型文本 2^8 - 1
- text 文本串 2^16 - 1
-
日期类型
- date YYYY-MM-DD
- time HH:mm:ss
- datetime YYYY-MM-DD HH:mm:ss 最常用
- timestamp 时间戳,从1970.1.1的毫秒数
- year 年份
-
null
- 没有值,未知
- 不要使用NULL进行运算,否则结果为空
4、字段属性
主键、非空、长度(int的长度和存储大小没关系)、Unsigned、自增、Zerofill
注意,字符串的Null和""是不一样的。
5、创建数据库
注意要在USE 数据库后选中才能直接执行。
公式:
CREATE TABLE [判断条件]`表名`(
`字段名` 字段类型 + 字段属性,
`字段名` 字段类型 + 字段属性,
`字段名` 字段类型 + 字段属性,
设置主键
)设置引擎,设置默认字符集
例子:
CREATE TABLE IF NOT EXISTS`teacher`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '老师编号',
`name` VARCHAR(10) NOT NULL DEFAULT '匿名' COMMENT '老师姓名',
--------设置默认值的时候和注释的时候,要用英文的单引号
`age` INT(3) NOT NULL DEFAULT '0' COMMENT '老师年龄',
PRIMARY KEY (`id`) -----设置主键要用括号括起来
)ENGINE=INNODB DEFAULT CHARSET=utf8 ---注意等号
相对/相反的常用命令:
SHOW CREATE DATABASE `onlinemall` --得到创建该数据库的语句
SHOW CREATE TABLE `users` --得到创建该表的语句
desc(describe) `表名` --得到某一个表的详细信息
6、修改删除表中字段
------------------------修改表-----------------------------
主关键字:
- alter
- rename as
- add
- drop
- modify\change
--修改表名
ALTER TABLE teacher RENAME AS teachers
--增加字段
ALTER TABLE `teachers` ADD `birthday` DATETIME NOT NULL
--删除字段
ALTER TABLE `teachers` DROP `birthday`
----改变字段
--modify不能重命名,但可以改变类型和约束
--change可以重命名,并可以改变类型和约束
ALTER TABLE `teachers` MODIFY age VARCHAR(3) NOT NULL
ALTER TABLE `teachers` CHANGE age age1 VARCHAR(3)
--删除表
DROP TABLE `teachers`
四、数据库管理
1、物理外键
**创建方式一:**在创建表的同时增加外键
CREATE TABLE `grade`(
`gradeID` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年级编号',
`name` VARCHAR(10) NOT NULL COMMENT '年级名称',
PRIMARY KEY (`gradeID`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
CREATE TABLE `teacher`(
`id` INT(10) NOT NULL DEFAULT '0' COMMENT '老师ID',
`name` VARCHAR(10) NOT NULL DEFAULT '匿名' COMMENT '老师姓名',
`age` INT(3) NOT NULL DEFAULT '0' COMMENT '老师年龄',
`gradeID` INT(10) NOT NULL COMMENT '老师所属的年级',
PRIMARY KEY (`id`),
KEY `FK_gradeID` (`gradeID`),--声明
CONSTRAINT `FK_gradeID` FOREIGN KEY (`gradeID`) REFERENCES `grade` (`gradeID`)
--添加约束,引用
)ENGINE=INNODB DEFAULT CHARSET=utf8
**创建方式二:**在已有的表的基础上增加外键
CREATE TABLE `grade`(
`gradeID` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年级编号',
`name` VARCHAR(10) NOT NULL COMMENT '年级名称',
PRIMARY KEY (`gradeID`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
CREATE TABLE `teacher`(
`id` INT(10) NOT NULL DEFAULT '0' COMMENT '老师ID',
`name` VARCHAR(10) NOT NULL DEFAULT '匿名' COMMENT '老师姓名',
`age` INT(3) NOT NULL DEFAULT '0' COMMENT '老师年龄',
`gradeID` INT(10) NOT NULL COMMENT '老师所属的年级',
PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
-----完成创建表后,用alter关键字和add关键字增加外键
ALTER TABLE `teacher`
ADD CONSTRAINT `FK_gradeID` FOREIGN KEY (`gradeID`) REFERENCES `grade` (`gradeID`)
2、DML语言
database manipulation language–数据库操作语言
insert语句
--公式:insert into 表名(字段名) values (‘值’,‘值……),(’值‘,’值‘,……)
---公式中字段名可以省略,但省略后要把所有的值全部填充上
INSERT INTO `student` (`name`,`age`,`test`)
VALUES ('傻22子',15,'slf'),
('憨11憨',18,'lsf')
update语句
--公式:update 表名 set 字段名=值,字段名=值 where 子句
--注意,如果不回where是非常危险的,会改变所有记录的值
UPDATE `student` SET `name`='aaa' WHERE id='11' AND age='12'
delete和truncate语句
delete:
--公式:delete from 表名 where 条件
--
DELETE FROM `student` WHERE id='34'
truncate:
--公式:truncate [table] 表名
TRUNCATE TABLE `student`
区别(当delete不加where条件子句的时候):
- truncate 会重新设置自增列 计数器会归零
- truncate 不会影响事务
delete删除问题:
- innoDB 自增列会重1开始 (存在内存中,断电即失)
- myisam 继续从上一个自增量开始 (存在文件中的,不会丢失)
select语句
关键字顺序
SELECT[ALL|DISTINCT|DISTINCTROW|TOP]
{
*|talbe.*|[table.]field1[AS alias1][,[table.]field2[AS alias2][,…]]}
FROM tableexpression[,…][IN externaldatabase]
[WHERE…]
[GROUP BY…]
[HAVING…]
[ORDER BY…]
[LIMIT offset,row_count]
基本语法:
--选择所有字段:
SELECT * FROM `student`
--选择特有字段
SELECT `id`,`name` FROM `student`
--起别名
SELECT `id` AS 编号,`name` AS 姓名 FROM `student` AS 学生表
--用concat函数连接结果
SELECT CONCAT('编号:',`name`) AS 编号列 FROM `student` AS 学生表
去重及表达式:
--去重关键字:distinct
SELECT DISTINCT `name` FROM `teacher`
-----------------------
--表达式
--数据库中的表达式种类:文本值、列、NULL、函数、计算表达式、系统变量
SELECT 8+9 AS 计算结果 --计算表达式
SELECT `age` + 1 AS 加1后的值 FROM `teacher` --列加上计算表达式
SELECT VERSION() --函数
SELECT @@auto_increment_increment --变量
3、where及模糊查询
逻辑运算符
运算符 | 语法 | 描述 |
---|---|---|
<> | 表示不等于 | |
and && | where a and b a && b | 与 |
or || | where a or b a || b | 或,会改变 A并B 的集合 |
Not ! | where not number=3 !(number=3) | 非 |
模糊搜索
运算符 | 语法 | 描述 | 注意点 |
---|---|---|---|
is null | where 字段名 is null | 如果记录为空则满足条件 | 空字符不是NULL |
is not null | |||
between | 是一个闭区间 | ||
like | where 字段名 like ‘具体匹配’ | 多字符匹配 | “_”代表一个字符,而“%”代表多个字符。like后面的条件必需用英文单引号包起来! |
in | where 字段名 in (‘值’,‘值’) | 查询记录在in括号里面的值 | 是精确匹配! |
4、联表查询join on语句
知识点:
- 七种join理论
- where条件与on条件的区别
- 多表联合查询
注意点:
- ambigious错误
--下面是查询商品已经有购买记录的需求
SELECT g.goodID, NAME
FROM `goods` AS g
LEFT JOIN `orders` AS o
ON g.goodID = o.goodID
WHERE o.goodID IS NOT NULL
5、自连接
- 可以理解为树结构
CREATE TABLE `school`.`category`(
`categoryid` INT(3) NOT NULL COMMENT 'id',
`pid` INT(3) NOT NULL COMMENT '父id 没有父则为1',
`categoryname` VARCHAR(10) NOT NULL COMMENT '种类名字',
PRIMARY KEY (`categoryid`)
) ENGINE=INNODB CHARSET=utf8 COLLATE=utf8_general_ci;
INSERT INTO `school`.`category` (`categoryid`, `pid`, `categoryname`) VALUES ('2', '1', '信息技术');
INSERT INTO `school`.`CATEGOrY` (`categoryid`, `pid`, `categoryname`) VALUES ('3', '1', '软件开发');
INSERT INTO `school`.`category` (`categoryid`, `PId`, `categoryname`) VALUES ('5', '1', '美术设计');
INSERT INTO `School`.`category` (`categoryid`, `pid`, `categorynamE`) VALUES ('4', '3', '数据库');
INSERT INTO `school`.`category` (`CATEgoryid`, `pid`, `categoryname`) VALUES ('8', '2', '办公信息');
INSERT INTO `school`.`category` (`categoryid`, `pid`, `CAtegoryname`) VALUES ('6', '3', 'web开发');
INSERT INTO `SCHool`.`category` (`categoryid`, `pid`, `categoryname`) VALUES ('7', '5', 'ps技术');
---爸爸找儿子,儿子找爸爸
SELECT a.categoryname AS 父亲栏,b.categoryname AS 儿子栏
FROM `category` AS a,`category` AS b
WHERE a.`categoryid` = b.pid
6、排序与分页
排序:
-- ASC是升序 ==》ascend 上升
-- DESC是降序 ==》 descend 下降
-- 不加关键字相当于升序,即相当于加了ASC
SELECT `name` AS 商品名,`price` AS 价格
FROM `goods`
ORDER BY `price` ASC
分页:
-- limit 第一个参数是分页起始值,也就是从哪个记录开始
-- 第二个参数是分页面的大小
-- 公式: LIMIT (当前页数 - 1) * 页面大小,页面大小
-- 总页数 = (总数据量大小 / 页面大小) 向上取整。(不是加1,因为整除的时候加1不行)
SELECT `name` AS 商品名,`price` AS 价格
FROM `goods`
ORDER BY `price` ASC
LIMIT 0,10
7、子查询与嵌套查询
-- 嵌套查询中,是从里面计算到外面的
SELECT `name` AS 已经有购买的商品名, `price` AS 价格
FROM `goods`
WHERE `goodID` IN (-- 子查询中,如果有多个记录,要用in,不能用 =
SELECT `goodID` FROM `orders`
)
8、常用函数与聚合函数
https://dev.mysql.com/doc/refman/5.7/en/sql-function-reference.html
常用函数:
--数学函数
SELECT ABS(-10)
SELECT CEILING(9.4)
SELECT FLOOR(9.4)
SELECT RAND()
SELECT SIGN(-10)
--字符处理函数
SELECT CHAR_LENGTH('钟包子')
SELECT CONCAT('你好','世界')
SELECT CHAR_LENGTH('钟包子')
SELECT CONCAT('你好','世界')
SELECT UPPER('zhongxiaohao')
SELECT LOWER('QQ.com')
--日间和日期函数
SELECT CURRENT_TIME() --22:46:01
SELECT CURRENT_DATE() --2020-11-10
SELECT CURDATE() --2020-11-10
SELECT NOW() --2020-11-10 22:45:36
SELECT LOCALTIME() --本地时间2020-11-10 22:46:26
SELECT SYSDATE() -- 系统时间2020-11-10 22:46:52
--- 下面都要用一个date对象为参数
SELECT YEAR(CURRENT_TIME())
SELECT MONTH(CURRENT_DATE())
SELECT DAY(CURDATE())
SELECT HOUR(NOW())
SELECT MINUTE(LOCALTIME())
SELECT SECOND(SYSDATE())
--系统
SELECT SYSTEM_USER() --root@localhost
SELECT USER() --root@localhost
SELECT VERSION() --5.7.15
聚合函数:
定义:聚合函数是对列中的一系列数据进行处理,返回单个统计值。针对表中一列或者多列数据的分析就称为聚合分析
-- count,sum,max,mim,avg
SELECT SUM(`price`) AS 订单产生的总价值
FROM `orders` o
INNER JOIN `goods` g
ON o.goodID = g.goodID
-- 重点:count(字段) 会忽略所有的NULL值
--count(*) 不会忽略所有的NULL值
--count(1) 不会忽略所有的NULL值
--- 的区别与联系
9、分组过滤
**出现报错:**mysql sql_mode=only_full_group_by
对于group by聚合操作,如果在select中的列没有在group by中出现,那么这个SQL是不合法的,因为列不在group by从句中,所以设置了sql_mode=only_full_group_by的数据库,在使用group by时就会报错,
既然知道了问题,那么修改这个配置就可以了,找到MySQL的配置文件,my.ini文件,手动添加进去:
sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
需要注意的一点是一定要添加在[mysqld]配置内,这样添加完后重启mysql才会生效,退出数据库:exit,重启命令:
-- 下面的功能是查找用户购买的最高价格的商品,并且最高价格要大于20元
-- 需要注意的是,如果条件中含有聚合函数,则只能用having,而不能用where
-- having是对结果进行二次过滤,如果查询的栏目中没有某个栏目,那个having不能引用该某个栏目
SELECT u.`userName`,`nickName`,`name`,MAX(`price`)
FROM `orders` o
INNER JOIN goods g
ON o.goodID = g.`goodID` --联合查询到商品的名字
INNER JOIN users u
ON o.userName = u.userName --联合来查询到用户的名字
GROUP BY u.`userName` --用用户名来分组
HAVING MAX(`price`) >= 20 --要满足最高价格大于20
-- HAVING u.`userName`='guest' --如果写成o.userName,则会提示找不到该栏目
五、扩展知识
1、数据库级别MD5加密算法
- MD5 信息摘要算法 message-digest algorithm
- 不可逆,只能正向加密
- 应用:对用户注册的密码进行MD5加密,然后放入数据库中。用户登录的时候,将其输入的密码进行MD5加密,和数据库中的暗文进行匹配。可以进行二次加密。
-- 语法:直接调用Mysql内置的函数即可
SELECT MD5('你好吧')
2、事务
1、基本概念
参考博文:https://blog.csdn.net/dengjili/article/details/82468576
事务管理的四个基本特点(ACID):
-
原子性(Atomicity)
事务的操作要么全部发生,要么全部不发生
-
一致性(Consistency)
事务提交前后,数据完整性一致(如转钱,钱总数不变)
-
隔离性(Isolation)
不同事务之间互不干扰
-
持久性(Durability)
事务提交后,对数据的改变是永久的
由于隔离性带来的三个读取问题:
-
脏读(read out of invaild data)
一个事务读取了别一个未提交的事务的数据
-
不可重复读
一个事务多次读取同一个数据,多次读取的结果不同
-
虚读/幻读(phantom read)
一个事务内读取了别的事务插入的数据,导致前后读取不一致。(一般是行影响,多了一行)
2、语法
SET autocommit = 0; ------设置事务自动提交关闭
START TRANSACTION --事务开始
UPDATE `student` SET `name`='黄' WHERE id='1' --一旦执行,数据库的数据会立即变,但没有持久化
UPDATE `student` SET `age`='19' WHERE id='1'
COMMIT --提交事务
ROLLBACK --事务回滚
SET autocommit = 1 --设置事务自动提交开启
3、索引
相关文章:http://blog.codinglabs.org/articles/theory-of-mysql-index.html
索引分类:
-
主键索引
- 唯一的标识,不可重复,只能有一个列作为索引
-
唯一索引
- 记录不可重复(除了NULL以外),但一个表中可以有多个 唯一索引
-
常规索引
- 没有任何限制
-
全文索引
- 在特定的数据库引擎都有,MyISAM有
- 快速定位数据
语法:
-- 总共有三种方式可以创建索引
-- ---------------方法一:在创建表的时候定义索引----------------------------
CREATE TABLE `test`(
`id` INT(10) NOT NULL,
`name` VARCHAR(20) NOT NULL,
`age` INT(100) NOT NULL,
`address` VARCHAR(30) NOT NULL,
PRIMARY KEY(`id`), --主键索引
UNIQUE `name`(`name`), --唯一索引
KEY `age`(`age`), --普通索引,也可以用INDEX,等效于KEY
FULLTEXT `address`(`address`)--全文索引用int类型会报错(不知道为什么)
)ENGINE=INNODB DEFAULT CHARSET=utf8
-- --------------------方法二:利用create语句------------------------
CREATE UNIQUE INDEX indexName ON mytable(username(length))
CREATE UNIQUE INDEX `name` ON `test`(`name`(2))
CREATE INDEX `age` ON `test`(`age`)
CREATE FULLTEXT INDEX `name` ON `test`(`name`)
-- ---------方法三:利用alter语句-------------------
ALTER TABLE tbl_name ADD PRIMARY KEY (column_list)-- 该语句添加一个主键,这意味着索引值必须是唯一的,且不能为NULL。
ALTER TABLE tbl_name ADD UNIQUE index_name (column_list)-- 这条语句创建索引的值必须是唯一的(除了NULL外,NULL可能会出现多次)。
ALTER TABLE tbl_name ADD INDEX index_name (column_list)--添加普通索引,索引值可出现多次。
ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list)--该语句指定了索引为 FULLTEXT ,用于全文索引。
ALTER TABLE `test` ADD INDEX `name`(`name`)
ALTER TABLE `test` ADD PRIMARY KEY `id`(`id`)
其它:
- explain 用于分析执行的sql语句
- show index from table_name 显示表中所有的索引
- DROP INDEX [indexName] ON mytable; 删除索引
索引原则:
- 索引不是越多越好
- 不要对经常变动的数据加索引
- 小数据量的表不需要加索引
- 索引一般加在常用来查询的字段上
4、用户管理
-- 创建用户
CREATE USER testUser2 IDENTIFIED BY '232323'
-- 修改密码(修改当前密码)
SET PASSWORD = PASSWORD('123456')
--- 修改密码(给特定用户)
SET PASSWORD FOR testUser2 = PASSWORD('232323')
--- 给用户重命名
RENAME USER testUser2 TO testUser3
---给用户授权 库.表
GRANT ALL PRIVILEGES ON *.* TO testUser3
---查询权限
SHOW GRANTS FOR testUser3
---撤销权限
REVOKE ALL PRIVILEGES ON *.* FROM testUser3
---删除用户
DROP USER testUser3
5、备份
方式一: 直接拷贝data目录(物理文件)
方式二: 可视化操作
方式三: 命令行
-- 导入数据库
-- mysqldump -h服务器地址(可远程) -u -p 数据库名 【表1 表2】 > 物理地址
mysqldump -hlocalhost -uroot -p123456 school grade student > d:/school.sql
-- 导入数据库
--------------方式1-----------------
--1.登入数据库管理界面
--2.用source + 物理文件地址
--(注意:如果导入表要在要导入的数据库下,但一般sql文件里面都可能自带有创建数据库的语句)
--------------方式2-----------------
-- -h参数可以省略
mysql -hlocalhost -uroot -p123456 < C:\Users\aj\Desktop\2.sql
6、三大范式(NF:normalform)
范式基本概念:
-
1NF
数据库要体现原子性,列中的数据要不可再分
-
2NF
一张表只做一件事。不产生局部依赖:对于联合主键而言,非主键的字体不能只完全依赖于其中一个主键,如果只依赖其中一个主键,那么这张表可以拆分成两个表,即原来的表做了“两件事“。
-
3NF
数据中的每一列都要与主键直接相关,而不能通过其它字段传递依赖而间接相关。
第二范式和第三范式的区别:
----来源:百度知道
第二范式(bai2NF)和第三范式(3NF)的概念很容易混淆,du区分它们zhi的关键点在于,2NF:非主键列是否完全依dao赖于主键,还是依赖于主键的一部分;3NF:非主键列是直接依赖于主键,还是直接依赖于非主键列。
第二范式(2NF):首先是 1NF,另外包含两部分内容,一是表必须有一个主键;二是没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。考虑一个订单明细表OrderDetail其属性如下: (OrderID,ProductID,UnitPrice,Discount,Quantity,ProductName)。
因为我们知道在一个订单中可以订购多种产品,所以单单一个OrderID 是不足以成为主键的,主键应该是(OrderID,ProductID)。显而易见 Discount(折扣),Quantity(数量)完全依赖(取决)于主键(OderID,ProductID),而 UnitPrice,ProductName 只依赖于 ProductID。所以 OrderDetail 表不符合 2NF。不符合 2NF的设计容易产生冗余数据。可以把OrderDetail表拆分为:
OrderDetail(OrderID,ProductID,Discount,Quantity)
Product (ProductID,UnitPrice,ProductName)
来消除原订单表中UnitPrice,ProductName多次重复的情况。
第三范式(3NF):首先是 2NF,另外非主键列必须直接依赖于主键,不能存在传递依赖。即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。考虑一个订单表Order: (OrderID,OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity)主键是(OrderID)。
其中OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity
等非主键列都完全依赖于主键(OrderID),所以符合 2NF。不过问题是CustomerName,CustomerAddr,CustomerCity 直接依赖的是
CustomerID(非主键列),而不是直接依赖于主键,它是通过传递才依赖于主键,所以不符合 3NF。
通过拆分Order为Order(OrderID,OrderDate,CustomerID)和Customer(CustomerID,CustomerName,CustomerAddr,CustomerCity)从而达到 3NF。
范式与性能之间的取舍:
- 在阿里规范中,关联查询的表不得超过3张表
- 在商业化的需求中,为了用户体验数据库的性能更加重要
- 有时会故意增加一些冗余的字段,使多表查询变成单表查询
- 故意增加一些计算列,从大数据量降低为小数据量。比如增加一个count列,如果要统计数量,直接读取最后一行记录即可。
范式与反范式的优缺点:
范式 | 反范式 | |
---|---|---|
优点 | 结构合理,避免冗余数据的产生。数据表更新快体积小。 | 考虑性能,满足需求,减少表的关联 |
缺点 | 查询时要对更多的表进行关联查询,性能低。 | 存在大量数据冗余,维护成本更高 |
(更新与查询间进行比较)
7、数据库的设计
六、JDBC
1、基本概念
- JDBC:Java DataBasse Connectivity 是一套规范,为开发者能如何、更好地访问数据库而设计的一套规范。
- 执行原理:用户程序 --> JDBC --> 数据库驱动(不同厂商有不同驱动) --> 数据库
- JDBC驱动程序:是对JDBC规范的完整的实现,它的存在在Java程序与数据库系统之间建立了一条通信的渠道。
2、基本语法
步骤:
- 加载驱动
- 根据信息建立连接
- 得到执行语句对象
- 关闭连接
//加载驱动
Class.forname("com.mysql.jdbc.Driver");
//根据信息,建立连接
String url = "jdbc:mysql://localhost/onlinemall?useSSL=true&useUnicode=true&characterEncoding=utf8";
String user = "roog";
String password = "123456";
Connection con = DriverManager.getConnection(url , user, password);
/** 上面步骤是共性 **/
/********************************************************/
//得到执行语句对象有两种
//第一种,普通sql语句处理对象
String sql = "selece * from `goods` where `price` >= 30";
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(sql);
while (rs.next()) {
操作};
//第二种,预编译语句处理对象
String sql = "selece * from `goods` where goodName = ?";
PreparedStatement pst = con.preparedStatement(sql);
pst.setString(1, "牛奶");
ResultSet rs = pst.executeQuery();
while (rs.next()) {
操作};
/********************************************************/
//释放连接
con.close();
st.close();
pst.close();
3、事务
con.setAutocommit(false);//mysql默认自动提交事务,要先关闭。
//同时,关闭自动提交,则相当于自动开启事务
执行代码。。。。。。。
con.commit();
con.rollback();
con.autocommit(true);
4、连接池
全部都要实现DataSource接口
1.DBCP
用到的依赖包:
commons-dbcp2-2.8.0.jar
commons-logging-1.2.jar
commons-pool2-2.9.0.jar
配置文件:
########DBCP配置文件##########
#驱动名
driverClassName=com.mysql.jdbc.Driver
#url
url=jdbc:mysql://localhost:3306/school?useSSL=true&useUnicode=true&characterEncoding=utf8
#用户名
username=root
#密码
password=123456
#初试连接数
initialSize=30
#最大活跃数
maxTotal=30
#最大空闲连接数,用完之后先不释放,看有没有人用,到一定时间后释放
maxIdle=10
#最小空闲连接数
minIdle=5
#最长等待时间(毫秒)
maxWaitMillis=1000
#程序中的连接不使用后是否被连接池回收(该版本要使用removeAbandonedOnMaintenance和removeAbandonedOnBorrow)
#removeAbandoned=true
removeAbandonedOnMaintenance=true
removeAbandonedOnBorrow=true
#连接在所指定的秒数内未使用才会被删除(秒)(为配合测试程序才配置为1秒)
removeAbandonedTimeout=1
Java实现:
InputStream in = test.class.getClassLoader().getResourceAsStream("dbcp.properties");//从类加载器中拿到配置文件资源
Properties properties = new Properties();//new一个配置文件实例
properties.load(in);//加载资源
//根据配置文件创建工厂
DataSource dataSource = BasicDataSourceFactory.createDataSource(properties);
//拿到链接
Connection con = dataSource.getConnection();
/** 之后的操作和普通jdbc一样 **/
所有的连接池都有DateSource.getConnection()方法
2.C3P0
用到的依赖包:
c3p0-0.9.5.5.jar
mchange-commons-java-0.2.19.jar
xml配置文件:
(也可以在Java里面进行配置,但不建议,因为又发生又偶合)
<c3p0-config>
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/school?useSSL=true&useUnicode=true&characterEncoding=utf8</property>
<property name="user">root</property>
<property name="password">123456</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property><!--最大可创建的statement对象-->
</default-config>
<!-- 可以有不同的数据库配置 -->
<named-config name="intergalactoApp">
<property name="acquireIncrement">50</property>
<property name="initialPoolSize">100</property>
<property name="minPoolSize">50</property>
<property name="maxPoolSize">1000</property>
</named-config>
</c3p0-config>
Java代码实现:
ComboPooledDataSource dataSource = new ComboPooledDataSource();//可以传入参数,代表其它named-config数据库配置
Connection con = dataSource.getConnection();