狂神說階段三——MySQL
原視訊網站
https://www.bilibili.com/video/BV1NJ411J79W?p=7&t=17
1.初始MySQL
javaEE:企業級java開發 Web
前端 (頁面:展示資料)
後臺 (連線點,連線資料庫JDBC,連線前端:控制檢視跳轉,給前端傳遞資料)
資料庫 (存資料 txt,excel...)
只會寫程式碼,學好資料庫,基本混飯吃(大部分程式設計師)
作業系統,資料結構與演算法,當一個不錯的程式設計師
離散數學,數位電路,體系結構,編譯原理,實戰經驗。高階程式設計師,不怕被幹掉的
1.1 為什麼學習資料庫
- 崗位需求
- 現在的世界,大資料時代,得資料者得天下(如精準營銷)
- 被迫需求:存資料(例去IOE"去掉IBM的小型機、Oracle資料庫、EMC儲存裝置")
- 資料庫是所有軟體體系中最核心的存在 DBA (資料庫管理員)
1.2 什麼是資料庫
資料庫(DB DataBase)
概念: 資料倉庫、是一個軟體、安裝在作業系統(windows,linux,mac...)之上
作用:儲存資料,管理資料
1.3 資料庫分類
- 關係型資料庫:SQL
- MySQL,Oracle,Sql Server,DB2,SQLlite
- 通過表和表之間,行和列之間的關係進行資料的儲存,學生資訊,考勤表...
- 非關係資料庫: (NoSQL)Not Only
- Redis,MonDB
- 物件儲存,通過物件滋生的屬性來決定
- DBMS資料庫管理系統
- 資料庫管理軟體,方便獲取和維護管理我們的資料
- MySQL 本質上是資料庫管理系統,可以管理我們的資料
1.4 MySQL簡介
(看簡介推薦去百度百科,然後抽取核心)
MySQL是一個關係型資料庫管理系統
前世:瑞典MySQL AB 公司開發
今生:Oracle 旗下產品
開源的,體積小、速度快、總體擁有成本低。(招人成本低,所以必須會)
中小型網站,或者大型網站(叢集)
https://www.mysql.com/
安裝建議(用的是穩定版5.7)
1.儘量不要使用exe,會修改登錄檔(解除安裝,可能寫在不乾淨)
2. 儘可能使用壓縮包安裝
mysql5.7 64位下載地址:
1.5 安裝
安裝步驟
1、下載後得到zip壓縮包,解壓
2、把這個包放到自己電腦環境目錄下
3、新增環境變數:我的電腦->屬性->高階->環境變數
選擇PATH,在其後面新增: 你的mysql 安裝檔案下面的bin資料夾
4、編輯 my.ini 檔案 ,注意替換路徑位置
[mysqld]
# 目錄一定要換成自己的
basedir = D:\Environment\mysql-5.7.19\
datadir = D:\Environment\mysql-5.7.19\data\
port=3306
skip-grant-tables
5、啟動管理員模式下的CMD,並將路徑切換至mysql下的bin目錄,然後輸入mysqld –install (安裝mysql)
6、再輸入 mysqld --initialize-insecure --user=mysql 初始化資料檔案
7、然後再次啟動mysql 然後用命令 mysql –u root –p 進入mysql管理介面(密碼可為空)
8、進入介面後更改root密碼
update mysql.user set authentication_string=password('123456') where user='root' and Host = 'localhost';
9、重新整理許可權
flush privileges;
10、修改 my.ini檔案刪除最後一句skip-grant-tables
11、重啟mysql即可正常使用
net stop mysql
net start mysql
12、連線上測試出現以下結果就安裝好了
安裝不成功執行 sc delete mysql 然後再重灌
1.6 安裝SQLyog(視覺化工具)
- 安裝註冊,預設的4個數據庫一個都不要動
- 新建一個數據庫
滑鼠右鍵點選操作,每一個sqlyog的操作本質上都是執行的sql語句,都可以在歷史記錄中檢視 - 新建一張表student
id,name,age
1.7 連線資料庫
命令列連線
所有語句都使用;結尾
mysql -uroot -p123456 --連線資料庫
update mysql.user set authentication_string=password('123456') where user='root'and Host = 'localhost';
--修改使用者密碼
flush privileges;--重新整理許可權
show databases;--檢視所有的資料庫
use DBname;--切換資料庫
show tables;--檢視資料庫中所有表
describe student;--顯示資料庫中所有的表的資訊
create database dbname;--建立資料庫
exit;--退出
--單行註釋(sql的註釋)
/*
多行註釋
*/
資料庫xxx語言
DDL 資料庫定義語言
DML 操作管理語言
DQL 查詢語言
DCL 控制
2. 操作資料庫
操作資料庫-》操作表-》操作表中資料
MySQL不區分大小寫
2.1 操作資料庫(瞭解)
1.建立資料庫
中括號項表示可選,大括號項表示必選
CREATE DATABASE [IF NOT EXISTS] westos
2.刪除資料庫
DROP DATEBASE [IF EXISTS] westos
3.使用資料庫
如果表名或者欄位名帶有特殊字元,需要帶`反引號
USE `school`
select `user` FROM student
- 檢視資料庫
show DATABASES--檢視所有的資料庫
學習思路:
- 對比 sqlyog視覺化操作,檢視歷史紀錄裡的sql語句來學習
- 固定語法或關鍵字必須要記住
2.2 資料型別
2.2.1 數值
- tinyint 十分小的資料 1個位元組
- smallint 較小的資料 2個位元組
- mediumint 中等大小的資料 3個位元組
- int 標準整數 4個位元組(常用的)
- big 較大的資料 8個位元組
- float 浮點數 4個位元組
- double 浮點數 8個位元組
注:int(M)M表示顯示的寬度,不是實際儲存範圍 - decimal 字串形式的浮點數 金融計算的時候,一般用decimal(常用)
2.2.2 字串
- char 固定大小的字串 0~255
- varchar 可變大小的字串 0~65535(用來存常用的變數,對應java中string)
- tinytext 微型文字 2^8-1
- text 文字串 2^16-1 (儲存大文字)
注 varchar(M)表示實際儲存的字元數
2.2.3 時間日期
- date YYYY-MM-DD 日期
- time HH:mm:ss 時間格式
- datetime YYYY-MM-DD HH:mm:ss 最常用的時間格式
- timestamp 時間戳,從1970.1.1到現在的毫秒數 也較為常用
- year 年份表示
2.2.4 null
- 沒有值,未知
**注意,不要使用NULL來運算,結果一定是NULL
2.3 資料庫的欄位屬性(重點)
- Unsigned:
- 無符號的**整數*
- 聲明瞭該列不能宣告為負數
- zerofill:
- 0填充的
- 不足的位數使用0來填充,int(3) (3表示顯示寬度為3,和儲存的範圍大小無關)輸入值為5,則實際儲存為005
- 自增
- 自動在上一條記錄的基礎上+1(預設+1,也可以自定義主鍵自增的起始值和步長)
- 通常用來設計唯一的主鍵index,必須是整數型別
- 非空 not null
- 假設設定為not null,不賦值就會報錯
- NULL,如果不填寫值,預設就是NULL
- 預設:
- 設定預設的值,如果不指定該列的值,則使用預設值
- 擴充套件
每張表必須存在以下5個欄位,未來做專案用的
id 主鍵
version 每條記錄都有個版本,用來做樂觀鎖的
is_delete 偽刪除 標記為1後只有管理員才能檢視被刪除的資料
gmt_create 建立時間 該記錄的建立時間
gmt_update 修改時間
2.4 建立資料庫表(重點)
--注意點使用英文符號{},表的名稱和欄位儘量使用``反引號包起來
-- AUTO_INCREMENT自增
-- 字串使用單引號括起來(雙引號也可以,用的少)
-- 所有的語句後加英文逗號,最後一個不用加
-- PRIMARY KEY 主鍵,一般一個表只有一個唯一的主鍵
CREATE TABLE IF NOT EXISTS`student`{
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '學號',
`name` VARCHAR(20) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密碼',
`sex` VARCHA(2) NOT NULL DEFAULT '女' COMMENT '性別',
`birthday` DATATIME DEFAULT NULL COMMENT '出生日期',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭地址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '郵箱',
PRIMARY KEY(`id`)
}ENGINE=INNODB DEFAULT CHARSET=utf8
格式:
CREATE TABLE [IF NOT EXISTS] `表名`{
'欄位名' 列型別 [屬性] [索引] [註釋],
'欄位名' 列型別 [屬性] [索引] [註釋],
...
'欄位名' 列型別 [屬性] [索引] [註釋]
}[表型別][字符集集設定][表的註釋]
如果不記得怎麼寫,可以檢視已存在的資料庫或表的建立語句
SHOW CREATE DATABASE school --檢視建立資料庫的語句
SHOW CREATE TABLE student --檢視student資料表的定義語句
DESC student --顯示錶的結構
2.5 資料表的型別
資料庫引擎
INNODB 預設使用,MYISAM 早些年使用的。二者區別如下:
MYISAM | INNODB |
---|---|
事務支援 | 不支援 |
資料行鎖定 | 不支援 |
外來鍵約束 | 不支援 |
全文索引 | 支援 |
表空間的大小 | 較小 |
- 常規使用操作
- MYISAM 節約空間,速度較快
- INNODB 安全性高,事務的處理,多表多使用者操作
- 在物流空間存在的位置
所有的資料庫檔案都存在data目錄下,一個資料夾就對應一個數據庫
本質還是檔案的儲存
MySQL引擎在物理檔案上的區別- InnoDB在資料庫表中只有一個*.frm檔案以及上級目錄下的ibdata1檔案
- MYISAM對應檔案
- *.frm--表結構定義的檔案
- *.MYD 資料檔案(data)
- *.MYI 索引檔案(index)
- 設定資料庫表的字符集編碼
CHARSET=utf8
不設定使用預設字符集Latin1編碼,不支援中文
可以修改my.ini配置編碼 character-set-server=utf8,但最好每次建立表時都加一句CHARSET=uft8.這樣這張表拿到別人那沒設定配置檔案也可以用
2.6 修改刪除表
修改
--修改表名: ALTER TABLE 舊錶名 RENAME AS 新表名
ALTER TABLE teacher RENAME AS teacher1
--增加表的欄位: ALTER TABLE 表名 ADD 欄位名 列屬性
ALTER TABLE teacher1 ADD age INT(11)
--修改表的欄位(重新命名,修改約束)
-- 修改約束:ALTER TABLE 表名 MODIFY 欄位名 新列屬性
-- 重新命名: ALTER TABLE 表名 CHANGE 舊名字 新名字 列屬性[]
ALTER TABLE teacher MODIFY age VARCHAR(11) --修改約束
ALTER TABLE teacher CHANGE age age1 INT(1) --欄位重新命名
--刪除表的欄位: ALTER TABLE 表名 DROP 欄位名
ALTER TABLE teacher1 DROP age1
--刪除表
DROP TABLE IF EXISTS teacher
注:* change用來修改欄位名,modify用來修改約束
* 所有建立和刪除操作儘量加上判斷,以免報錯
* ``欄位名用反引號包裹(防止和關鍵字重複)
* 註釋-- /* */
* sql 關鍵字大小寫不敏感,建議使用小寫,方便閱讀
* 所有符號都用英文
3 MySQL資料管理
3.1 外來鍵 (瞭解即可)
刪除表A,如果表A(主表)存在表B(從表)的外來鍵引用,先要把表B刪除,才能刪除表A(被引用表)
- 建立外來鍵方式一
CREATE TABLE `grade`{
`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年級id',
`gradename` VARCHAR(50) NOT NULL COMMENT '年級名稱',
PRIMARY KEY (`gradeid`)
} ENGIN = INNODB DEFAULT CHARSET =utf8
--學生表的gradeid欄位要去引用年級表的gradeid欄位
--定義外來鍵
--給這個外來鍵新增約束(執行引用)
CREATE TABLE IF NOT EXISTS`student`{
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '學號',
`name` VARCHAR(20) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密碼',
`sex` VARCHA(2) NOT NULL DEFAULT '女' COMMENT '性別',
`birthday` DATATIME DEFAULT NULL COMMENT '出生日期',
`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '學生年級',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭地址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '郵箱',
PRIMARY KEY(`id`),
KEY `FK_gradeid` (`gradeid`),
CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade` (`gradeid`)
}ENGINE=INNODB DEFAULT CHARSET=utf8
- 方式二
建立表的時候沒有外來鍵關係
ALERT TABLE 表名 ADD CONSTAINT 約束名 FOREIGN KEY(作為外來鍵的列) REFERENCE 被引用表名 (被引用欄位)
ALTER TABLE `student`
ADD CONSTRAINT `FK_gradeid` FOREIGN KEY(`gradeid`) REFERENCES `grade` (`gradeid`)
以上操作都是資料庫級別的物理外來鍵,不建議使用。(避免資料庫過多造成困擾,這裡瞭解即可)
最佳實踐
- 資料庫就是單純的表,只用來存資料,只有行(資料)和列(欄位)
- 我們項使用多張表的資料,想使用外來鍵(用程式去實現)
3.2 DML語言(全部記住)
資料庫存在意義:資料儲存,資料管理
DML語言: 資料操作語言
insert, update,delete
3.2.1 insert
INSERT INTO 表名([欄位名1,欄位2,欄位3])values ('值1','值2','值3'),('值1','值2','值3')
插入語句一定要欄位和值一一對應
INSERT INTO `grade` (`gradename`) VALUES('大三')
--一次插入多行
INSERT INTO `grade` (`gradename`) VALUES('大三')('大四')
--多行多欄位(下例兩行)
INSERT INTO student(`name`,`pwd`,`sex`) VALUES('李四','12324','男'),('王五','232434','女')
注意事項:
- 欄位和欄位之間使用 英文逗號隔開
- 欄位是可以省略的,但是表裡後面的值要都列出來,一一對應
- 可以同時插入多條資料,VALUES後面的值,需要使用逗號隔開 value(),()...
- update
- delete
3.2.2 修改
語法(關鍵字大寫)
UPDATE 表名 SET column_name = value [, column_name2 = value..] WHERE[條件]
--加where條件,修改指定的行
UPDATE `student` SET `name` ='xiaoming' WHERE id=1;
--不加where條件,修改的是整張表
UPDATE `student` SET `name`='xiaohong' ;
--同時修改多個欄位
UPDATE `student` SET `name`='xiaofang', email='[email protected]' WHERE id=1;
--多個條件定位資料
UPDATE `student` SET `name`='長江7好' WHERE `name`='xiaoming` AND sex ='女';
--value可以是個變數
UPDATE `student` SET `birthday`=CIRRENT_TIME WHERE `name`='長江7好' AND sex ='女'
條件
where 子句 運算子 id等於某個值,大於某個值,在某個區間內修改...
注意:
- column_name 是資料庫的列,儘量帶上``
- 條件,篩選的條件,如果沒有指定則會修改所有的列
- value 可以是個具體的值,也可以是個變數(通常是時間)
- 設定多個屬性,用英文逗號隔開(java操作,通常用trim把最後一個逗號剪掉)
3.2.3 刪除
語法
DELETE FROM 表名 WHERE
--避免這種寫法刪除整張表,要帶條件
DELETE FROM `student`;
--刪除指定資料
DELETE FROM `student` WHERE id=1;
``
**TRANCATE清空命令**
作用:完全清空一個表,表的結構和約束不會變
```sql
TRANCATE `student`
操作符 | 含義 |
---|---|
‘=’ | 等於 |
<>或者!= | 不等於 |
> | |
< | |
<= | |
>= | |
BETWEEN…AND.. | [a,b]閉合範圍內 |
AND | && 兩個條件同時成立 |
OR |
** DELETE和TRANCATE的區別**
- 相同點都能刪除資料,而且都不會刪除表結構
- 不同點
- TRANCATE 不同於delete重新設定自增列,計數器會歸零,不會影響事務(推薦)
DELETE刪除的問題,重啟資料庫現象
- TRANCATE 不同於delete重新設定自增列,計數器會歸零,不會影響事務(推薦)
- INNODB 自增列重新從1開始(存在記憶體中,斷電即失)
- MyISAM 繼續從上一個自增量開始(存在檔案中,不會丟失)
4 DQL查詢資料(最重點)
(Data Query Launguage)
- 所有的拆線呢操作都用它,Select
- 簡單的查詢,複雜的查詢都能做
- 使用頻率最高的最核心的語言
SELECT [ALL|DISTINCT]
{
*|table.*|table.field1[as alias1][,table.field2[as alias2]][,....]]}--查哪些欄位
From table_name [as table_alias] --從哪個表查
[left|right|inner join table_name2]--聯合查詢
[WHERE...]--指定結果需要滿足的條件
[GROUP BY..]--指定結果按照哪幾個欄位來分組
[HAVING]--過濾分組的記錄必須滿足的次要條件
[ORDER BY...]--指定查詢記錄按一個或多個條件排序
[LIMIT {[offset,]row_count|row_countOFFSET offset}];
--指定查詢記錄從哪條至哪條
}
中括號可選,大括號必選,注意遵守先後順序
4.1 SELECT語法
語法:
SELECT 欄位1 ... FROM 表名
有時候,列的名字不是那麼的見名知意,我們起別名,AS 欄位名 as 別名 表名 AS 別名
--查詢全部的學生
SELECT * FROM student
--查詢指定欄位
SELECT `StudentNo`,`StudentName` FROM student
--別名,給查詢結果欄位起別名,結果列名就是這個別名,給表起別名用於多表查詢
SELECT `StudentNo` AS 學號, `StudentName` AS 學生姓名 FROM student AS s
--函式 CONCAT(a,b)字串拼接
SELECT CONCAT('姓名:',StudentName) AS 新名字 FROM student
4.2 去重
使用distinct 去除SELECT** 查詢結果**中重複的資料,重複就只顯示一條
注意distinct只區別目標欄位,所有目標欄位有一個不重複就是不同的
SELECT * FROM result -- 查詢全部的考試成績
SELECT `StudentNo` FROM result --查詢有哪些同學參加了考試
--發現重複資料,去重
SELECT DISTINCT `StudentNo` FROM result
4.3 資料庫列表達式
資料庫中的表示式:文字值,列,Null,函式,計算表示式,系統變數...
select 表示式 from 表
SELECT VERSION() --查詢系統版本(函式)
SELECT 100*3-1 AS 計算結果 --用來計算(表示式)
SELECT @@auto_increment_increment --查詢自增的步長(變數)
--學員考試成績+1分檢視
SELECT `StudentNo`,`StudentResult`+1 AS '提分後' FROM result
4.4 where條件子句
作用:檢索資料中符合條件的值
搜素條件由一個或者多個表示式組成,結果為布林值,儘量使用英文關鍵字,可讀性提高
- 邏輯運算子
運算子 | 語法 |
---|---|
and && | a and b , a && b |
or | a or b, a |
Not ! | not a ! A |
SELECT studentNo, `StudentResult` FROM result
-- 查詢考試成績在95-100之間的
SELECT studentNo, `StudentResult` FROM result WHERE StuentResult>=95 AND StudentResult<=100
--使用between andd(區間)
SELECT studentNo, `StudentResult` FROM result WHERE StudentResult BETWEEN 95 AND 100
-- 除了1000號學生之外的同學的成績
SELECT studentNo,`StudentResult` FROM result WHERE studentNo!=1000;
SELECT studentNo,`StudentResult` FROM result WHERE NOT studentNo=1000;
- 模糊查詢:比較運算子
運算子 | 語法 |
---|---|
IS NULL | a is null 為真 |
IS NOT NULL | a is not null 為真 |
BETWEEN | a between b and c, a在[b,c]為真 |
Like | a like b,如果a能夠匹配b 則結果為真 |
In | a in(a1,a2,a3..),a 在後面的集合裡,則結果為真 |
like結合%(%代表0到任意個字元)_(代表一個字元), in後面是具體的值不和符號結合使用
--查詢姓劉的同學
SELECT `StudentNo`,`StudentName` FROM 'student' WHERE StudentName LIKE '劉%'
--查詢姓劉的同學,名字後面只有一個字
SELECT 'StudentNo','StudentName' FROM 'student' WHERE StudentName LIKE '劉_'
--查詢姓劉的同學,名字後面有兩個字
SELECT 'StudentNo','StudentName' FROM 'student' WHERE StudentName LIKE '劉__'
--查詢名字中帶有'嘉'字的
SELECT 'StudentNo','StudentName' FROM 'student' WHERE StudentName LIKE '%嘉%'
--==IN具體的一個或多個值===
---查詢1001,1002,1003號學員
SELECT 'StudentNo','StudentName' FROM 'student' WHERE StudentNo IN (1001,1002,1003)
--==null not null==
--查詢地址為空的學生 null ''
SELECT 'StudentNo','StudentName' FROM 'student' WHERE address='' OR address IS NULL
--查詢有出生日期的同學 不為空
SELECT 'StudentNo','StudentName' FROM 'student' WHERE 'BornDate' IS NOT NULL
4.5 聯表查詢
Join .. on
7 Join | 操作符 | 描述 |
---|---|---|
1 | left join … on左連線 | 左表的全部,右表不滿足的列補空NULL |
2 | right join 右連線 | 右表的全部,左表不滿足的列補空 |
3 | left join B.key is null | 只保留左表特有的資料,右表裡沒有 |
4 | inner join 內連線 | 只輸出左右表均存在的記錄(交集) |
5 | right join A.key is null | 只保留右表特有的資料 |
6 | full outer join/union 合併左,右外連線結果集 | 獲取左右表所有記錄,各自沒有時補空 |
7 | "full outer join key is null 從合併左右外連線結果集裡查詢a.key=null 或者B.key=null" | 獲取兩表連線交集的補集 |
- where 是用來做篩選條件的
- join...on才是連線查詢,通常使用on
寫sql語句思路:
- 確定要查哪些資料select ...
- 從那幾張表種查, FROM表, XXX Join連線的表, on 交叉條件
- 如存在多表查詢,慢慢來,先查詢兩張表然後再逐步增加連表
---查詢參加了考試的同學(學號,姓名,科目編號,分數)
/*思路
1.分析需求,查詢的欄位來自哪些表,多表需要聯合查詢
2.確定使用過那種連線查詢?7 種
確定交叉點,這兩個表中哪個資料是相同的
判斷的條件:學生表中的studentNo = 成績表中的studentNo
*/
--Inner join,此時where 和on等效,但是在其他查詢裡是不一樣的
SELECT s.studentNO,studentName,SubjectNo,StudentResult FROM student AS s
INNER JOIN result AS r WHERE s.studentNO = r.studentNO
--Right JOIN
SELECT s.studentNO,studentName,SubjectNo,StudentResult FROM student s RIGHT JOIN
result r ON s.studentNO=r.studentNO
--left JOIN
SELECT s.studentNO,studentName,SubjectNo,StudentResult FROM student s LEFTJOIN
result r ON s.studentNO=r.studentNO
--查詢缺考的同學
SELECT s.studentNO,studentName,SubjectNo,StudentResult
FROM student s LEFT JOIN result r ON s.studentNO = r.studentNO WHERE StudentResult IS NULL
--查詢參加考試的同學資訊:學號,學生姓名student,科目名subject,分數score(三表查詢)
SELECT s.studentNo,studentName,SubjectName,'StudentResult' FROM student s RIGHT JOIN
result ON r.studentNo=s.studentNo INNER JOIN `subject` sub ON r.subjectNo = sub.subjectNo
4.6 自連線查詢
自己的表和自己連線
`CREATE TABLE `category` {
`categoryid ` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主題id',
`pid` INT(10) NOT NULL COMMENT '父id',
'categoryName' VARCHAR(50) NOT NULL COMMENT '主題名字',
PRIMARY KEY('categoryid')
}
INSERT INTO `category` (`categoryid`,`pid`,`categoryName`)
VALUES('2','1','資訊科技').
('3','1','軟體開發'),
('4','3','資料庫'),
('5','1','美術設計'),
('6','3','web開發'),
('7','5','ps技術'),
('8','2','辦公資訊');
}
原始的單表如下,是個樹形結構
categoryid | pid | categoryName |
---|---|---|
2 | 1 | 資訊科技 |
3 | 1 | 軟體開發 |
4 | 3 | 資料庫 |
5 | 1 | 美術設計 |
6 | 3 | web開發 |
7 | 5 | ps技術 |
8 | 2 | 辦公資訊 |
可以拆成如下兩張表
父類(pid為1的):
categoryid | categoryName |
---|---|
2 | 資訊科技 |
3 | 軟體開發 |
5 | 美術設計 |
子類:
pid | categoryid | categoryName |
---|---|---|
3 | 4 | 資料庫 |
3 | 6 | web開發 |
5 | 7 | ps技術 |
2 | 8 | 辦公資訊 |
操作--查詢父類對應的子類關係
父類 | 子類 |
---|---|
資訊科技 | 辦公資訊 |
軟體開發 | 資料庫 |
軟體開發 | web開發 |
美術設計 | ps技術 |
--查詢父子關係:把一張表看作兩張一摸一樣的表即可
SELECT a.`categoryName` AS '父欄目',b.`categoryName` AS '子欄目'
FROM `category` AS a, `category` AS b WHERE a.`categoryid` = b.`pid`
4.7 排序ORDER BY和分頁LIMIT
--排序 升序 ASC,降序DESC
SELECT S.`StudentNo`,`StudentName`,`SubjectName`,`StudentResult`
FROM student s INNER JOIN `result` r
ON s.StudentNo = r.`StudentNo`
INNER JOIN `subject` sub ON r.`SubjectNo`=sub.SubjectNo`
WHERE subjectName = '資料庫結構-1'
ORDER BY `StudentResult` DESC --降序排列
--分頁,緩解資料庫壓力,給人更好的體驗
--(百度圖片沒使用分頁,而是用瀑布流)
--語法:limit 起始值,頁面顯示的資料行數大小
--LIMIT 0,5 1~5
--LIMIT 1,5 2~6
--LIMIT 6,5 第二頁
SELECT S.`StudentNo`,`StudentName`,`SubjectName`,`StudentResult`
FROM student s INNER JOIN `result` r
ON s.StudentNo = r.`StudentNo`
INNER JOIN `subject` sub ON r.`SubjectNo`=sub.SubjectNo`
WHERE subjectName = '資料庫結構-1'
ORDER BY `StudentResult` DESC
LIMIT 6,5
/*
網頁應用:當前curPage,總資料量,頁面的大小pageSize(展示多少條資料)
firstIndex=(curpage-1)*pageSize
lastIndex=curPage*PageSize
pages=(total+pageSize-1)/pageSize
*/
--查詢JAVA 第一學年課程成績排名前十的學生,並且分數要大於80的學生資訊(學號,姓名,課程名稱,分數)
SELECT s.`StudentNo`,`StudentName`,`SubjectName`,`StudentResult`
FROM student s INNER JOIN result r ON s.studentNo=r.studentNo
INNER JOIN subject sub ON r.SubjectNo=sub.SubjectNo
Where subjectName='JAVA 第一學年' AND StudentResult>80
ORDER BY StudentResult DESC
LIMIT 0,10
4.8 子查詢
where(子句判斷條件是計算出來的)
本質:在where 語句種巢狀一個子查詢, where(select * from)
通常子查詢效率要比連表查詢效率低
--1. 查詢資料庫結構-1的所有考試結果(學號,科目編號,成績)降序排列
--方式一使用連線查詢
SELECT s.`StudentNo`,'SubjectNo','StudentResult'
FROM result r
INNER JOIN subject sub ON r.SubjectNo=sub.SubjectNo
WHERE SubjectName='資料庫結構-1'
ORDER BY StudentResult DESC
--方式二使用子查詢(由裡及外,相當於小學生分步計算)
--查詢所有資料庫結構-1的學生學號
SELECT SubjectNo FROM `subject` WHERE SubjectName='資料庫結構-1'
--組合子查詢條件
SELECT `StudentNo`,`SubjectNo`,`StudentResult` FROM student
WHERE SubjectNo = (
SELECT SubjectNo FROM `subject` WHERE SubjectName='資料庫結構-1')
ORDER BY StudentResult DESC
--分數不小於80分的學生的學號和姓名
SELECT s.StudentNo, StudentName FROM student
INNER JOIN result r ON r.StudentNo = s.StudentNo
WHERE `StudentResult`>=80 AND `SubjectNo` =
(SELECT SubjectNo FROM `subject` WHERE `SubjectName`='高等數學-2')
--再改造
SELECT StudentNo, StudentName FROM student
WHERR studentNo IN (SELECT StudentNo from result
WHERE StudentResult>=80 AND subjectNo = (
SELECT subjectNo from subject WHERE subjectName='高等數學-2'))
4.9 過濾和分組
- 當時用GROUP BY後,不能再使用where來限制條件篩選,而是使用HAVING來進行分組篩選
- GOURP BY 一般結合聚合函式使用(多個輸入一個輸出,如AVG平均值,MAX最大值),因為分組後有的列入數學對應多個學生的分數,需要寫在一個單元格里,不再是多個單元格
--查詢不同課程的平均分,最高分,最低分
-- 根據不同的課程分組
SELECT `SubjectName`, AVG(StudentResult), MAX(StudentResult),MIN(StudentResult)
FROM result r INNER JOIN `subject` sub ON r.subjectNo = sub.subjectNo
GOURP BY `r.subjectNo` --通過什麼分組
--增加條件 查詢不同課程的平均分,最高分,最低分,且要求平均分大於80分
SELECT `SubjectName`, AVG(StudentResult) AS 平均分, MAX(StudentResult),MIN(StudentResult)
FROM result r INNER JOIN `subject` sub ON r.subjectNo = sub.subjectNo
GOURP BY `r.subjectNo`
HAVING 平均分>80
實際應用中sql查詢跨表,跨資料庫,本地資料庫遠端資料庫等等,複雜度增加(淘寶頁面千人千面)
5 MySQL函式
官網https://dev.mysql.com/doc/refman/5.7/en/built-in-function-reference.html
5.1 基本函式
--========數學運算======
SELECT ABS(-8) --絕對值
SELECT CEILING(9.4) --向上取整
SELECT FLOOR(9.4)--向下取整
SELECT RAND()--返回一個0~1之間的隨機數
SELECT SIGN(10) --判斷符號,正數返回1,負數返回-1
---字串函式
SELECT CHAR_LENGTH('即使在校的帆,也能遠航')--字串長度
SELECT CONCAT('世界','之大','無奇','不有')
SELECT INSERT('我愛程式設計helloworld',1,2,'超級熱愛')--插入替換,我愛-->超級熱愛
SELECT UPPER('hello')
SELECT LOWER('HEllo')
SELECT INSTR('hello world','r')--返回第一次出現的字串的索引
SELECT REPLACE('堅持就是勝利','堅持','努力')--替換指定字串
SELECT SUBSTR('堅持就是勝利',4,1)--擷取字串
SELECT REVERSE('堅持就是勝利')--反轉
--舉例
SELECT REPLACE(studentname,'周','鄒')FROM student
WHERE studentName LIKE '周%'
--時間和日期函式
SELECT CURRENT_DATE()--獲取當前日期
SELECT NOW()--獲取當前時間
SELECT LOCALTIME()--獲取本地時間
SELECT SYSDATE() --獲取系統時間
SELECT YEAR(NOW())--獲取年(時分秒類似)
--系統
SELECT SYSTEM_USER()
SELECT USER() --同上獲取系統當前使用者
SELECT VERSION()
5.2 聚合函式(常用)
函式名稱 | 描述 |
---|---|
COUNT() | 計數 |
SUM() | 求和 |
AVG() | 平均值 |
MAX() | 最大值 |
MIN() | 最小值 |
想查詢一個表中有多少記錄,就使用COUNT
注意COUNT(*),COUNT(1),COUNT(列名)都會統計行數,但略有不同
- COUNT(列名)會進行非NULL判斷,只有非NULL才會進入統計
COUNT(*),COUNT(1)都統計所有行數,不論是否是NULL - COUNT(1)可以想象成表有個固定欄位1,對其進行統計
- COUNT(*)則會根據Mysql的優化自動指定到效率高的欄位上
- 有主鍵的情況下COUNT(主鍵)查索引速度最快
--COUNT(*) COUNT(1) COUNT(列名)
SELECT COUNT(studentname) FROM student;--Count指定列
SELECT COUNT(*) FROM student;
SELECT COUNT(1) FROM student;
SELECT SUM(`StudentResult`) AS '總和' FROM result
SELECT AVG('StudentResult`) AS '平均分' FROM result
SELECT MAX(`StudentResult`) AS '最高分' FROM result
SELECT MIN(`StudentResult`) AS '最低分' FROM result
5.3 資料庫級別的MD5加密(擴充套件)
什麼事MD5? 不可逆的演算法,具體值對應的md5值是一致的。
MD5破解網站的原理,背後有一個字典,輸出MD5加密後的值,查表返回加密前的值
--測試MD5加密
CREATE TABLE 'testmd5'{
`id` INT(4) NOT NULL,
`name` VARCHAR(20) NOT NULL,
`pwd` VARCHAR(50) NOT NULL,
PRIMIARY KEY(`id`)
} ENGINE=INNODB DEFAULT CHARSET=utf8
--明文密碼
INSERT INTO testmd5 VALUES (1,'zhangsan','123456'),(2,'lisi','123434'),
(3,'wangwu','1234346')
--加密
UPDATE testmd5 SET pwd=MD5(pwd) --加密全部的密碼
--插入的時候加密
INSERT INTO testmd5 VALUES (4,'xiaoming',MD5('34343434'))
--如何校驗:將使用者傳遞進來的密碼,進行md5加密,比較加密後的值
SELECT * FROM testmd5 WHERE `name`='xiaoming' AND pwd=MD5('123456')
6. 事務
6.1 什麼是事務
- 事務原則:ACID 原子性(Atomicity),一致性(Consisitency),隔離性(Isolation),永續性(Durability)
- 原子性:要麼都成功,要麼都失敗,一組SQL放在一個批次中執行
---------
1. SQL 執行 A給B轉賬 A:1000->200 B:200
2. SQL 執行 B收到A的錢 A:800 B:400
---------
- 一致性:事務操作前後資料的完整性是保持一致的,如A,B賬戶錢的總和在轉帳前後保持一致
- 永續性: 事務一旦提交就不可逆不受事故影響了。假設出現事故,如斷電,事務沒有提交,資料庫回覆到原有狀態;事務已經提交了,持久化到資料庫,重啟後仍然是持久化後的狀態。
- 隔離性:多個使用者併發訪問資料庫時,資料庫為每個使用者開啟單獨的事務,事務間相互隔離,排除其他事務對本次事務的影響
- 事務的隔離級別(隔離所產生的問題)
- 髒讀:一個事務讀取另外一個事務未提交的資料
- 不可重複讀:在一個事務內讀取表的某一行資料,多次讀取結果不一樣(如第二次讀之前,有人轉錢了,賬戶餘額變多了),這個不一定是錯誤,只是某些場合不對。
- 幻讀(虛讀) 指在一個事務內讀取到了別的事務插入的資料,導致前後讀取不一致(如多了一行)
參考連結:https://blog.csdn.net/dengjili/article/details/82468576
6.2 處理事務sql
--mysql是預設開啟事務自動提交的
SET autocommit = 0 /*關閉自動提交*/
SET autocommit = 1 /*開啟自動提交*/
--手動處理事務
SET autocommit = 0
--事務開啟
START TANSACTION -- 標記一個事務的開啟,從這個之後的sql都在同一個事務內
INSERT XX
INSERT XX
--提交:持久化(成功)
COMMIT
--回滾:回到原來的樣子(失敗)
ROLLBACK
--事務結束
SET autocommit = 1
--儲存點了解,(玩遊戲掛掉,回到相應的關卡)
SAVEPOINT 儲存點名 --設定一個事務的儲存點
ROLLBACK TO SAVEPOINT 儲存點名--回滾到儲存點
RELEASE SAVEPOINT 儲存點名--撤銷儲存點
例
CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf_8_general_ci--核對COLLATE
USE shop
CREATE TABLE `account` {
`id` INT(3) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(30) NOT NULL,
`money` DECIMA(9,2) NOT NULL.
PRIMARY KEY ('id')
}ENGINE=INNODE DEFAULT CHASET=utf8
INSERT INTO account(`name`,`money`)
VALUES('A',2000.00),('B',1000.00)
----模擬轉賬:事務
SET autocommit=0;
START TRANSACTION
UPDATE account SET money=money-500 WHERE `name`='A'--A減500
UPDATE account SET money=money+500 WHERE `name`='B'--B加500
COMMIT;--提交事務
ROLLBACK;
SET autocommit=1; --恢復預設值
7 索引
https://blog.csdn.net/wufuhuai/article/details/79631466 (講的比較深的mysql原理,待看)
MySQL官方對索引的定義為:索引(Index)是幫助MySQL高效獲取資料的資料結構。
索引的本質是資料結構。
7.1 索引的分類
- 主鍵索引(PRIMARY KEY)
- 唯一標識,主鍵不可重複,表中只能有一個列作為主鍵,不能為null
- 唯一索引 (UNIQUE KEY)
- 被標識的列值不可以重複,在一個表中帶唯一索引的列可以有多個
主鍵一定是唯一性索引,但是唯一索引不一定是主鍵
- 被標識的列值不可以重複,在一個表中帶唯一索引的列可以有多個
- 常規索引 (KEY/Index)
- 預設的用Index/Key關鍵字來設定
- 全文索引(FullText)
- 在特定的資料庫引擎下才有,Myisam,作用快速定位資料,用關鍵字FULLTEXT INDEX
7.2 索引的使用
- 建立索引兩種方法
1.在建立表的時候CREATE給欄位增加索引
2.建立完畢後,增加索引 ALTER TABLE 表名 ADD xxx INDEX 索引名(列名)
3. 在表上加索引,索引命名方式 id_表名_欄位名
語法: CREATE INDEX 索引名 on 表(欄位)
--顯示所有的索引資訊
SHOW INDEX FROM student
--增加一個全文索引 (索引名)列名,查詢的時候有索引的列會快一點
ALTER TABLE school.student ADD FULLTEXT INDEX `studentName`(`studentName`);
- 索引建立完使用,是指查詢的時候自動使用,加快搜索
- explain分析sql執行的情況
語法:explain+SQL語句
-- EXPLAIN 分析sql執行的情況
EXPLAIN SELECT * FROM student WHERE MATCH(studentName) AGAINST('劉')
explain的使用參考https://blog.csdn.net/jiadajing267/article/details/81269067
- 測試索引
給app_user表加入1000000條測試資料
--插入100萬的資料(寫sql函數了解即可)
DELIMITER $$ --寫函式之前必須要寫的標誌
CREATE FUNCTION mock_data()
RETURNS INT
BEGIN
DECLARE num INT DEFAULT 1000000;
DECLARE i INT DEFAULT 0;
WHILE i<num DO
--插入語句
--currenttime, update time 不用手動寫,勾選了自動更新
INSERT INTO app_user(`name`,`email`,`phone`,`gender`,`password`,`age`)
VALUES(CONCAT('使用者',i),'[email protected]',CONCAT('18',FLOOR(RAND()*(999999999-100000000))+100000000)),
FLOOR(RAND()*2),UUID(),FLOOR(RAND()*100));
SET i = i+1;
END WHILE
RETURN I;
END;
建立索引,索引命名id_表名_欄位名
比較加上索引和沒加索引查詢速度
SELECT * FROM app_user WHERE `name`='使用者9999';--1sec左右的執行時間
EXPLAIN SELECT * FROM app_user WHERE `name`='使用者9999';--查了9000多條資料
--id_表名_欄位名
--CREATE INDEX 索引名 on 表(欄位)
CREATE INDEX id_app_user_name ON app_user(`name`);
--此時再查使用者9999速度飛起
SELECT * FROM app_user WHERE `name`='使用者9999';--0.001 sec
--rows為1行,相當於唯一定位了,key value查詢
EXPLAIN SELECT * FROM app_user WHERE `name`='使用者9999';
索引再小資料量的時候,差別不大,但是大資料時十分明顯
7.3 索引原則
-
索引不是越多越好
-
不要對經常變動的資料加索引
-
小資料量的表不需要加索引
-
索引一般加在常用來查詢的欄位上
-
索引的資料結構
Hash型別的索引
Btree:InnoDB的預設資料結構
--業務級的mysql
--運維級的mysql 負載均衡,mysql底層
8.許可權管理和備份
8.1 使用者管理
- SQLyog 可是化管理
- SQL 命令操作
在資料庫目錄下有張user使用者表,增加刪除使用者就是對該表進行增刪改查
--建立使用者 CREATE USER 使用者名稱 IDENTIFIED BY '密碼'
CREATE USER xiaoming IDENTIFIED BY '123456'
--修改當前使用者的密碼
SET PASSWORD = PASSWORD('1232434')
--修改指定使用者密碼
SET PASSWORD FOR xiaoming= PASSWORD('12323233')
--重新命名 RENAME USER 原名字 TO 新名字
RENAME USER xiaoming TO xiaolan
--使用者授權 ALL PRIVILEGES 全部的許可權(除了給別人授權). 庫.表
GRANT ALL PRIVILEGES ON *.* TO xiaolan
--查詢許可權
SHOW GRANTS FOR xiaolan --檢視指定使用者的許可權
--root的許可權查出來是GRAN ALL PRIVILEGES ON *.* TO 'root@localhost' WITH GRANT OPTION
SHOW GRANTS FOR root@localhost
--撤銷許可權 REVOKE 哪些許可權,在哪個庫表,給誰撤銷
REVOKE ALL PRIVILEGES ON *.* FROM xiaolan
--刪除使用者
DROP USER xiaolan
8.2 資料庫備份
為什麼要備份:
- 保證資料不丟失
- 資料轉移
MySQL資料備份的方式 - 直接拷貝物理檔案 data資料夾
- 在Sqlyog這種視覺化工具中手動匯出
右鍵想要匯出的表或資料庫->轉儲到sql,選結構和資料,其他預設 - 使用命令列在終端上匯出 mysqldump (對於windows系統指的是cmd彈出的終端)
# ======匯出======
# mysqldump -h 主機 -u 使用者名稱 -p密碼 資料庫 表名>物理位置
mysqldump -hlocalhost -uroot -p123456 school student >D:/a.sql
# dump多張表
# mysqldump -h 主機 -u 使用者名稱 -p密碼 資料庫 表名1 表名2 表名3>物理位置
mysqldump -hlocalhost -uroot -p123456 school student result>D:/b.sql
# dump資料庫
mysqldump -hlocalhost -uroot -p123456 school >D:/db.sql
#======匯入=======
# 先登入
mysql -uroot -p123456
# 切換到指定的資料庫
use school
# 匯入,登入的情況下切換到指定的資料庫,source備份的檔案
source d:/a.sql
# 第二種匯入方法
mysql -u使用者名稱 -p密碼 庫名<備份檔案
9 規範資料庫設計
9.1 為什麼需要設計
當資料庫比較複雜的時候,我們就需要設計了
糟糕的資料庫設計:
-
資料冗餘,浪費空間
-
資料庫插入和刪除都會比較麻煩,異常【遮蔽使用物理外來鍵】
-
程式的效能差
良好的資料庫設計: -
節省記憶體空間的
-
保證資料庫的完整性
-
方便我們開發系統的
軟體開發中,關於資料庫的設計 -
分析需求: 分析業務和需要處理的資料庫的需求
-
概要設計:設計關係圖E-R圖
設計資料庫的步驟:(個人部落格) -
收集資訊,分析需求
- 使用者表(使用者登入登出,使用者的個人資訊,寫部落格,建立分類)
- 分類表(文章分類,誰建立的)
- 文章表(文章的資訊)
- 友連結串列(友鏈資訊)
- 自定義表(系統資訊,某個關鍵的字,或者一些主欄位 key:value)可選項
- 說說表(發表心情..id...content...create_time)
comments表,user_id_parent回覆評論形式,查詢時單表自聯接
links表
user表
user_follow表(中間表)
category分類表
blog表
-
標識實體,實現功能時表與表之間的關係(把需求落地到每個欄位)
- 寫部落格:user->blog
- 建立分類:user->category
- 關注:user->user
- 友鏈:links
- 評論:user->user->blog
常見的系統:部落格,論壇,CRM管理系統
注:資料庫裡欄位使用下劃線_分隔,儘量不要使用駝峰命名,因為資料庫不區分大小寫
9.2 三大正規化
- 為什麼需要資料規範化?
- 資訊重複(如兩張表裡都寫username 和userid)
- 更新異常
- 插入異常
- 無法正常顯示資料(插入資訊不完整,多張表重複欄位,漏插入)
- 刪除異常
- 丟失有效的資訊
- 三大正規化
(注:檢索概念的時候,搜那些有例子的部落格,方便理解,不要純文字)
參考 https://www.cnblogs.com/wsg25/p/9615100.html- 第一正規化(1NF)
原子性:保證每一列不可以再分 - 第二正規化(2NF)
滿足第一正規化的前提下,每張表只描述一件事情,產品,或者訂單是兩張不同的表,不能混在一起談 - 第三正規化
滿足一二正規化的前提下,確保資料表中的每一列水簌俱都和主鍵直接相關,而不能間接相關
- 第一正規化(1NF)
- 規範性和效能的問題
關聯查詢的表不能超過三張- 考慮商業化的需求和目標,(成本,使用者體驗等考慮)資料庫的效能更加重要
- 在規範效能的問題的時候,需要適當的考慮一下規範性
- 故意給某些表增加一些冗餘的欄位,從多表查詢變成單表查詢
如訂單-商品id,還增加了商品資訊 - 故意增加一些計算列(從大資料量計算,降為小資料兩的查詢)
10. JDBC(重點)
10.1 資料庫驅動
類似於音效卡顯示卡,資料庫也需要有安裝驅動,我們的程式會通過資料庫驅動來和資料庫互動
10.2 JDBC
SUN公司為了簡化開發人員對資料庫的統一操作,提供了一個java操作資料庫的規範JDBC.這些規範的具體實現由資料庫廠商實現。
(注:在架構中沒有什麼是加一層解決不了的)
- 主要涉及的包
java.sql
javax.sql
匯入的資料庫驅動包:
mysql-connector-java-5.1.47.jar
下載該包的時候一般去maven倉庫下載 maver repository
官網也可以下載,但是用的少 官網下載地址
10.3 第一個JDBC程式
1.建立測試資料庫
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','[email protected]','1980-12-04'),
(2,'lisi','123456','[email protected]','1981-12-04'),
(3,'wangwu','123456','[email protected]','1979-12-04')
- 建立一個普通專案,把驅動包mysql-connector-java-5.1.47.jar放在建立的lib目錄下,右鍵add as library新增進來
- 編寫測試程式碼
步驟總結: - 載入驅動 Class.forName
- 使用者資訊及url
- 連線資料庫DriverManager->connection
- 獲得執行sql的物件->statement
- 執行sql,可能得到返回結果
- 關閉結果集resultSet,Statement,connection釋放資源
public class JdbcFirstDemo{
public static void main(String[]args){
//1.載入驅動
Class.forName("com.mysql.jdbc.Driver");//固定寫法
//2.使用者資訊和url
//jdbc:mysql://serverIP:3306/databaseName?
//useUnicode支援中文編碼,characterEncoding設定字符集,useSSL安全連線
String url =
"jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8useSSL=true“;
String username="root";
String password="123456";
//3.連線成功,返回資料庫物件connection
Connection connection = DriverManager.getConnection(url,username,password);
//4.執行SQL物件statement
Statement statement = connection.createStatement();
//5.去執行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("pwd="+resultSet.getObject("pwd"));
System.out.println("email="+resultSet.getObject("email"));
System.out.println("birth="+resultSet.getObject("birth"));
System.out.println("=======================")
}
//6.釋放連線
resultSet.close();
statement.close();
connection.close();
}
}
解釋:
- 載入資料庫驅動
Class.forName("com.mysql.jdbc.Driver")對應靜態程式碼塊,載入類直接執行DriverManager.registerDriver(new com.mysql.jdbc.Driver())
推薦用Class.forName這種寫法 - URL
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
協議//主機地址:3306(mysql預設埠號)/資料庫名?引數1&引數2&引數3
擴充套件oralce--1521寫法
jdbc:oracle:thin:@localhost:1521:sid - connection
connection代表資料庫,可以設定自動提交,事務提交,事務回滾
connection.rollback()
connection.commit()
connection.setAutoCommit(); - statement執行SQL類(PrepareStatement也是)
executeQuery()//返回查詢結果集Resultset
execute()//執行任何sql,裡面有判斷的過程,效率更低一點
executeUpdate()//增刪改都用它,返回受影響的行數
executeBatch()//執行批處理多個sql - ResultSet查詢的結果集
封裝了所有的查詢結果,拿結果時可以指定資料型別
getObject(),getString(),getInt(),getfloat()...
在不知道資料庫列對應的資料型別時用getObject,知道的情況就用指定的型別
遍歷,指標resultSet.next() - 釋放資源
resultSet.close();
statement.close();
connection.close();
10.4 statement物件
statement物件用於向資料庫傳送增刪改查語句
executeQuery()返回查詢結果集ResultSet
executeUpdate增刪改,返回受影響改變的行數,當返回值大於零說明執行成功
- 提取工具類
- db.properties
driver = com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username=xiaoming
password=123456
- JdbcUtils.java工具類
static塊load properties檔案,載入驅動
提取獲取連線的方法
提取釋放資源的方法
public class JdbcUtils{
private static String driver = null;
private static String url = null;
private static String name = null;
private static String password = null;
static {
try{
//在src目錄下的資源都可以用類反射載入
InputStream in =
JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(in);
driver = properties.getProperty(driver);
url = properties.getProperty(url);
name = properties.getProperty(name);
password = properties.getProperty(password);
//1.驅動只用載入一次
Class.forName(driver);
}catch(Exception){
e.printStackTrace();
}
}
//獲取連線
public static void getConnection() throw SQLException{
return DriverManager.getConnection(url,name,password);
}
//釋放資源
public static void release(Connection conn, Statement st, ResultSet rs){
if(rs!=null){
try{
rs.close();
}catch(SQLException e){
e.printStackTrace();
}
}
if(st!=null){
try{
st.close();
}catch(SQLException e){
e.printStackTrace();
}
}
if(conn!=null){
try{
conn.close();
}catch(SQLException e){
e.printStackTrace();
}
}
}
}
- 測試編寫增刪改查的程式碼
變的時sql語句和執行語句,查詢略
在finally裡釋放資源
public class TestInsert{
public static void main(String[] args){
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try{
conn= JdbcUtils.getConnection();
st = conn.createStatement();
String sql =" Insert INTO users(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)
VALUES(4,‘xiaoming','1232434','[email protected]’,‘2001-3-4’)";
/* 刪除的sql
String sql ="DETELET FROM users WHERE id=4”;
*/
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("插入成功");
}
}catch(SQLException e){
e.printStackTrace();
}finally{
JdbcUtils.release(conn,st,rs)
}
}
}
- SQL注入問題
本質上輸入的sql存在惡意拼接(or,and version()>0),攻擊者可以在web應用程式中事先定義好的查詢語句的結尾上新增額外的SQL語句。實現非授權的任意查詢
public static void login(String username, String password){
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try{
conn= JdbcUtils.getConnection();
st = conn.createStatement();
//對應組合的sql,sql注入時如下
//SELECT * from users WHERE `name`= ' ' OR ‘1=1’ AND `password`=' ’ or '1=1';
String sql ="SELECT * from users WHERE `name`= '"+username+"' AND `password`='"+ password+"'";
rs =st.executeQuery(sql);
while(rs.next()){
System.out.println(rs.getString(name));
}
}catch(SQLException e){
e.printStackTrace();
}finally{
JdbcUtils.release(conn,st,rs)
}
}
public static void main(String args[]){
//正常登入
//login("xiaoming","123456");
//sql注入
login(" 'or 1=1"," 'or 1=1");
}
10.5 PreparedStatement物件
PreparedStatement(sql)預編譯的可以防止注入,且效率更高
- 編寫sql先用?佔位符來代表值,
- 預編譯preparedStatement
- 賦值
- 再執行
public class TestInsert(){
public static void main(String[] args){
Connection conn = null;
PreparedStatement pst =null;
try{
conn = JdbcUtils.getConnection();
//區別,先使用?佔位符代替引數
String sql ="Insert INTO users(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)
VALUES(?,?,?,?,?)"
//引數預編譯sql,先寫sql然後不執行
pst = conn.prepareStatement(sql);
//手動給引數賦值
pst.setInt(1,4);
pst.setString(2,"xiaohong");
pst.setString(3,"1232434");
pst.setString(4,"[email protected]");
//注意 sql.Date資料庫裡的時間,引數是時間戳
//util.Date java裡的時間
pst.setDate(5,new java.sql.Date(new Date().getTime()));
//執行,不用傳參
int i = pst.executeUpdate();
if(i>0){
System.out.println("插入成功");
}
}catch(Exception e){
e.printStackTrace();
}finally{
}
}
}
10.6 使用IDEA連線資料庫
前提工程裡已經導好了資料庫驅動包connector
- 點選IDEA右側Database標籤->點選+加號->選擇MySQL資料庫
新增資料庫具體資訊Host,User,Password,和URL,使用Test Connection 進行連線測試
點選apply OK, 第一次連線比較耗時 - 連線成功mysql後,新增具體的資料庫
點選Database標籤裡的設定按鈕(彈出Data Sources and Drivers)->Schemas(裡面勾選資料庫)->apply->OK - 檢視資料庫表
雙擊新增的資料庫裡面的表,即可展示裡面的內容 - 更新資料
直接再開啟的表裡修改,注意點選提交按鈕 - IDEA裡執行命令列寫sql
開啟database標籤裡的console,輸入sql語句執行即可 - 如果連線sql出現問題,可以檢視驅動配置是否有問題
參考 https://blog.csdn.net/weixin_44199123/article/details/106296349
10.7 事務
程式碼實現
- 開啟事務 conn.setAutoCommit(false);
- 一組業務執行完畢,提交事務connection.submit
- 可以在catch裡顯示定義回滾,但是預設失敗就會回滾的
public class TestTransaction1{
public static void main(String[] args){
Connection conn = null;
PrepareStatement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
//關閉資料庫自動提交,會自動開啟事務
conn.setAutoCommit(false);
String sql1 = "UPDATE account SET money = money-100 where name ='A'";
st = conn.prepareStatement(sql1);
st.executedUpdate();
int x = 1/0;//報錯,測試兩個操作在同一個事務裡,回滾
String sql2 = "UPDATE account SET money = money+100 where name ='B'";
st = conn.prepareStatement(sql2);
st.executedUpdate();
//業務完畢,提交事務
conn.commit();
System.out.println("成功");
}catch(Exception e){
//如果不手動回滾,也可以自動回滾
try{
//如果失敗回滾
conn.rollback();
}catch(SQLException e1){
e1.printStackTrace();
}
e.printStacTrace();
}finally{
JdbcUtils.release(con,st,rs);
}
}
}
10.8 DBCP-C3P0連線池
資料庫連線--執行--釋放,十分耗費資源
池化計數:預先準備一些資源,後面就直接取用就行
編寫連線池實現JDK提供介面DataSource
- 開源資料實現DataSource
- DBCP
- C3P0
- Druid:阿里巴巴
使用了這些資料庫連線池後,我們在專案開發中就不需要編寫載入資料庫驅動的程式碼了 - DBCP
- 匯入相關jar包,add as libary
commons-dbcp-1.4.jar
commons-pool-1.6.jar - 匯入配置檔案dbcpconfig.properties
- 匯入相關jar包,add as libary
#連線設定 這裡面的名字是DBCP資料來源中定義好的,可以只寫這4條後面的都不要
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=123456
#<!-- 初始化連線 -->
initialSize=10
#最大連線數量
maxActive=50
#<!-- 最大空閒連線 -->
maxIdle=20
#<!-- 最小空閒連線 -->
minIdle=5
#<!-- 超時等待時間以毫秒為單位 6000毫秒/1000等於60秒 -->
maxWait=60000
#JDBC驅動建立連線時附帶的連線屬性屬性的格式必須為這樣:【屬性名=property;】
#注意:"user" 與 "password" 兩個屬性會被明確地傳遞,因此這裡不需要包含他們。
connectionProperties=useUnicode=true;characterEncoding=UTF8
#指定由連線池所建立的連線的自動提交(auto-commit)狀態。
defaultAutoCommit=true
#driver default 指定由連線池所建立的連線的只讀(read-only)狀態。
#如果沒有設定該值,則“setReadOnly”方法將不被呼叫。(某些驅動並不支援只讀模式,如:Informix)
defaultReadOnly=
#driver default 指定由連線池所建立的連線的事務級別(TransactionIsolation)。
#可用值為下列之一:(詳情可見javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED
- 寫JdbcUtils_DBCP.java工具類
public class JdbcUtils_DBCP{
private DataSource dataSource=null;
static {
try{
//載入jdbc對應的properties檔案
InputStream in =
JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
Properties properties = new Properties();
properties.load(in);
//建立資料來源 工廠模式-->建立
dataSource = BasicDataSourceFactory.creatDataSource(properties);
}catch(Exception){
e.printStackTrace();
}
}
//獲取連線
public static void getConnection() throw SQLException{
//從資料來源中獲取連線
return dataSource.getConnection();
}
//釋放資源
public static void release(Connection conn, Statement st, ResultSet rs){
if(rs!=null){
try{
rs.close();
}catch(SQLException e){
e.printStackTrace();
}
}
if(st!=null){
try{
st.close();
}catch(SQLException e){
e.printStackTrace();
}
}
if(conn!=null){
try{
conn.close();
}catch(SQLException e){
e.printStackTrace();
}
}
}
}
- 測試類和前面一樣,只是工具類換成剛建立的JdbcUtils_DBCP
public static void main(String[] args){
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try{
conn= JdbcUtils_DBCP.getConnection();
st = conn.createStatement();
String sql ="Insert INTO users(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)
VALUES(4,‘xiaoming','1232434','[email protected]’,‘2001-3-4’)";
/* 刪除的sql
String sql ="DETELET FROM users WHERE id=4”;
*/
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("插入成功");
}
}catch(SQLException e){
e.printStackTrace();
}finally{
JdbcUtils_DBCP.release(conn,st,rs)
}
}
- C3P0
- 匯入jar包
c3p0-0.9.5.5.jar
mchange-commons-java-0.2.19.jar - C3P0配置檔案c3p0-config.xml(注意使用xml配置)
xml裡可以寫多套資料來源配置,ComboPooledDataSource ds=new ComboPooledDataSource(),不寫引數代表使用預設資料來源
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!--
c3p0的預設(預設)配置
如果在程式碼中"ComboPooledDataSource ds=new ComboPooledDataSource();"無參使用預設資料來源-->
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcStudy?useUnicode=true&characterEncoding=utf8&uesSSL=true&serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">123456</property>
<property name="acquiredIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</default-config>
<!--如果在程式碼中"ComboPooledDataSource ds=new ComboPooledDataSource("MySQL");
使用指定的資料來源-->
<named-config name="MySQL">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcStudy?useUnicode=true&characterEncoding=utf8&uesSSL=true&serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">123456</property>
<property name="acquiredIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</named-config>
</c3p0-config>
對應工具類
public class JdbcUtils_C3P0{
private static comboPooledDataSource dataSource=null;
static {
try{
//程式碼版配置 一般不這麼配
/*
dataSource = new ComboPooledDataSource();
dataSource.setDriverClass();
dataSource.setUser();
dataSource.setPassword();
dataSource.setJdbcUrl();
*/
//xml版配置
dataSource = new ComboPooledDataSource("MySQL");
}catch(Exception){
e.printStackTrace();
}
}
//獲取連線
public static void getConnection() throw SQLException{
//從資料來源中獲取連線
return dataSource.getConnection();
}
//釋放資源
public static void release(Connection conn, Statement st, ResultSet rs){
if(rs!=null){
try{
rs.close();
}catch(SQLException e){
e.printStackTrace();
}
}
if(st!=null){
try{
st.close();
}catch(SQLException e){
e.printStackTrace();
}
}
if(conn!=null){
try{
conn.close();
}catch(SQLException e){
e.printStackTrace();
}
}
}
}
測試類 類似上面的略
- 總結
無論使用什麼資料來源,本質上是一樣的,dataSource及方法getConnection不會變
擴充套件
Apacha開源專案網站:Durid(阿里貢獻的),maven, tomcat等等