1、初識MySQL
javaEE:企業級java開發 web
前端(頁面、展示、數據!)
后台(連接點:連接數據庫JDBC,連接前端(控制,控制視圖跳轉,和給前端傳遞數據))
數據庫(存數據。TXT,Excel,Word)
只會寫代碼,學好數據庫,基本可以混飯吃
操作系統,數據結構,算法,當一個不錯的程序員
離散數學,數字電路,體系結構,編譯原理,實戰經驗 高級程序員
1.1、為什么學數據庫
1、崗位需求
2、現在的世界,大數據時代,得數據者得天下
3、被迫需求,存數據
4、數據庫是所有軟件體系最核心的存在 DBA
1.2、什么是數據庫
數據庫:(DB,DateBase)
概念:數據倉庫,軟件,安裝在操作系統之上,SQL,可以存儲大量數據,500萬條一下,超過后得需要增加索引相關東西
作用:存儲數據,管理數據
1.3、數據庫分類
關系型數據庫:(SQL)
- MySQL,Oracle,Sql Server,DB2,SQLlite
- 通過表和表之間,列和行之間的關系進行數據的存儲, 學員表、考勤表
非關系型數據庫:(No SQL)Not Only SQL
- Redis、MongoDB
- 非關系型數據庫,對象存儲,通過對象的自身屬性來決定。
DBMS(數據庫管理系統)
- 數據庫的管理軟件:可視化軟件,科學有效的管理我們的數據,維護和獲取數據
- MySQL,本質是數據庫管理系統
1.4、MySQL簡介
MySQL是一個關系型數據庫管理系統,由瑞典[MySQL AB](https://baike.baidu.com/item/MySQL AB/2620844) 公司開發,屬於 Oracle 旗下產品。MySQL 是最流行的關系型數據庫管理系統之一,在 WEB 應用方面,MySQL是最好的 RDBMS (Relational Database Management System,關系數據庫管理系統) 應用軟件之一。
MySQL是一種關系型數據庫管理系統,關系數據庫將數據保存在不同的表中,而不是將所有數據放在一個大倉庫內,這樣就增加了速度並提高了靈活性。
MySQL所使用的 SQL 語言是用於訪問數據庫的最常用標准化語言。MySQL 軟件采用了雙授權政策,分為社區版和商業版,由於其體積小、速度快、總體擁有成本低,尤其是開放源碼這一特點,一般中小型網站的開發都選擇 MySQL 作為網站數據庫。
1.5、連接數據庫
命令行連接!!
mysql -uroot -proot --連接數據庫
flush privileges; --刷新權限
--所有語句使用分號結尾
use school --切換數據庫use數據哭名
show tables; --查看數據庫中所有的表
describe student --顯示數據庫中所有表的相關信息
數據庫xxx語言
DDL 定義
DML 操作
DQL 查詢
DCL 控制
2、操作數據庫
操作數據庫 > 操作數據庫中的表 > 操作數據庫表中的數據
MySQL關鍵字不區分大小寫
2.1、操作數據庫
1、創建數據庫
CREATE DATABASE [IF NOT EXISTS] WESTOS;
2、刪除數據庫
DROP DATABASE WESTOS;
3、使用數據庫
USE school;
如果表名或者字段是一個特殊字符,就需要
USE `SCHOOL`
4、查看數據庫
SHOW DATABASE; --查看所有數據庫
學習思路:
- 對照SQLYog可視化歷史查看SQL
- 固定的語法或關鍵字必須要強行記住
2.2、數據庫的列類型
數值
- tinyint 十分小的數據 1個字節
- smallint 較小的數據 2個字節
- int 標准的整數 4個字節 (常用)
- big 較大的數據 8個字節
- float 浮點數 4個字節
- double 雙精度浮點數 8個字節
- decimal 字符串形式的浮點數 金融計算的時候,一般使用decimal
字符串
-
char 字符串固定的大小 0-255
-
varchar 可變字符串 0-65535 常用的變量
-
tinytext 微型文本 2^8-1
-
text 文本串 2^16-1 保存大文本
時間日期
java.util.Date
- date YYYY-MM-DD 日期格式
- time HH:mm:ss 時間格式
- datetime YYYY-MM-DD HH:mm:ss 最常用的時間格式
- timestamp 時間戳
- year 年份表示
null
-
沒有值,未知
-
注意,不要使用null進行運算,結果為null
2.3、數據庫的字段屬性(重點)
Unsigned
- 無符號的整數
- 聲明了該列不能聲明為負數
zerofill
- 0填充
- 不足的位數,使用0來填充,int(3) 5 ---- 005
自增
- 通常理解為自增,自動在上一條記錄的基礎上 +1 (默認)
- 通常用來設計唯一的主鍵 index 必須是整數類型
- 可以自定義來設計主鍵自增的起始值和步長
非空
-
假設設置為not null ,如果不給它賦值,就會報錯
-
null 如果不填寫,默認為null
默認
- 設置默認的值
- sex 默認值為男,如果不指定該列的值,則會有默認的值!
2.4、創建數據庫表
CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '學號',
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`psd` 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
格式:
CREATE TABLE [IF NOT EXISTS] `表名`(
`字段名` 列類型 [屬性] [索引] [注釋],
`字段名` 列類型 [屬性] [索引] [注釋],
`字段名` 列類型 [屬性] [索引] [注釋]
)[表類型][字段集設置][注釋]
常用命令:
顯示表的結構
2.5、數據表的類型
--關於數據庫引擎
/*
INNODB 默認使用
MYISAM 早些年使用
*/
INNODB | MYISAM | |
---|---|---|
事務支持 | 支持 | 不支持 |
數據行鎖定 | 支持 | 不支持 |
外鍵約束 | 支持 | 不支持 |
全文索引 | 不支持 | 支持 |
表空間大小 | 較大,約為2倍 | 較小 |
常規使用操作:
- MYISAM 節約空間,速度較快
- INNODB 安全性高,事務的處理,多表多用戶操作
所有數據庫文件都存在data目錄下,一個文件夾對應一個數據庫
本質還是文件的存儲
MySQL引擎在物理文件上的區別
- INNODB 在數據庫表中只有一個 *.frm文件,以及上級目錄下的ibdata1文件
- MYISAM 對應文件
- *.frm -表結構文件
- *.MYD 數據文件
- *.MYI 索引文件(index)
設置數據表的字符集編碼
推薦使用UTF-8,不使用會出問題。
MySQL默認的是Latin1,不支持中文
在my.ini配置默認編碼UTF-8
2.6、修改刪除表
修改
--修改表名
ALTER TABLE 舊表名 RENAME AS 新表名
--增加表的字段
ALTER TABLE 表名 ADD 字段名 列屬性
--修改表的字段(修改約束)
ALTER TABLE 表名 MODIFY 字段名 新的字段名() --修改約束
ALTER TABLE 表名 CHANGE 字段名 字段名1 () --字段重命名
--刪除表的字段
ALTER TABLE 表名 DROP 字段名
刪除
--刪除表,如果表存在再刪除
DROP TABLE IF EXISTS 表名
所有的創建和刪除操作盡量加上判斷,以免報錯
3、MySQL數據管理
3.1、外鍵(了解即可)
--創建表的時候沒有外鍵
ALTER TABLE `表1` ADD CONSTRAINT `FK_字段名` FOREIGN KEY(`字段名`) REFERENCES `表2`(`字段名`)
ALTER TABLE `student` ADD CONSTRAINT `FK_gradeid` FOREIGN KEY(`gradeid`) REFERENCES `grade`(`gradeid`)
ALTER TABLE `表1` ADD CONSTRAINT `約束名` FOREIGN KEY(`作為外鍵的列`) REFERENCES `表2`(`哪個字段名`)
以上操作為物理外鍵,數據庫級別的外鍵,我們不建議使用
最佳實踐
- 數據庫就是單純的表,只用來存數據,只有行(數據)和 列(字段)
- 我們想使用多張表的數據,想使用外鍵(用程序寫)
3.2、DML語言(全部記住)
數據庫意義:數據存儲、數據管理
DML語言
- insert
- update
- delete
3.3、添加
插入語句
INSERT INTO 表名([字段1,字段2,字段3]) VALUES('值1'),'值2'),('值3')
--主鍵自增我們可以省略主鍵(如果不寫表的字段,它就會一一匹配)
--插入多個數據
INSERT INTO `student`(`name`,`pwd`,`sex`) VALUES ('張三','aaaaa','男')
一一對應
注意:
- 字段和字段之間使用英文逗號隔開
- 字段是可以省略的,但是后面的值必須要一一對應,不能少
- 可以同時插入多條數據,VALUES后面的值,需要使用逗號隔開即可 VALUES(),()
3.4、修改
update 修改誰 條件 set原來的值=新值
--修改學員名字
UPDATE `student` SET `name`=`劉` WHERE id=1;
--需要指定條件,否則會將所有的修改
語法:
UPDATE 表名 set column_name = value where [條件];
條件:where子句運算符 運算符 id等於某個值,大於某個值,在某個區間內修改
操作符會返回布爾值
操作符 | 含義 | 范圍 | 結果 |
---|---|---|---|
= | 等於 | 5=6 | false |
<>或!= | 不等於 | 5<>6 | true |
> | |||
< | |||
>= | |||
<= | |||
BETWEEN...AND | 在某個范圍內 | [2,5] | |
AND | 我和你 && | 5>1 and 1>2 | false |
OR | 我或你 || | 5>1 or 1>2 | true |
--通過多個條件定位數據
UPDATE `student` SET `name`=`劉` WHERE id=1 AND sex=`男`
注意:
- colnum_name 是數據庫的列,盡量帶上``
- 條件,篩選的條件,如果沒有指定,則會修改所有
- value 是一個具體的值,也可以是一個變量
- 多個設置的屬性之間,使用英文逗號隔開
UPDATE student SET `birthday` = CURRENT_TIME WHERE `name` ='LIU' AND sex='男'
3.5、刪除
delete命令
--刪除數據(避免這樣,會將所有數據刪除)
DELETE FROM `student`
--刪除指定數據
DELETE FROM `student` WHERE id=1
TRUNCATE命令
作用:完全清空一個數據庫表,表的結構和索引約束不會變!
--清空student表
TRUNCATE `student`
delete 和 TRUNCATE 的區別
- 相同點:都能刪除數據,都不會刪除表結構
- 不同
- TRUNCATE 重新設置 自增列 計數器會歸零
- TRUNCATE 不會影響事務
CREATE TABLE `test`(
`id` INT(4) NOT NULL AUTO_INCREMENT,
`coll` VARCHAR(20) NOT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=UTF8
INSERT INTO `test`(`coll`) VALUES(`1`),(`2`),(`3`)
DELETE FROM `test` --不會影響自增
TRUNCATE TABLE `test` --自增會歸零
4、DQL查詢數據(最重點)
4.1、DQL
(Data Query Language: 數據查詢語言)
- 所有的查詢操作都用它 Select
- 簡單的查詢,復雜的查詢它都行
- 數據庫中最核心的語言,最重要的語句
- 使用頻率最高的語句
SELECT語法:
SELECT [ALL | DISTINCT]
{* l table.* l [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.2、指定查詢字段
--查詢全部的學生 SELECT 字段 FROM 表
SELECT * FROM student
--查詢指定字段
SELECT `StudentNum` ROM student
--別名,給結果起一個名字 AS 可以給字段和表起別名
SELECT `StudentNum` AS 學號,`StudentName` AS 姓名 FROM student
--函數 Concat(a,b)拼接字符串
SELECT CONCAT('姓名','StudentNum') AS 新名字 FROM student
語法:SELECT 字段 ....FROM 表
去重 distinct
--查詢一下有哪些同學參加了考試,成績
SELECT FROM result --查詢全部的考試成績
SELECT `studentNoFROM result --查詢有哪些同學參加了考試
SELECT DISTINCT `studentNo` FROM result --發現重復數據,去重
作用:去除SELECT查詢出來的結果中重復的數據,重復的數據只顯示一條
數據庫的列(表達式)
SELECT VERSION(--查詢系統版本(函數)
SELECT 100*3-1 AS 計算結果--用來計算(表達式)
SELECT @@auto_increment_increment --查詢自增的步長(變量)
--學員考試成績+1分查看
SELECT `studentNo`, 'studentResult +1 AS '提分后’FROM result
數據庫的表達式: 文本,列,NUll,函數,計算表達式,系統變量
4.3、where條件子句
作用:檢索數據中符合條件的值
檢索的條件由一個或多個表達式組成,結果返回一個布爾值
邏輯運算符
運算符 | 語法 | 描述 |
---|---|---|
and | a and b a&&b | 邏輯與 |
or | a or b a || b | 邏輯或 |
not | not a !a | 邏輯非 |
盡量使用英文字母
--查詢考試成績在95~100分之間
SELECT studentNo, `StudentResult` FROM result
WHERE StudentResult>=95 AND StudentResult<=100
-- and &&
SELECT studentNo, `StudentResult` FROM result
WHERE StudentResult>=95 && StudentResult<=100
--模糊查詢(區間)
SELECT studentNo, studentResult FROM result
WHERE StudentResult BETWEEN 95 AND 100
--除了1000號學生之外的同學的成績
SELECT studentNo,studentResult FROM result
WHERE studentNo !=1000;
-- != not
SELECT studentNo, studentResult FROM result
WHERE NOT studentNo = 1000
迷糊查詢
運算符 | 語法 | 描述 |
---|---|---|
IS NULL | a is null | 如果操作符為null,結果為真 |
IS NOT NULL | a is not null | 如果操作符不為null,結果為真 |
BETWEEN | a between b and c | 若a在b和c之間,則結果為真 |
LIKE | a like b | SQL 匹配,如果a匹配b,則結果為真 |
IN | a in (a1,a2...) | 假設a在a1,或者a2....其中的某一個值中,結果為真 |
--查詢姓劉的同學
-- like結合%(代表0到任意個字符)_(一個字符)
SELECT `StudentNo`, `StudentName` FROM `student`
WHERE StudentName LIKE '劉%'
--查詢姓劉的同學,名字后面只有一個字的
SELECT`StudentNo`,`StudentName` FROM`student
WHERE StudentName LIKE '劉_'
--查詢姓劉的同學,名字后面只有兩個字的
SELECT `StudentNo` , `studentName` FROM istudent`
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);
--查詢在北京的學生
SELECT `StudentNo`, `StudentName` FROM `student`
WHERE `Address` IN('安徽','河南洛陽');
--查詢地址為空的學生null ''
SELECT `StudentNo`, `StudentName ` FROM `student`
WHERE address=''OR address IS NULL
4.4、聯表查詢(JOIN)
-------------------------聯表查詢-----------------------------------
--查詢參加了考試的同學(學號,姓名,科目編號,分數)
SELECT *FROM student
SELECT *FROM result
思路:
1.分析需求,分析查詢的字段來自哪些表,(連接查詢)
2.確定使用哪種連接查詢?7種
3. 確定交叉點(這兩個表中哪個數據是相同的)
判斷的條件:學生表的中 studentNo =成績表studentNo
where 和 on 可以互換,意思同理
SELECT s.studentNO, studentName , SubjectNo,StudentResult
FROM student AS s
INNER JOIN result As r
ON s.studentNO = r.studentNO
--Right Join
SELECT s.studentNO,studentName , subjectNo ,studentResultFROM student s
RIGHT 3OIN result r
ON s.studentNO = r.studentNo
--Left Join
SELECT s.studentNo,studentName , subjectNo , studentResu7tFROM student s
LEFT J0IN result r
ON s.studentNO = r.studentNO
--查詢缺考的同學
SELECT s.studentNO,studentName , SubjectNo, StudentResultFROM student s
LEFT JOIN result r
ON s.studentNO = r.studentNO
WHERE StudentResult IS NULL
操作 | 描述 |
---|---|
inner join | 如果表中至少有一個匹配,就返回行 |
left join | 會從左表中返回所有的值,即使右表中沒有匹配 |
right join | 會從右表中返回所有的值,即使左表中沒有匹配 |
join on 連接查詢
where 等值查詢
--思考題(查詢了參加考試的同學信息:學號,學生姓名,科目名,分數)
/*思路
1.分析需求,分析查詢的字段來自哪些表,student、result、subject(連接查詢)
2.確定使用哪種連接查詢?7種
確定交叉點(這兩個表中哪個數據是相同的)
判斷的條件:學生表的中 studentNo =成績表 studentNo
*/
SELECT s.studentNo, studentName , SubjectName, `studentResult`
FROM student s
RIGHT JOIN result r
ON r.studentNo = s.studentNo
INNER JOIN `subject` sub
ON r.SubjectNo = sub.SubjectNo
--我要查詢哪些數據 select ...
--從那幾個表中查 FROM表xxx Join連接的表on交叉條件
--假設存在一種多張表查詢,慢慢來,先查詢兩張表然后再慢慢增加
-- From left join b
-- From right join b
自連接
自己的表和自己連接,核心:一張表拆為兩張一樣的表
--創建表
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`)
)ENGINE=INNODB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8
INSERT INTO `category`(`categoryid`, `pid`, `categoryName`)
VALUES('2','1','信息技術'),
('3','1','軟件開發'),
('4','3','數據庫'),
('5','1','美術設計'),
('6','3', 'web開發'),
('7', '5', 'ps技術'),
( '8','2','辦公信息');
父類
categoryid | categoryName |
---|---|
2 | 信息技術 |
3 | 軟件開發 |
5 | 美術設計 |
子類
pid | categoryid | categoryName |
---|---|---|
3 | 4 | 數據庫 |
2 | 8 | 辦公信息 |
3 | 6 | web開發 |
5 | 7 | ps技術 |
操作:查詢父類對應的子類
父類 | 子類 |
---|---|
信息技術 | 辦公信息 |
軟件開發 | 數據庫 |
軟件開發 | web開發 |
美術設計 | ps技術 |
-―查詢父子信息:把一張表看為兩個一模一樣的表
SELECT a.`categoryName` AS '父欄目',b.`categoryName` AS '子欄目'
FROM `category` AS a,`category` AS b
WHERE a.`categoryid` = b.`pid`
4.5、分頁和排序
排序
--排序:升序 ASC ,降序DESC
--ORDER BY通過那個字段排序,怎么排--查詢的結果根據成績降序排序
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
分頁
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 0,5
--第一頁 Limit 0,5 (1-1)*5
--第二頁 Limit 5,5 (2-1)*5
--第三頁 Limit 10,5 (3-1)*5
--第N頁 Limit o,5 (n-1) * pagesize,pagesize
--【pagesize:頁面大小】
--【(n-1)* pagesize:起始值】
--【n :當前頁】
--【數據總數/頁面大小=總頁數】
語法:Limite(查詢起始下標,pageSize)
4.6、子查詢
--方式二:使用子查詢(由里及外)
--查詢所有數據庫結構-1 的學生學號
SELECT `StudentNo`, `SubjectNo`, `studentResult`
FROM `result`
WHERE subjectNo =(
SELECT SubjectNo FROM`subject`
WHERE SubjectName ='數據庫結構-1'
)
ORDER BY studentResult DESC
-―在這個基礎上增加一個科目,高等數學-2-―查詢高等數學-2的編號
SELECT DISTINCT s.`studentNo, `studentName`
FROM student s
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 WHERE StudentNo IN (
SELECT StudentNo FROM result WHERE StudentResult>80 AND SubjectNo = (
SELECT SubjectNo FROM `subject` WHERE `SubjectName`= '高等數學-2'
)
)
4.7、分組和過濾
-- 查詢不同課程的平均分,最高分,最低分,平均大於80
-- 核心:(根據不同的課程分組)
SELECT SubjectName, AVG(StudentResult) AS 平均分,MAX(StudentResult) AS 最高分,MIN(StudentResult) AS 最低分
FROM result r
INNER JOIN `subject` sub
ON r.SubjectNo = sub.SubjectNo
GROUP BY r.SubjectNo -- 通過什么字段來分組
HAVING 平均分>80
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.1) -- 向下取整
SELECT RAND() -- 隨機數
SELECT SIGN(-21) -- 判斷一個數的符號 0-0 負數返回 -1 正數返回 1
SELECT CHAR_LENGTH('狂神說堅持就會成功') -- 字符串長度
SELECT CONCAT('我','愛','你') -- 拼接字符串
SELECT INSERT('我喜歡你',1,1,'他') -- 查詢,從某個位置開始替換某個長度
SELECT LOWER('KuangShen') -- 小寫字母
SELECT UPPER('KuangShen') -- 大寫字母
SELECT INSTR('KuangShen','h') -- 返回第一次出現的子串的索引
SELECT REPLACE('狂神說堅持就會成功','堅持','努力') -- 替換出現的指定字符串
SELECT SUBSTR('狂神說堅持就會成功',4,6) -- 返回指定的字符串(源字符串,截取的位置,截取的長度)
SELECT REVERSE('狂神說堅持就會成功') -- 反轉
SELECT NOW() -- 獲取當前的時間
SELECT CURRENT_DATE()
SELECT CURDARE()
SELECT LOCALTIME()
SELECT SYSDATE() -- 系統時間
SELECT DAYOFMONTH(NOW()) -- 一個月中的第幾天 dayofmonth
5.2、聚合函數
函數 | 描述 |
---|---|
COUNT | 計數 |
AVG | 平均 |
MAX | 最大 |
MIN | 最小 |
SUM | 求和 |
SELECT COUNT(`categoryName`) FROM `category` -- COUNT字段,會忽略所有的null值
SELECT COUNT(*) FROM `category` -- 不會忽略null值,
SELECT COUNT(1) FROM `category` -- 忽略所有的null值

5.3、數據庫級別的MD5加密(擴展)
js MD5
什么是MD5?
主要增強算法復雜度和不可逆性
特點:
- 普遍
- 穩定
- 快速
測試MD5加密
-- ============= MD5 加密 ================
CREATE TABLE `test1`(
`id` INT(4) NOT NULL,
`name` VARCHAR(20) NOT NULL,
`psw` VARCHAR(50) NOT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
-- ,明文密碼
INSERT INTO test1 VALUES(1,'zhangsan','123456'),(2,'lisi','123456'),(3,'wangwu','123456')
-- 加密
UPDATE test1 SET psw=MD5(psw) WHERE id = 1
UPDATE test1 SET psw=MD5(psw) -- 加密全部
-- 插入的時候加密
INSERT INTO test1 VALUES(4,'XIAOMING',MD5('123456'))
6、事務
6.1、什么是事務
要么都成功,要么都失敗
一一一一一一一一
1、SQL執行 A 給 B 轉賬 A 1000 -------> 200 B 200
2、SQL執行 B 收到 A的錢 A 800 ------> B 400
一一一一一一一一
將一組SQL放在一個批次中去執行,避免中途出現錯誤導致一方虧損
事務原則:ACID原則
1、原子性 2、一致性 3、隔離性 4、持久性
原子性(Atomicity)
原子性是指事務是一個不可分割的工作單位,事務中的操作要么都發生,要么都不發生。
一致性(Consistency)
事務前后數據的完整性必須保持一致。(800 200 最終結果的和一定是1000 ,不能多也不能少)
隔離性(lsolation)
事務的隔離性是多個用戶並發訪問數據庫時,數據庫為每一個用戶開啟的事務,不能被其他事務的操作數據所干擾,多個並發事務之間要相互隔離。
持久性(Durability)
持久性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來即使數據庫發生故障也不應該對其有任何影響舉個簡單的例子理解以上四點
如果在操作前(事務還沒有提交,恢復到原狀)服務器宕機或者斷電,那么重啟數據庫以后,數據狀態應該為A: 800,B: 200
如果在操作后(事務已經提交,持久化到數據庫)服務器宕機或者斷電,那么重啟數據庫以后,數據狀態應該為A: 600,B: 400
隔離所導致的一些問題
臟讀:
指一個事務讀取了另外一個為提交的數據
100 300
6.1.1、事務實現
-- 手動處理事務
SET autocommit =0 --關閉自動提交
-- 事務開啟
START TRANSACTION --標記一個事務的開始,從這個之后的sql都在同一個事務內
INSERT xx
INSERT Xx
-- 提交:持久化(成功!)COMMIT
-- 回滾:回到的原來的樣子(失敗!)ROLLBACK
-- 事務結束
SET autocommit =l -- 開啟自動提交--了解
SAVEPOINT 保存點名 -- 設置一個事務的保存點Ⅰ
ROLLBACK TO SAVEPOINT 保存點名 -- 回滾到保存點
RELEASE SAVEPOINT 保存點名 -- 撤銷保存點名
模擬轉賬場景
-- 創建賬戶
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
INSERT INTO account(`name`,`money`)
VALUES ('A',2000.00),('B',10000.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、索引
MySQL官方對索引的定義為:索引是幫助MySQL高效獲取數據的數據結構
索引是數據結構
7.1、索引的分類
- 主鍵索引(primary key)
- 唯一的標識,主鍵不可重復,只能有一個
- 唯一的索引(unique key)
- 避免重復的列出現,唯一索引可以重復,多個列可以標識唯一索引
- 常規索引(key/index)
- 默認的,index / key 來設置
- 全文索引(fulltext)
- 在特定的數據庫引擎下才有,MyISAM
- 快速定位數據
基礎語法:
-- 1、創建表的時候增加索引
-- 2、創建完畢后增加索引
-- 顯示所有的索引信息
SHOW INDEX FROM student/(表名)
-- 增加一個全文索引 (索引名) 列名
ALTER TABLE school.student ADD FULLTEXT INDEX `studentName`(`studentName`);
-- EXPLAIN 分析SQL執行情況
EXPLAIN SELECT * FROM student --非全文索引
EXPLAIN SELECT * FROM student WHERE MATCH(studentName) AGAINST('劉')
7.2、測試索引
CREATE TABLE `app_user`(
`id` BIGINT (20)UNSIGNED NOT NULL AUTO_INCREMENT,'name` VARCHAR (50)DEFAULT ''COMMENT '用戶昵稱',`email` VARCHAR(50) NOT NULL COMMENT '用戶郵箱',`phone` VARCHAR(20) DEFAULT ''COMMENT '手機號',
`gender`TINYINT(4)UNSIGNED DEFAULT 'O’COMMENT '性別(0:男;1:女) ',`password` VARCHAR (100)NOT NULL COMMENT '密碼',
`age `TINYINT (4)DEFAULT'0'COMMENT'年齡',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
'update time`TIMESTAMP NULI DEFAUIT CURRENT_TIMESTAMP ON UPDATE CURRENT_TPRIMARY KEY (~ild `)
)ENGINE=工NNODB DEFAULT CHARSET=utf8mb4 COMMENT= 'app用戶表'
-- 插入1萬條數據
DELIMITER $$ -- 寫函數之前必須要寫,標志
CREATE FUNCTION mock_data()
RETURN INT
BEGIN
DECLARE num INT DAFAULT 10000;
DECLARE i INT DAFAULT 0;
WHILE i < num DO
-- 插入語句
INSERT INTO app_user(`name`,`email`,`phone`,`gender`,`password`,`age`)
VALUES(CONCAT('用戶1',I),'1559721314@qq.com',CONCAT('18',FLOOR(RAND()*((999999999-100000000)+100000000)))
,FLOOR(RAND()*2,UUID(),FLOOR(RAND()*100))
,)
SET i=i+1;
END WHILE;
END;
SELECT mock_data();
SELECT * FROM app_user WHERE `name` = '用戶9999';
-- id_表名_字段名
-- CREATE INDEX 索引名 on 表(字段名)
CREATE INDEX id_app_user_name ON app_user(`name`)
索引在小數據量的時候。用處不大,但是在數據大的時候,區別十分明顯
7.3、索引原則
- 索引不是越多越好
- 不要對進程變動數據加索引
- 小數據量的表不需要索引
- 索引一般加載常用來查詢的字段上
索引的數據結構
Hash類型的索引
Btree:InnoDB的默認數據結構
8、權限管理和備份
8.1、用戶權限管理
SQL yog 可視化管理
點擊小人兒,可以添加刪除新的用戶
注意:主機當時是什么,登錄的時候就得保持一致
SQL命令操作
用戶表:
-- 創建用戶 CREATE USER 用戶名 IDENTIFIED BY '密碼'
-- 修改密碼 (修改當前用戶密碼) 選中當前的用戶
SET PASSWORD = PASSWORD('111111')
-- 修改制定用戶密碼
SET PASSWORD FOR kuangshen = PASSWORD('111111')
-- 用戶重命名
RENAME USER 原名字 TO 新名字
RENAME USER kuagnshen TO kuangshen2
-- 用戶授權 ALL PRIVILEGES 全部的權限 庫.表
-- ALL PRIVILEGES 除了給別人授權,其他都能干 (GRAN)
GRANT ALL PRIVILEGES ON *.* TO kuangshen2
-- 查詢權限
-- 查看指定用戶的權限
SHOW GRANTS FOR kaungshen2
-- 撤銷權限 REVOKE 哪些權限,在哪個庫撤銷,給誰撤銷
REVOKE ALL PRIVILEGES ON *.* FROM kaungshen2
8.2、MySQL備份
為什么備份:
- 保證重要的數據不會丟失
- 數據轉移
MySQL數據庫備份的方式
- 直接拷貝物理文件
- 在SQLyog這種可視化工具中手動導出
- 選中庫或者表,右鍵,導出或備份
- 使用命令行導出
# mysqldump -h 主機 -u 用戶名 -p 密碼 數據庫 表名 > 物理磁盤位置/文件
假設你要備份數據庫,防止數據丟失
9、規范數據庫設計
9.1、為什么需要設計
當數據庫比較復雜的時候,我們就需要設計了
糟糕的數據庫設計:
- 數據冗余,浪費空間
- 數據庫的插入和刪除都會麻煩,異常【屏蔽使用物理外鍵】
- 程序的性能差
良好的數據庫設計:
- 節省內存空間
- 保證數據的完整性
- 方便我們開發系統
軟件開發中,關於數據庫的設計
- 分析需求:分析業務和需要處理的數據的需求
- 概要設計:設計關系 E-R 圖
設計數據庫的步驟:(個人博客)
-
收集信息,分析需求
- 用戶表(用戶登錄注銷,用戶的個人信息,寫博客,創建分類)
- 分類表 (文章分類,誰創建的)
- 文章表 (文章的信息)
- 友鏈表 (友鏈信息)
- 自定義表 (系統信息,某個關鍵的字,或者一些主字段) key:value
-
標識實體 (把需求落實到每個字段)
-
標識實體之間的關系
- 寫博客:user--->blog
- 創建分類:user--->category
- 關注:user--->user
- 友鏈:links
- 評論:user--->user -->>blog
9.2、三大范式
為什么要數據規范化?
- 信息重復
- 更新異常
- 插入異常
- 無法正常顯示信息
- 刪除異常
- 丟失有效信息
三大范式:
第一范式(1NF)
原子性:要求數據庫表的每一列都是不可分割的原子數據項。
第二范式(2NF)
前提:滿足第一范式
每張表只描述一件事
在1NF的基礎上,非碼屬性必須完全依賴於候選碼(在1NF基礎上消除非主屬性對主碼的部分函數依賴)
第二范式需要確保數據庫表中的每一列都和主鍵相關,而不能只與主鍵的某一部分相關(主要針對聯合主鍵而言)。
第三范式(3NF)
第三范式需要確保數據表中的每一列數據都和主鍵直接相關,而不能間接相關。
規范性 和 性能 的問題
關聯查詢的表不能超過三張表
- 考慮商業化的需求和目標(成本,用戶體驗) 數據庫的性能更加重要
- 在考慮性能的問題的時候。需要適當的考慮一下規范性
- 故意給某些表增加一些榮譽的字段(從多表查詢中變為單表查詢)
- 故意增加一些計算列(從大數據量降低為小數據量的查詢:索引)
10、JDBC(重點)
10.1、數據庫驅動
SUN公司為了簡化開發人員的(對數據庫的統一)操作,提供了一個(Java操作數據庫的)規范,俗稱JDBC這些規范的實現由具體的廠商去做
對於開發人員來說,我們只需要掌握JDBC接口的操作即可!
10.2、JDBC
java.sql
javax.sql
還需要導入一個數據庫驅動包:mysql-connector-java-5.1.47
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,'zhangsan','123456','zs@sina.com','1980-12-04'),
(2,'lisi','123456','lisi@sina.com','1981-12-04'),
(3,'wangwu','123456','wangwu@sina.com','1982-12-04');
2、導入架包
3、編寫測試代碼
//我的第一個jdbc程序
public class JdbcFirstDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1、加載驅動
Class.forName("com.mysql.jdbc.Driver");
//2、用戶信息和url
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSl=true";
String username = "root";
String password = "root";
//3、連接成功,數據庫對象 connection代表數據庫
Connection connection = DriverManager.getConnection(url, username, password);
//4、執行SQL的對象 Statement執行SQL的對象
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("password=" + resultSet.getObject("PASSWORD"));
System.out.println("email=" + resultSet.getObject("email"));
System.out.println("birth=" + resultSet.getObject("birthday"));
System.out.println("============================================");
}
//6、釋放連接
resultSet.close();
statement.close();
connection.close();
}
}
步驟總結:
1、加載驅動
2、連接數據庫 DriverManager
3、獲取執行SQL的對象 Statement
4、獲得返回的結果集
5、釋放連接
10.4、statement對象
JDBC中的statement對象用於向數據庫發送SQL語句,想完成對數據庫的增刪改查,只需要通過這個對象向數據庫發送增刪改查即可
Statement對象中的executeUpdate方法,用於向數據庫發送增、刪、改的SQL語句,executeUpdate執行完之后,將會返回一個整數
(即增刪改語句導致了數據庫的幾行數據發生了改變)
Statement.executeQuery用於向數據庫發送查詢語句,executeQuery方法返回代表查詢結果的ResultSet對象。
CRUD操作-create
使用executeUpdate(String sql)方法完成數據添加操作,示例操作:
Statement st = connection.createStatement;
String sql = "insert into user(...) values(...)";
int num = st.executeUptate(sql);
if(num > 0){
System.out.println("插入成功!!")
}
CRUD操作-delete
使用executeUpdate(String sql)方法完成數據刪除操作,示例操作:
Statement st = connection.createStatement;
String sql = "delete from user where id=1";
int num = st.executeUptate(sql);
if(num > 0){
System.out.println("刪除成功!!")
}
CRUD操作-update
使用executeUpdate(String sql)方法完成數據修改操作,示例操作:
Statement st = connection.createStatement;
String sql = "update user set name='' where name=''";
int num = st.executeUptate(sql);
if(num > 0){
System.out.println("修改成功!!")
}
CRUD操作-read
使用executeQuery(String sql)方法完成數據修改操作,示例操作:
Statement st = connection.createStatement;
String sql = "select * from user where id=1"
ResultSet resultSet = statement.executeQuery(sql);
while(resultSet.next()){
//根據獲取列的整數類型,分別調用rs的相應方法映射到java對象中
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("birth=" + resultSet.getObject("birthday"));
System.out.println("============================================");
}
代碼實現
1、提取工具類
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 inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties preoperties = new Properties();
preoperties.load(inputStream);
driver = preoperties.getProperty("driver");
url = preoperties.getProperty("url");
username = preoperties.getProperty("username");
password = preoperties.getProperty("password");
//1、驅動只加載一次
Class.forName(driver);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
//獲取連接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, username, password);
}
//釋放連接資源
public static void release(Connection connection, Statement statement, ResultSet resultSet) {
if(resultSet!=null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement!=null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection!=null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
2、編寫增刪改的方法:executeUpdate
增:
import com.liu.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestInsert {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection(); //獲取數據連接
Statement st = connection.createStatement();
String sql = "INSERT INTO users(id,`name`,`password`,`email`,`birthday`)" +
"VALUES(4,'kuangshen','123456','1456548@qq.com','2021-8-10')";
int i = st.executeUpdate(sql);
if (i>0){
System.out.println("插入成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,statement,resultSet);
}
}
}
刪:
import com.liu.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestDelete {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection(); //獲取數據連接
Statement st = connection.createStatement();
String sql = "DELETE FROM users WHERE id=4";
int i = st.executeUpdate(sql);
if (i>0){
System.out.println("刪除成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,statement,resultSet);
}
}
}
改:
import com.liu.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestUpdate {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection(); //獲取數據連接
Statement st = connection.createStatement();
String sql = "UPDATE users SET `name`='kuangshen',email='98764@qq.com' WHERE id=1";
int i = st.executeUpdate(sql);
if (i>0){
System.out.println("更新成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,statement,resultSet);
}
}
}
3、查詢
import com.liu.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestUpdate {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection(); //獲取數據連接
Statement st = connection.createStatement();
String sql = "UPDATE users SET `name`='kuangshen',email='98764@qq.com' WHERE id=1";
int i = st.executeUpdate(sql);
if (i>0){
System.out.println("更新成功!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,statement,resultSet);
}
}
}
SQL注入的問題
SQL存在漏洞,會被攻擊導致數據泄露。SQL會被拼接 or
import com.liu.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SQL注入 {
public static void main(String[] args) {
login(" 'or '1=1"," 'or'1=1");
}
public static void login(String username,String password){
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
statement = connection.createStatement();
String sql = "select * from users where `NAME` = '" + username + "' AND `password` = '" + password + "'";
resultSet = statement.executeQuery(sql);//查詢完返回一個結果集
while(resultSet.next()){
System.out.println(resultSet.getString("NAME")+resultSet.getString("password"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,statement,resultSet);
}
}
}
10.5、PreparedStatement對象
PreparedStatement可以防止SQL注入,效率更高!
1、新增
import com.liu.lesson02.utils.JdbcUtils;
import javax.xml.crypto.Data;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestInsert {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtils.getConnection();
//區別
//使用?占位符代替參數
String sql = "insert into users(id,`name`,`password`,`email`,`birthday` ) values(?,?,?,?,?)";
preparedStatement = connection.prepareStatement(sql);//預編譯SQL,先編寫SQL,然后不執行
//手動給參數賦值
preparedStatement.setInt(1,4);
preparedStatement.setString(2,"junye");
preparedStatement.setString(3,"321654");
preparedStatement.setString(4,"1559721314@qq.com");
//注意點 sql.Date() 數據庫
// util.Date() java
preparedStatement.setString(5,"2000-08-10");
//執行
int i = preparedStatement.executeUpdate();
if(i>0){
System.out.println("插入成功!!!!!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,preparedStatement,null);
}
}
}
2、刪除
import com.liu.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestDelete {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtils.getConnection();
//區別
//使用?占位符代替參數
String sql = "delete from users where id=?";
preparedStatement = connection.prepareStatement(sql);//預編譯SQL,先編寫SQL,然后不執行
//手動給參數賦值
preparedStatement.setInt(1,4);
//執行
int i = preparedStatement.executeUpdate();
if(i>0){
System.out.println("刪除成功!!!!!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,preparedStatement,null);
}
}
}
3、更新
import com.liu.lesson02.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestUpdate {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = JdbcUtils.getConnection();
//區別
//使用?占位符代替參數
String sql = "update users set `NAME`=? where id=?";
preparedStatement = connection.prepareStatement(sql);//預編譯SQL,先編寫SQL,然后不執行
//手動給參數賦值
preparedStatement.setString(1,"俊爺");
preparedStatement.setInt(2,1);
//執行
int i = preparedStatement.executeUpdate();
if(i>0){
System.out.println("更新成功!!!!!");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,preparedStatement,null);
}
}
}
4、查詢
import com.liu.lesson02.utils.JdbcUtils;
import java.awt.image.RescaleOp;
import java.sql.*;
public class TestQuery {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement =null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
String sql = "select * from users where id=?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,1);//傳遞參數
resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
System.out.println(resultSet.getString("NAME"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,preparedStatement,resultSet);
}
}
}
5、防止SQL注入
import com.liu.lesson02.utils.JdbcUtils;
import java.sql.*;
public class SQL注入 {
public static void main(String[] args) {
login("junye","321654"); //可以正常查詢
login(" 'or '1=1"," 'or'1=1");//無法查詢到
}
public static void login(String username,String password){
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = JdbcUtils.getConnection();
//PreparedStatement 防止SQL注入的本質,把傳遞進來的參數當做字符
//假設其中存在轉義字符,不被'' 會被直接轉義
String sql = "select * from users where `NAME`=? and `password`=?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,username);
preparedStatement.setString(2,password);
resultSet = preparedStatement.executeQuery();//查詢完返回一個結果集
while(resultSet.next()){
System.out.println(resultSet.getString("NAME")+resultSet.getString("password"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.release(connection,preparedStatement,resultSet);
}
}
}
10.6、事務
ACID原則
原子性:要么都成功,要么都失敗
一致性:前后的總數是一致的
持久性:一旦提交就不可逆,持久化到數據庫
隔離性:多個進程之間互不干擾
隔離性的問題:
- 臟讀:一個事物讀取了另外一個沒有提交的事物
- 不可重復讀:在同一個事務內,重復讀取表中數據,表數據發生了改變
- 虛讀(幻讀):在一個事物內,讀取了別人插入的數據,導致前后讀出來的救過不一致
代碼實現
1、開啟事務 connection.setAutoCommit(false)
2、一組業務執行完畢,提交事務
3、可以在catch語句中顯示的定義回滾語句,但默認失敗就會回滾
10.7、數據庫連接池
數據庫連接-----執行完畢------釋放
連接----釋放 十分消耗資源
池化技術:預先准備好需要的資源,過來就可以連接
編寫連接池,實現一個接口 DataSource
開源數據源實現
DBCP
C3P0
Druid:阿里巴巴
使用這些數據庫連接池后,我們在項目開發中就不需要編寫連接數據庫的代碼了。
DBCP
需要用到jar包
commons-pool-1.6、commons-dbcp-1.4
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!--
c3p0的缺省(默認)配置
如果在代碼中ComboPooledDataSource ds=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&useSSL=true</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="acquiredIncrement">5</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
</default-config>
<!--c3p0的命名配置
如果在代碼中ComboPooledDataSource ds=new ComboPooledDataSource(MySQL);這樣寫就表示使用的是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&useSSL=true</property>
<property name="user">root</property>
<property name="password">root</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>