MySQL學習筆記(狂神)


1.初時MySQL

  • MySQL是一個關系型數據庫管理系統

  • MySQL是一種關系型數據庫管理系統,關系數據庫將數據保存在不同的表中,而不是將所有數據放在一個大倉庫內,這樣就增加了速度並提高了靈活性。

  • 連接 MySQL

    格式:mysql -h 主機地址 -u 用戶名 -p 用戶密碼

    1.例1:連接到本機上的MYSQL。

    首先在打開 DOS 窗口,然后進入目錄 mysqlbin,再鍵入命令mysql -uroot -p,回車后提示你輸密碼,如果剛安裝好MYSQL,超級用戶root 是沒有密碼的,故直接回車即可進入到 MySQL 中了,MySQL 的提示符是:mysql>

    2.例2:連接到遠程主機上的MYSQL。假設遠程主機的IP為:110.110.110.110,用戶名為root,密碼為abcd123。則鍵入以下命令:

    mysql -h110.110.110.110 -uroot -pabcd123

    (注:u與root可以不用加空格,其它也一樣)

    3.退出 MySQL 命令:exit (回車)

    注意:想要成功連接到遠程主機,需要在遠程主機打開MySQL遠程訪問權限

    方法如下:

    在遠程主機中以管理員身份進入

    輸入如下命令

    mysql>GRANT ALL PRIVILEGES ON . TO 'agui'@%'IDENTIFIEDBY '123' WITH GRANT OPTION;

    FLUSH PRIVILEGES;

    //賦予任何主機訪問數據的權限

    mysql>FLUSH PRIVILEGES

    //修改生效

    agui為我們使用的用戶名

    密碼為 123

    即:在遠程主機上作好設置,我們即可通過mysql -h110.110.110.110 -uagui -p123連接進遠程主機

    修改密碼

    格式:mysqladmin -u用戶名 -p 舊密碼 -password 新密碼

    1.例1:給root加個密碼ab12。首先在DOS下進入目錄mysqlbin,然后鍵入以下命令

    mysqladmin -uroot -password ab12

    注:因為開始時root沒有密碼,所以-p舊密碼一項就可以省略了。

    2.例2:再將root的密碼改為djg345。

    mysqladmin -uroot -pab12 -password djg345

    增加新用戶

    (注意:和上面不同,下面的因為是 MySQL 環境中的命令,所以后面都帶一個分號作為命令結束符)

    格式:grant select on 數據庫.* to 用戶名@登錄主機 identified by “密碼”

    例1、增加一個用戶 test1 密碼為 abc,讓他可以在任何主機上登錄,並對所有數據庫有查詢、插入、修改、刪除的權限。首先用以 root 用戶連入 MySQL,然后鍵入以下命令:

    grant select,insert,update,delete on . to test1@“%” Identified by “abc”;

    但例1增加的用戶是十分危險的,你想如某個人知道test1的密碼,那么他就可以在internet上的任何一台電腦上登錄你的mysql數據庫並對你的數據可以為所欲為了,解決辦法見例2。

    例2、增加一個用戶 test2 密碼為 abc,讓他只可以在 localhost 上登錄,並可以對數據庫 mydb 進行查詢、插入、修改、刪除的操作(localhost指本地主機,即MYSQL數據庫所在的那台主機),這樣用戶即使用知道test2的密碼,他也無法從internet上直接訪問數據庫,只能通過MYSQL主機上的web頁來訪問了。

    grant select, insert, update, delete on mydb.* to test2@localhost identified by “abc”;

    如果你不想 test2 有密碼,可以再打一個命令將密碼消掉。

    grant select, insert, update, delete on mydb.* to test2@localhost identified by “”;

    下面來看看 MySQL 中有關數據庫方面的操作。注意:必須首先登錄到 MySQL 中,以下操作都是在 MySQL 的提示符下進行的,而且每個命令以分號結束。

    操作技巧

    1.如果你打命令時,回車后發現忘記加分號,你無須重打一遍命令,只要打個分號回車就可以了。也就是說你可以把一個完整的命令分成幾行來打,完后用分號作結束標志就 OK。

    2.你可以使用光標上下鍵調出以前的命令。但以前我用過的一個 MySQL 舊版本不支持。我用的是mysql-3.23.27-beta-win。

    顯示命令

    1.顯示數據庫列表。

    show databases;

    剛開始時才兩個數據庫:mysql 和 test。mysql 庫很重要它里面有 MySQL 的系統信息,我們改密碼和新增用戶,實際上就是用這個庫進行操作。

    2.顯示庫中的數據表:

    use mysql; //打開庫,學過 FOXBASE 的一定不會陌生吧

    show tables;

    3.顯示數據表的結構:

    describe 表名;

    4.建庫:

    create database 庫名;

    5.建表:

    use 庫名;

    create table 表名 (字段設定列表);

    6.刪庫和刪表:

    drop database 庫名;

    drop table 表名;

    7.將表中記錄清空:

    delete from 表名;

    8.顯示表中的記錄:

    select * from 表名;

    9.顯示最后一個執行的語句所產生的錯誤、警告和通知:

    show warnings;

    10.只顯示最后一個執行語句所產生的錯誤:

    show errors;

 

2 .操作數據庫

2.1 操作數據庫(了解)

1.命令行連接: MySQL-uroot-p123456

此處123456是密碼

2.啟動 net start mysql

3.刷新權限 flush privileges;

4.查看全部的數據庫 show database;

5.使用數據庫 use school --這里school是數據庫名

6.查看數據庫中所有的表 show tables;

7.顯示數據庫中表(student)的所有信息 describe student

--describe student等同於show columns from customers

8.創建一個數據庫 create if exits database xxx;

9.刪除一個數據庫 drop database if exits xxx

10.使用(如果表名或字段是一個特殊字符,就需要帶"``")

use `school`

11.查表 在student表中查詢user信息

select `user` from student

12.查數據庫 show database

2.2 數據庫的列類型

數值 tinyint 1字節
  smallint 2字節
  mediumint 3字節
  int 4字節(常用)
  bigint 8字節
  float 4字節
  double 8字節
  decimal 字符串形式的浮點數,金融計算常用
字符串 char 固定大小 0~255
  varchar 可變字符串 0~65535(常用)
  tinytext 微型文本 2^8-1
  text 文本串 2^16-1(常用)
時間日期 data 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來填充, int(3), 5---005

自增AUTO_INCREMENT:

通常理解為自增,自動在上一條記錄的基礎上+1(默認)

通常用來設計唯一的主鍵~index,必須是整數類型

可以自定義設計主鍵自增的起始值和步長(在高級設置那里)

非空 NULL NOT ULL:

假設設置為not null,如果不給它賦值,就會報錯! 如果不填寫值,默認就是null

默認default:

設置默認值

如sex,默認值為男,如果不指定該列的值,則為男

拓展:聽聽就好

/*每一個表,都必須存在以下五個字段!未來做項目用的,表示一個記錄存在的意義
id 主鍵
version 樂觀鎖
is_delete 偽刪除
gmt_create 創建時間
gmt_update 修改時間
*/

2.4 創建數據表

-- 創建學生表: 使用SQL創建
-- 學號int:登陸密碼varchar(20),姓別varchar(2),出生日期(datatime),家庭住址,email
-- AUTO_INCREMENT自增
-- comment注釋
-- 字符串使用單引號括起來
-- 所有的語句后面加,(英文的),最后一個不用加
CREATE TABLE IF NOT EXISTS `student` (
 `id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '學號',
 `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

 

格式

CREATE TABLE[IF NOT EXISTS] `表名`(
'字段名' 列類型 [屬性] [索引] [注釋],  
'字段名' 列類型 [屬性] [索引] [注釋], 
......
'字段名' 列類型 [屬性] [索引] [注釋], 
)[表類型][字符集設置][注釋]-- "[]"中表示不是必須寫的

 

 

2.5 數據表的類型

-- 創建學生表: 使用SQL創建
-- 學號int:登陸密碼varchar(20),姓別varchar(2),出生日期(datatime),家庭住址,email
-- AUTO_INCREMENT自增
-- comment注釋
-- 字符串使用單引號括起來
-- 所有的語句后面加,(英文的),最后一個不用加
CREATE TABLE IF NOT EXISTS `student` (
 `id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '學號',
 `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
​
`student`
SHOW CREATE DATABASE school -- 查看創建數據庫的語句
SHOW CREATE TABLE student -- 查看student數據表的定義語句
DESC student -- 顯示表的結構
-- 關於數據庫引擎
/*
INNODB 默認使用
MYISAM 早年使用
*/

 

 

關於數據庫引擎

  MYISAM INNODB
事務支持 不支持 支持
數據行鎖定 不支持 支持
外鍵約束 不支持 支持
全文索引 支持 不支持
表空間的大小 較小 較大,約為MYISAM的2倍

常規使用操作:

1.MYISAM 節約空間速度較快

2.INNODB 安全,事務處理,多表用戶操作

在物理空間存在的位置

所有的數據庫文件都存在data目錄下

本質還是文件的存儲

MySQL引擎在物理文件上的區別

//8.0版本沒用frm

  1. INNODB 在數據庫表中只有一個*.frm 文件,以及上級目錄下的ibdata1文件

  2. MYISAM對應文件

    *.frm 表結構的定義文件

    *.MYD 數據文件(data)

    *.MYI 索引文件(index)

 

設置數據庫表的字符集編碼

CHARSET=utf8

不設置的的話,回事MySQL默認的字符集編碼Latin1(不支持中文)

也可以在my.ini中配置默認的編碼(但不建議)

character-set-server=utf8

 

2.6 修改刪除表

修改

-- 修改表名    ALTER TABLE 舊表名 RENAME AS 新表名
ALTER TABLE teacher RENAME AS teacher1

-- 增加表的字段 ALTER TABLE 表名 ADD 字段名 列屬性
ALTER TABLE teacher1 ADD age INT(11)

-- 修改表的字段 (重命名,修改約束!)
ALTER TABLE teacher1 MODIFY age VARCHAR(11) -- 修改約束
ALTER TABLE teacher1 CHANGE age age1 INT(1) -- 字段重命名

-- 刪除表的字段
ALTER TABLE teacher1 DROP age1

 

 

刪除

-- 刪除表
DROP TABLE IF EXISTS teacher1

==所有創建和刪除操作盡量加上判讀,以免報錯==

 

注意點:

1.`` 字段名,使用這個包裹

2.注釋 --/**/

3.sql關鍵字大小寫不敏感,建議寫小寫

 

3.MySQL數據管理

3.1 外鍵(了解就好)

-- 方式一:在創建表的時候,增加約束(麻煩)
CREATE TABLE IF NOT EXISTS `grade`(
`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年級id',
`gradename` VARCHAR(50) NOT NULL COMMENT '年級名稱',
PRIMARY KEY(`gradeid`)
)
ENGINE=INNODB DEFAULT CHARSET=utf8

-- 學生表的gradeid字段要去引用年級表的gradeid
--
定義外鍵key,再給這個外鍵添加約束
CREATE TABLE IF NOT EXISTS student (
id
INT(4) NOT NULL AUTO_INCREMENT COMMENT '學號',
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 '出生日期',
gradeid
INT(10) NOT NULL COMMENT '學生的年級',
address
VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
email
VARCHAR(50) DEFAULT NULL COMMENT '郵箱',
PRIMARY KEY (id) ,
KEY FK_gradeid (gradeid) , -- 先定義一個key
CONSTRAINT FK_gradeid FOREIGN KEY (gradeid) REFERENCES grade(gradeid)-- 再加一個約束
)
ENGINE
=INNODB DEFAULT CHARSET=utf8

 

當刪除有外鍵關系的表的時候,必須要先刪除引用別人的表(從表),再刪除被引用的表(主表)

 

-- 方式二 創建表成功后,添加外鍵約束
create table IF NOT EXISTS `grade`(
`gradeid` int(10) not null auto_increment COMMENT '年級id',
`gradename` varchar(50) not null comment '年級名稱',
primary key(`gradeid`)
)
ENGINE=INNODB DEFAULT CHARSET=utf8

CREATE TABLE IF NOT EXISTS student (
id
INT(4) NOT NULL AUTO_INCREMENT COMMENT '學號',
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 '出生日期',
gradeid
int(10) not null comment '學生的年級',
address
VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
email
VARCHAR(50) DEFAULT NULL COMMENT '郵箱',
PRIMARY KEY (id)
)
ENGINE
=INNODB DEFAULT CHARSET=utf8

-- 創建表時沒有外鍵關系
alter table student
add constraint FK_gradeid FOREIGN KEY(gradeid) referenceS grade(gradeid);

-- ALTER TABLE 表名
--
ADD CONSTRAINT 約束名 FOREIGN KEY(作為外鍵的列) REFERENCES 哪個表(哪個字段);

 

 

以上操作均為物理外鍵,是數據庫級別的外鍵,我們不建議使用!避免數據庫太多造成困擾(了解即可)


最佳實踐

數據庫就是單純的表,只用來存數據,只有行(數據)和列(字段)

我們想使用多張表的數據,想使用外鍵,我們用程序來實現

 

3.2 DML語言(全部記住)

數據庫意義:數據存儲,數據管理

DML語言:數據操作語言

insert

update

delete

3.3 添加insert

insert

-- 插入語句(添加)
-- insert into 表名([字段名1,字段2,字段3]) values('值1','值2','值3',......)
INSERT INTO `grade`(`gradename`) VALUES('大四')

-- 由於主鍵自增我們可以省略(如果不寫表的字段,他就會一一匹配)
INSERT INTOgrade VALUES ('大三')

-- 一般寫插入語句,我們一定要數據和字段一一對應!
--
插入多個字段
INSERT INTO student(name,pwd,sex,gradeid) VALUES ('張三','aaa','','3')
INSERT INTO student(name,pwd,sex,gradeid)
VALUES('李四','bbb','','4'),('王五','ccc','','5')

 

注意事項:

1.字段和字段之間使用英文逗號隔開

2.字段是可以省略的,但是后面的值必須要一一對應,不能少

3.可以同時插入多條數據,VALUES后面的值,需要使用逗號隔開即可

values(),(),...

3.4 修改update

update 修改誰(條件) set原來的值=新值

-- 修改學員名字
UPDATE `student` SET `name`='狂神' WHERE id =1;
-- 不指定條件的情況下,會改動所有的表
UPDATE `student` SET `name`='長江七號'
-- 語法:
-- UPDATE 表名 set column_name =value where [條件]

-- 修改多個屬性用逗號隔開
UPDATE student SET name='狂神',email='123@qq.com' WHERE id =1;

 

條件: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`='長江7號' WHERE `name` ='狂神44' AND sex='女'

 

3.5 刪除 delete

delete命令

語法:delete

-- 刪除數據(避免這樣寫,會全部刪除)
DELETE FROM `student`
-- 刪除指定數據
DELETE FROM  `student` WHERE id=1;

 

TRUNCATE命令

作用:完全清空一個數據庫,表的結構和索引約束不會變

-- 清空student表
TRUNCATE `student`

delete與truncate的區別

相同點:都能刪除數據,而且都不會刪除表結構

不同:

TRUNCATE 重新設置 自增列 計數器會歸零

TRUNCATE 不會影響事務

-- 測試delete與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 -- 自增會歸零

 

了解即可:delete刪除的問題,重啟數據庫,現象

1.innodb 自增列會從1開始(存在內存當中,斷電即失)

2.myisam 繼續從上一個自增量開始(存在文件中的,不會丟失)

 

4.DQL查詢數據(最重點)

用的代碼

create database if not exists `school`;
-- 創建一個school數據庫
use `school`;-- 創建學生表
drop table if exists `student`;
create table `student`(
    `studentno` int(4) not null comment 學號,
    `loginpwd` varchar(20) default null,
    `studentname` varchar(20) default null comment 學生姓名,
    `sex` tinyint(1) default null comment 性別,0或1,
    `gradeid` int(11) default null comment 年級編號,
    `phone` varchar(50) not null comment 聯系電話,允許為空,
    `address` varchar(255) not null comment 地址,允許為空,
    `borndate` datetime default null comment 出生時間,
    `email` varchar (50) not null comment 郵箱賬號允許為空,
    `identitycard` varchar(18) default null comment 身份證號,
    primary key (`studentno`),
    unique key `identitycard`(`identitycard`),
    key `email` (`email`)
)engine=myisam default charset=utf8;

-- 創建年級表
drop table if exists grade;
create table grade(
gradeid
int(11) not null auto_increment comment '年級編號',
gradename
varchar(50) not null comment '年級名稱',
primary key (gradeid)
) engine
=innodb auto_increment = 6 default charset = utf8;

-- 創建科目表
drop table if exists subject;
create table subject(
subjectno
int(11) not null auto_increment comment '課程編號',
subjectname
varchar(50) default null comment '課程名稱',
classhour
int(4) default null comment '學時',
gradeid
int(4) default null comment '年級編號',
primary key (subjectno)
)engine
= innodb auto_increment = 19 default charset = utf8;

-- 創建成績表
drop table if exists result;
create table result(
studentno
int(4) not null comment '學號',
subjectno
int(4) not null comment '課程編號',
examdate
datetime not null comment '考試日期',
studentresult
int (4) not null comment '考試成績',
key subjectno (subjectno)
)engine
= innodb default charset = utf8;

-- 插入學生數據 其余自行添加 這里只添加了2行
insert into student (studentno,loginpwd,studentname,sex,gradeid,phone,address,borndate,email,identitycard)
values
(
1000,'123456','張偉',0,2,'13800001234','北京朝陽','1980-1-1','text123@qq.com','123456198001011234'),
(
1001,'123456','趙強',1,3,'13800002222','廣東深圳','1990-1-1','text111@qq.com','123456199001011233');

-- 插入成績數據 這里僅插入了一組,其余自行添加
insert into result(studentno,subjectno,examdate,studentresult)
values
(
1000,1,'2013-11-11 16:00:00',85),
(
1000,2,'2013-11-12 16:00:00',70),
(
1000,3,'2013-11-11 09:00:00',68),
(
1000,4,'2013-11-13 16:00:00',98),
(
1000,5,'2013-11-14 16:00:00',58);

-- 插入年級數據
insert into grade (gradeid,gradename) values(1,'大一'),(2,'大二'),(3,'大三'),(4,'大四'),(5,'預科班');

-- 插入科目數據
insert into subject(subjectno,subjectname,classhour,gradeid)values
(
1,'高等數學-1',110,1),
(
2,'高等數學-2',110,2),
(
3,'高等數學-3',100,3),
(
4,'高等數學-4',130,4),
(
5,'C語言-1',110,1),
(
6,'C語言-2',110,2),
(
7,'C語言-3',100,3),
(
8,'C語言-4',130,4),
(
9,'Java程序設計-1',110,1),
(
10,'Java程序設計-2',110,2),
(
11,'Java程序設計-3',100,3),
(
12,'Java程序設計-4',130,4),
(
13,'數據庫結構-1',110,1),
(
14,'數據庫結構-2',110,2),
(
15,'數據庫結構-3',100,3),
(
16,'數據庫結構-4',130,4),
(
17,'C#基礎',130,1);

 

 

4.1 DQL

(Data Query Language:數據查詢語言)

1.所有的查詢操作都用它 Select

2.簡單的查詢,復雜的查詢它都能做

3.數據庫中最核心的語言

3.使用頻率最高的語言

SELECT語法

SELECT
    [ALL | DISTINCT | DISTINCTROW ]
      [HIGH_PRIORITY]
      [STRAIGHT_JOIN]
      [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
      [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
    select_expr [, select_expr ...]
    [
 FROM table_references
  [PARTITION partition_list</span><span style="color: #ff0000;">]</span>
<span style="color: #ff0000;">[</span><span style="color: #ff0000;">WHERE where_condition</span><span style="color: #ff0000;">]</span>
<span style="color: #ff0000;">[</span><span style="color: #ff0000;">GROUP BY {col_name | expr | position}
  [ASC | DESC</span><span style="color: #ff0000;">]</span>, ... <span style="color: #ff0000;">[</span><span style="color: #ff0000;">WITH ROLLUP</span><span style="color: #ff0000;">]</span><span style="color: #000000;">]
</span><span style="color: #ff0000;">[</span><span style="color: #ff0000;">HAVING where_condition</span><span style="color: #ff0000;">]</span>
<span style="color: #ff0000;">[</span><span style="color: #ff0000;">ORDER BY {col_name | expr | position}
  [ASC | DESC</span><span style="color: #ff0000;">]</span><span style="color: #000000;">, ...]
</span><span style="color: #ff0000;">[</span><span style="color: #ff0000;">LIMIT {[offset,</span><span style="color: #ff0000;">]</span> row_count <span style="color: #808080;">|</span><span style="color: #000000;"> row_count OFFSET offset}]
</span><span style="color: #ff0000;">[</span><span style="color: #ff0000;">PROCEDURE procedure_name(argument_list)</span><span style="color: #ff0000;">]</span>
<span style="color: #ff0000;">[</span><span style="color: #ff0000;">INTO OUTFILE 'file_name'
    [CHARACTER SET charset_name</span><span style="color: #ff0000;">]</span><span style="color: #000000;">
    export_options
  </span><span style="color: #808080;">|</span> <span style="color: #0000ff;">INTO</span> DUMPFILE <span style="color: #ff0000;">'</span><span style="color: #ff0000;">file_name</span><span style="color: #ff0000;">'</span>
  <span style="color: #808080;">|</span> <span style="color: #0000ff;">INTO</span> var_name <span style="color: #ff0000;">[</span><span style="color: #ff0000;">, var_name</span><span style="color: #ff0000;">]</span><span style="color: #000000;">]
</span><span style="color: #ff0000;">[</span><span style="color: #ff0000;">FOR UPDATE | LOCK IN SHARE MODE</span><span style="color: #ff0000;">]</span><span style="color: #000000;">

]

 

 

 

4.2 指定查詢字段

-- 查詢全部的學生 select字段from 表
SELECT *FROM student
SELECT *FROM result

-- 查詢指定字段
SELECT studentNo,studentnameFROM student
-- 別名,給結果起一個名字 AS 可以給字段起別名,也可以給表起別名
SELECT studentno AS 學號,studentname AS 學生姓名 FROM student

-- 函數 concat(a,b)
SELECT CONCAT('姓名:',studentname) AS 新名字 FROM student

 

有的時候,列名字不是那么的見名知意.我們起別名 AS 字段名 as 別名 表名 as 別名

 

去重 distinct

作用:去除select查詢出來的結果中重復的數據,只顯示一條

-- 查詢一下有哪些同學參加了考試,成績
SELECT * FROM result -- 查詢全部的考試成績
-- 查詢有哪些同學參加了考試
SELECT `studentno` FROM result
-- 發現重復數據, 去重
SELECT DISTINCT `studentno` FROM result

 

 

數據庫的列

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 邏輯非

 

==盡量使用英文字母==

select studentno,studentresult from result 
-- 查詢95-100分之間的
where studentresult>=95 and studentresult<=100

-- 模糊查詢
select studentno,studentresult from result
where studentresult between 95 and 100

-- 除了1000號學生之外的同學的成績
select studentno,studentresult from result
where 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,z3...) 假設a在a1,或者a2...其中的某一個值中,結果為真
-- 查詢姓劉的同學
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);

-- 查詢在北京的學生
select studentno,studentname from student
where address in ('北京');

-- 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

-- 查詢沒有出生日期的同學 為空
select studentno,studentname from student
where borndate is not null

 

 

 

4.4 聯表查詢

JOIN對比

image-20210804152410934

img

/*
join on 連接查詢
where 等值查詢
*/

-- inner join
SELECT s.studentno,studentname,subjectno,studentresult -- studentno前面要加點,要么從s表查,要么從r表查
FROM student AS s -- 因為兩個表都有studentno,所以給他們分別命名否則會報錯
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
LEFT JOIN 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

-- 思考題 (查詢了參加考試的同學信息:學號,學生姓名,科目名,分數)
/

思路
1.分析需求,分析查詢的字段來自哪些表,(連接基礎)
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 a left join b 以左表為准
--
From a right join b 以右表為准

 

 

操作 描述
inner join 如果表中至少有一個匹配,就返回行;只要兩個表的公共字段有匹配值,就將這兩個表中的記錄組合起來。以一個共同的字段求兩個表中符合要求的交集,並將每個表符合要求的記錄以共同的字段為牽引合並起來。
left join 會從左表中返回所有的值,即使右表中沒有匹配
right join 會從右表中返回所有的值,即使左表中沒有匹配

 

自連接

父類

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

 

4.5分頁和排序

分頁:limit

排序:order by

升序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 ASC  -- 升序

 

分頁

-- 分頁,要求每頁只顯示5條數據
-- 語法: 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 ASC  -- 升序
limit 0,5 -- limit 0,5 是1-5

-- 第一頁 limit 0,5 (1-1)5
--
第二頁 limit 5,5 (2-1)
5
--
第三頁 limit 10,5 (3-1)5
--
第N頁 limit (N-1)
5
--
規律: (n-1)*pageSize,pageSize,n表示當前頁
--
[數據總數/頁面大小 = 總頁數]

 

語法:✔limit(查詢起始下標,pageSize)

-- 思考
-- 查詢,Java第一學年,課程成績排名前十的學生,並且分數要大於80的學生信息(學號,姓名,課程名稱,分數)
select s.`StudentNo`,`StudentNmae`,`SubjectName`,`StudentResult`
from `student` s
inner join `result` r
on s.StudentNo = r.`SubjectNo`
where SubjectName =`Java第一學年`AND StudentResult >=80
order by StudentResult DESC
limit 0,10

 

 

4.6 子查詢

where(值是固定的,這個值是計算出來的)

本質:在where語句中嵌套一個子查詢語句

-- =============where==============
-- 1.查詢數據庫結構-1的所有考試結果(學號,科目編號,成績),降序排列
-- 方式1
select `StudentNo`,r.`SubjectNo`,`StudentResult`
from `result` r
inner join `subject` sub
on r.subjectNo =sub.subjectNo
where subjectNo ='數據庫結構-1'
order by StudentResult DESC

-- 查詢課程為高等數學-2 且分數不小於80 的同學的學號的姓名
select StudentNo,StudentNmae
from student s
inner join result r
on s.studentNo=r.StudentNo
inner join subject sub
on r.subjectNo= sub.subjectNo
where subjectName='高等數學' and studentResult>=80

-- 方式2:使用子查詢(由里及外)
select StudentNo,SubjectNo,StudentResult
from result r
where StudentNo = (select subjectNo from subject where Subjectname='數據庫結構-1')
-- 查詢所有數據庫結構-1的學生學號
--
select subjectNo from subject where Subjectname='數據庫結構-1'
order by StudentResult DESC

-- 分數不小於80分的學生學號和姓名
select distinct s.StudentNo,StudentName
from student s
inner join result r
on r.studentNo = s.studentNo
where studentResult >=80

-- 在這個基礎上增加一個科目,高等數學-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 subjectNo from 'subject'where subjectName='高等數學-2'

 



5.MySQL函數

官網: https://dev.mysql.com/doc/refman/8.0/en/functions.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('I','LOVE','U')-- 拼接字符串
SELECT INSERT('我愛helloworld',1,2,'超級愛') -- 查詢,替換,輸出超級愛helloworld
SELECT LOWER('HELLOWORLD') -- 轉成小寫
SELECT UPPER('helloworld') -- 轉成大寫
SELECT INSTR('kuangshen','h') -- 查詢字符位置,輸出7
SELECT REPLACE('kuangshen','kuang','6')-- 替換出現的指定字符串 輸出6shen
SELECT SUBSTR('狂神說堅持就能成功',4,6) -- 返回指定的子字符串 輸出堅持就能成功
SELECT REVERSE('狂神說堅持就能成功') -- 反轉

-- 查詢姓 張的同學, 名字 換成 贊
SELECT REPLACE(studentname,'','') FROM student
WHERE studentname LIKE '張%'

-- 時間和日期函數(記住)
SELECT CURRENT_DATE() -- 獲取當前日期
SELECT CURRENT_TIME() -- 獲取當前時間
SELECT NOW() -- 獲取當前日期時間
SELECT LOCALTIME() -- 本地時間
SELECT SYSDATE() -- 系統時間
SELECT YEAR(NOW())
SELECT HOUR(NOW())
SELECT MINUTE(NOW())
SELECT SECOND(NOW())

-- 系統
SELECT SYSTEM_USER()
SELECT USER()
SELECT VERSION()

 

 

5.2.聚合函數(常用)

函數名稱 描述
count() 技數
sum() 求和
avg() 平均值
max() 最大值
min() 最小值
... ...
select count(student name) from student;-- count(指定列)
select count(*) from student;-- count(*)
select count(1) from student;-- count(1)

/*
一、從執行效果來看

  1. count(1) and count(*):

基本沒差別

count(*)包括了所有的列,相當於行數,在統計結果的時候,不會忽略NULL

  1. count(1) and count(列名):

(1) count(1) 會統計表中的所有的記錄數,不會忽略NULL,包含字段為null 的記錄。

(2) count(列名) 會統計該列字段在表中出現的次數,會忽略字段為null 的情況,即不統計字段為null 的記錄。

二、從執行效率來看
若列名為主鍵,count(列名)會比count(1)快

若列名不為主鍵,count(1)會比count(列名)快

若表多個列並且沒有主鍵,則 count(1) 的執行效率優於 count(*)

若表有主鍵,則 select count(主鍵)的執行效率是最優的

若表只有一個字段,則 select count(*)最優。

所以實際業務中一般用count(1)比較普遍,但是如果需要聚合多個列,則用count(列名)比較合適。
*/

select sum(StudentResult) as 總和 from result
select avg(StudentResult) as 平均分 from result
select max(StudentResult) as 最高分 from result
select min(StudentResult) as 最低分 from result

-- 查詢不同課程的平均分,最高分,最低分,平均分大於80
--
核心:(根據不同的課程分組)
select subjectName,AVG(StudentResult),MAX(StudentResult),MIN(StudentResult)
From result r
INNER JOIN subject sub
ON r.subjectNo = sub.subjectNo
where AVG(StudentResult)
group by r.subjectNo -- 通過什么字段來分組

 

 

5.3 數據庫級別的MD5加密(拓展)

什么是MD5?

MD5信息摘要算法 (英語:MD5 Message-Digest Algorithm),一種被廣泛使用的 密碼散列函數 ,可以產生出一個128位(16 字節 )的散列值(hash value),用於確保信息傳輸完整一致。

主要增強算法復雜度和不可逆性

MD5不可逆,具體的值的md5是一樣的

MD5破解網站的原理,背后有一個字典,MD5加密后的值

 

 1 -- ==================測試MD5加密====================
 2 CREATE TABLE `testmd5`(
 3 `id` INT(4) NOT NULL,
 4 `name` VARCHAR(20) NOT NULL,
 5 `pwd` VARCHAR(50) NOT NULL,
 6 PRIMARY KEY(`id`)
 7 )
 8 ENGINE=INNODB DEFAULT CHARSET=utf8
 9 -- 明文密碼
10 INSERT INTO testmd5 VALUES(1,'zhangsan','123456'),(2,'lisi','123456'),(3,'wangwu','123456')
11 -- 加密
12 UPDATE testmd5 SET pwd=MD5(pwd) WHERE id =1
13 UPDATE testmd5 SET pwd=MD5(pwd)-- 加密全部的密碼
14 
15 -- 插入的時候加密
16 INSERT INTO testmd5 VALUES(4,'小明',MD5('123456'))
17 
18 -- 如何校驗:將用戶傳遞進來的密碼,進行md5加密,然后比對加密后的值
19 SELECT *FROM testmd5 WHERE `name`='小明' AND pwd=MD5('123456')

 

 

6.事務

6.1.什么是事務

要么都成功,要么都失敗


1.SQL執行 A給B轉賬 A1000 ---->200 B 200

2.SQL執行 B收到A的錢 A 800 ---> B 400


將一組SQL放在一個批次中去執行

事務原則

四大特性(ACID) 含義
原子性A 一個事務要么成功,要么失敗
一致性C 一個事務執行之前跟執行之后狀態保持一致
A和B一共100元,無論中間轉賬多少次、轉多少,最終兩人的錢加一起還是100元
隔離性I 兩個事務之間互不干擾
A給B轉賬,不會影響到B給C轉賬,屬於兩個事務
持久性D 事務一旦提交,永久保存

 

臟讀:

指一個事務讀取了另外一個事務未提交的數據

不可重復讀:

在一個事務內讀取表中的某一行數據,多次讀取結果不同.(這個不一定是錯誤,只是某些場合不對)

虛讀(幻讀)

是指在一個事務內讀取到了別的事務插入的數據,導致前后讀取不一致

 

執行事務

 1 -- ==============事務=============
 2 -- MySQL是默認開啟事務自動提交的
 3 SET autocommit = 0 -- 關閉
 4 SET autocommit = 1 -- 開啟(默認)
 5 
 6 -- 手動處理事務
 7 SET autocommit = 0 -- 關閉自動提交
 8 
 9 -- 事務開啟
10 START TRANSACTION -- 標記一個事務的開始,從這個之后的sql都在同一個事務內
11 INSERT xx
12 INSERT xx
13 
14 -- 提交:持久化(成功)
15 COMMIT
16 -- 回滾:回到原來的樣子(失敗)
17 ROLLBACK
18 
19 -- 事務結束
20 SET autocommit = 1 -- 開啟自動提交
21 
22 -- 了解
23 SAVEPOINT 保存點名 -- 設置一個保存點
24 ROLLBACK TO SAVEPOINT 保存點名 -- 回滾到保存點
25 RELEASE SAVEPOINT 保存點名 -- 撤銷保存點
26  
27 
28 模擬場景
29 
30 -- 轉賬
31 CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf8_general_ci
32 USE shop
33 
34 CREATE TABLE `account`(
35 `id`   INT(3) NOT NULL AUTO_INCREMENT,
36 `name` VARCHAR(30) NOT NULL,
37 `money` DECIMAL(9,2) NOT NULL,
38 PRIMARY KEY (`id`)
39 )
40 ENGINE =INNODB DEFAULT CHARSET=utf8
41 
42 -- 模擬轉賬:事務
43 SET autocommit =0; -- 關閉自動提交
44 START TRANSACTION -- 開啟一個事務(一組事務)
45 UPDATE `account` SET money=money-500 WHERE `name` ='A' -- A-500
46 UPDATE `account` SET money=money+500 WHERE `name` ='B' -- B+500
47 
48 COMMIT; -- 提交事務,就被永久化了
49 ROLLBACK; -- 回滾
50 SET autocommit =1;-- 恢復默認值
51 java
52 
53 方法(){
54 
55 try(){
56 
57 ​    正常業務代碼
58 
59 ​    commmit();
60 
61 }catch(){
62 
63rollback();
64 
65 }}
66  

 

 

 

7.索引

http://blog.codinglabs.org/articles/theory-of-mysql-index.html

[MySQL官方對索引的定義為:索引(Index)是幫助MySQL高效獲取數據的數據結構。提取句子主干,就可以得到索引的本質:索引是數據結構。]

7.1. 索引的分類

  • 主鍵索引 (primary key)

    • 唯一標識,主鍵不可重復,只能有一個列作為主鍵

  • 唯一索引 (unique key)

    • 避免重復的列出現,唯一索引可以重復,多個列都可以表示為唯一索引

    • 唯一索引:不允許具有索引值相同的行,從而禁止重復的索引或鍵值

  • 常規索引 (key)

    • 默認的,index.key關鍵字來設置

  • 全文索引 (fulltext)

    • 在特定的數據庫引擎下才有,MyISAM

    • 快速定位數據

 

 1 -- ==============索引的使用==========
 2 -- 在創建表的時候給字段增加索引
 3 -- 創建完畢后,增加索引
 4 
 5 -- 顯示所有的索引信息
 6 SHOW INDEX FROM student
 7 
 8 -- 增加一個索引
 9 ALTER TABLE school.`student` ADD FULLTEXT INDEX `studentName`(`studentName`);
10 
11 
12 -- explain 分析sql執行的狀況
13 EXPLAIN SELECT * FROM student; -- 非全文索引
14 
15 SELECT * FROM student WHERE MATCH(studentName) AGAINST('');

 

 

7.2. 測試索引

 1 CREATE TABLE `app_user`(
 2 `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
 3 `name`    VARCHAR(50) DEFAULT '' COMMENT'用戶昵稱',
 4 `email` VARCHAR(50) NOT NULL COMMENT '用戶郵箱',
 5 `phone` VARCHAR(20) DEFAULT '' COMMENT '手機號',
 6 `gender` TINYINT(4) UNSIGNED DEFAULT '0' COMMENT '性別(0:男;1:女)',
 7 `password` VARCHAR(100) NOT NULL COMMENT '密碼',
 8 `age` TINYINT(4) DEFAULT '0' COMMENT '年齡',
 9 `create_time`    DATETIME DEFAULT CURRENT_TIMESTAMP,
10 `update_time`    TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
11 PRIMARY KEY (`id`)
12 )
13 ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='app用戶表'
14 
15 -- 插入100w數據
16 DELIMITER $$ -- 寫函數之前必寫,當作標志
17 CREATE FUNCTION mock_data()
18 RETURNS     INT
19 DETERMINISTIC -- 8.0版本必須寫這一句
20 BEGIN
21     DECLARE num INT DEFAULT 1000000;
22     DECLARE i INT DEFAULT 0;
23     WHILE i<num DO
24         INSERT INTO `app_user`(`name`,`email`,`phone`,`gender`,`password`,`age`)
25         VALUES(CONCAT('用戶',i),'123456@qq.com',
26         CONCAT('18',FLOOR(RAND()*((999999999-100000000)+100000000))),
27         FLOOR(RAND()*2),
28         UUID(),
29         FLOOR(RAND()*100)
30 );    
31         SET i=i+1;
32     END WHILE;
33     RETURN i;
34 END;
35 SELECT mock_data();
36 
37 -- 創建一個索引
38 -- id_表名_字段名
39 -- create index 索引名 on 表(字段)
40 CREATE INDEX id_app_user_name ON app_user(`name`);
41 -- 現在再查詢速度就非常快了
42 
43 SELECT * FROM app_user WHERE `name` = '用戶9999'; -- 0.0001秒出來

 

 

  • 索引在小數據量時用處不大,但在大數據時,區別十分明顯

 

7.3. 索引原則

  • 索引不是越多越好

  • 不要對經常變動的數據加索引

  • 小數據量的表不要加索引

  • 索引一般加在常用來查詢的字段上

索引的數據結構

Hash 類型的索引

Btree: innodb 的默認數據結構

MySQL索引背后的數據結構及算法原理

 

8.數據庫備份和權限管理

8.1. 用戶管理

SQLyog可視化管理

image-20210806101252212

SQL命令操作

用戶表: mysql.user (MySQL數據庫下的user表)

本質:讀這張表進行增刪改查

 1 -- 創建用戶
 2 CREATE USER kuangshen IDENTIFIED BY '123456'
 3 
 4 -- 修改密碼(修改當前用戶密碼)
 5 SET PASSWORD = PASSWORD('111111') -- 8.0版本這個語句失效了
 6 ALTER USER 'kuangshen'@'%' IDENTIFIED BY'123456'-- 這是8.0版本修改語句的方法
 7 
 8 -- 修改密碼(修改指定用戶密碼)
 9 SET PASSWORD FOR kuangshen = PASSWORD('111111') -- 這是5.7版本的
10 -- 8.0 版本都是這個格式: ALTER USER 'kuangshen'@'%' IDENTIFIED BY'123456'
11 
12 -- 用戶重命名
13 rename user kuangshen to kuangshen2
14 
15 -- 用戶授權all privileges 全部權限,庫,表
16 grant all privileges on *.* to kuangshen2
17 -- all privileges 除了給別人授權,其他都能干
18 
19 -- 查看權限
20 show grants for kuangshen2
21 show grants for root@localhost
22 
23 -- 撤銷權限 revoke 哪些權限 在哪個庫撤銷 給誰撤銷
24 revoke all privileges on *.* from kuangshen2
25 
26 -- 刪除用戶
27 drop user kuangshen

 

 

8.2.MySQL備份

為什么要備份

  • 保證重要的數據不丟失

  • 轉移A---->B

MySQL數據庫備份的方式

    1. 直接拷貝data文件

    1. 在SQLyog這種可視化工具中手動導出

    1. 使用命令行導出 mysqldump 命令行使用

      mysqldump -hlocalhost -uroot -p123456 school student >D:/a.sql

 

加入要備份數據庫,防止數據丟失

把數據庫給朋友,sql文件給別人即可

 

 

 

9.規范數據庫設計

9.1. 為什么需要設計

當數據庫比較復雜的時候,我們就需要設計了

糟糕的數據庫設計:

  • 數據冗余,浪費空間

  • 數據插入和刪除都會麻煩,異常[屏蔽使用物理外鍵]

  • 程序的性能差

良好的數據庫設計:

  • 節省內存空間

  • 保證數據的完整性

  • 方便我們開發系統

軟件開發中關於數據庫的設計

  • 分析需求:分析業務和需要處理的數據庫的需求

  • 概要設計:設計關系圖E-R圖

設計數據庫的步驟:(個人博客)

  • 收集信息,分析需求

    • 用戶表(用戶登錄注銷,用戶個人信息,寫博客,創建分類)

    • 分類表(文章分類,誰創建的)

    • 文章表(文章的信息)

    • 有鏈表(友鏈信息)

    • 自定義表(系統信息,某個關鍵的字,或者一些主字段) key:value

  • 標識實體(把需求落地到)

    • 寫博客:user -->blog

    • 創建分類:user -->category

    • 關注:user -->user

    • 友鏈:links

    • 評論:user-user-blog

       

9.2.三大范式(了解即可)

為什么需要數據規范化?

  • 信息重復

  • 更新異常

  • 插入異常

    • 無法正常顯示信息

  • 刪除異常

    • 丟失有效的信息

三大范式

https://blog.csdn.net/weixin_52837751/article/details/116605537

第一范式(1NF)

原子性:要求數據庫表的每一列都是不可分割的原子數據項

 

第二范式(2NF):

前提:滿足第一范式

每張表只描述一件事

 

第三范式(3NF):

前提:滿足第一范式,第二范式

要確保數據表中的每一列數據都和主鍵直接相關,而不能間接相關

 

規范性和性能的問題

關聯查詢的表不得超過三張表(阿里)

  • 考慮商業化的需求和目標,(成本,用戶體驗)數據庫的性能更重要

  • 再規范性能的問題時,需要適當的考慮一下規范性

  • 故意給某些表增加一些冗余的字段.(從多表查詢中變為單表查詢)

  • 故意增加一些計算列(從大數據量降低為小數據量的查詢: 索引)

 

 

10.JDBC(重點)

10.1.數據庫驅動

驅動:聲卡,顯卡,數據庫

image-20210806140316317

我們的程序會通過數據庫驅動,和數據庫打交道

 

10.2.JDBC

SUN公司為了簡化開發人員的(對數據庫的統一)操作,提供了一個(Java操作數據庫的)規范,俗稱JDBC

對於開發人員來說,我們只需要掌握jdbc接口的操作即可

image-20210806140902908

java.sql

javax.sql

還需要導入一個數據庫驅動包 mysql-connector-java-5.1.47.jar (這是5.7版本用的)

MySQL8.0用的是 mysql-connector-java-8.0.25.jar

 

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,'zhangsan','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');

 

  1. 創建一個普通項目(用IDEA)

  2. 導入數據庫驅動(創建一個lib目錄,把jar包放進去,然后右鍵,add as library)

  3. 編寫測試代碼

 1 package com.kuang.lesson01;
 2 
 3 import java.sql.*;
 4 
 5 //我的第一個JDBC程序
 6 public class JdbcFirstDemo {
 7     public static void main(String[] args) throws ClassNotFoundException, SQLException {
 8         //1.加載驅動
 9         Class.forName("com.mysql.cj.jdbc.Driver");// 固定寫法,加載驅動(8.0版本)
10        // Class.forName("com.mysql.jdbc.Driver");// 固定寫法,加載驅動(5.7版本)
11 
12         //2.用戶信息和url
13         //useUnicode=true&characterEncoding=utf8&useSSL=true
14         //支持中文編碼    &設定字符為utf8          &使用安全連接        jdbcstudy是數據庫名
15     String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
16         String username ="root";
17         String password ="123456";
18 
19         //3.連接成功,數據庫對象  Connection 代表數據庫
20         Connection connection = DriverManager.getConnection(url,username,password);
21 
22         //4.執行SQL的對象
23         Statement statement= connection.createStatement();
24 
25         //5.執行SQL的對象去執行SQL,可能存在結果,查看返回結果
26         String sql ="SELECT * FROM USERS";
27 
28         ResultSet resultSet = statement.executeQuery(sql);//返回的結果集,結果集中封裝了我們全部的查詢出來的結果
29 
30         while (resultSet.next()){
31             System.out.println("====================================================");
32             System.out.println("id="+resultSet.getObject("id"));
33             System.out.println("name="+resultSet.getObject("NAME"));
34             System.out.println("pwd="+resultSet.getObject("PASSWORD"));
35             System.out.println("email="+resultSet.getObject("email"));
36             System.out.println("birth="+resultSet.getObject("birthday"));
37         }
38 
39         //6.釋放連接
40         resultSet.close();
41         statement.close();
42         connection.close();
43     }
44 }

 

步驟總結:

  1. 加載驅動

  2. 連接數據庫DriverManager

  3. 獲取執行sql的對象Statement

  4. 獲得返回的結果集

  5. 釋放連接

 

DriverManager

 1 //DriverManager.registerDriver(new com.mysql.jdbc.Driver());
 2 Class.forName("com.mysql.cj.jdbc.Driver");// 固定寫法,加載驅動(8.0版本)
 3 
 4 Connection connection = DriverManager.getConnection(url,username,password);
 5 
 6 //connection代表數據庫
 7 //數據庫設置自動提交
 8 //事務提交
 9 //事務提醒
10     connection.rollback();
11     connection.commit();
12     connection.setAutoCommit();
13 //數據庫能干的connection都能干

 

 

URL

String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";

//mysql 默認端口3306
//協議://主機地址:端口號/數據庫名?參數1&參數2&參數3

//oracle默認端口1521
//jdbc:oracle:thin:@localhost:1521:sid

 

 

Statement執行SQL的對象 PrepareStatement執行SQL的對象

String sql= "SELECT*FROM users";//編寫sql

statement.executeQuery();//查詢操作返回ResultSet
statement.execute();//執行任何SQL
statement.executeUpdate();//更新,插入,刪除,都是用這個,返回一個受影響的行數

 

 

ResultSet查詢的結果集:封裝了所有的查詢結果

獲得指定的數據型

resultSet.getObject();//在不知道列類型的情況下使用
//如果知道列的類型使用指定的類型
resultSet.getObject();
resultSet.getString();
resultSet.getInt();
resultSet.getFloat();
resultSet.getDate();
resultSet.getObject();
...

遍歷,指針

resultSet.beforeFirst();//移動到最前面
resultSet.afterLast();//移動到最后面
resultSet.next();//移動到下一個數據
resultSet.previous();//移動到前一行
resultSet.absolute();//移動到指定行

釋放資源

//釋放連接

resultSet.close();
statement.close();
connection.close(); //很耗資源,用完關掉!

 

10.4.statement對象

  • jdbc中的statement對象用於向數據庫發送SQL語句,想完成對數據庫的增刪改查,只需要通過這個對象向數據庫發送增刪改查語句即可.

statement對象的executeUpdate方法,用於向數據庫發送增刪改的sql語句,executeUpdate執行完后,將會返回一個整數(即增刪改語句導致了數據庫幾行數據發生了變化).

statement.executeQuery方法用於向數據庫發送查詢語句,executeQuery方法返回代表查詢結果的ResultSet對象.

 

CRUD操作-create

使用executeUpdate(String sql)方法完成數據添加操作,示例操作

1 Statement st =conn.createStatement();
2 String sql ="insert into user(...)values(...)";
3 int num =st.executeUpdate(sql);
4 if(num>0){
5     System.out.println("插入成功!!");
6 }

 

 

CRUD操作-delete

使用executeUpdate(String sql)方法完成數據刪除操作,示例操作:

Statement st=conn.createStatement();
String sql ="delete from user where id=1";
int num =st.executeUpdate(sql);
if(num>0){
    System.out.println("刪除成功!!")
}

 

 

CRUD操作-update

Statement st=conn.createStatement();
String sql ="update user set name='' where name=''";
int num =st.executeUpdate(sql);
if(num>0){
    System.out.println("修改成功!!")
}

 

 

CRUD操作-read

Statement st=conn.createStatement();
String sql ="select*from user where id=1";
ResultSet rs=st.executeQuery(sql);
while(rs.next()){
    //根據獲取列的數據類型,分別調用rs的相應方法映射到Java對象中
}

 


 

代碼實現

  1. 創建一個db.properties文件在src目錄下,等下引用更方便

    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
    username=root
    password=123456

     

  2. 提取工具類

    package com.kuang.lesson02.utils;
    

    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;

    </span><span style="color: #0000ff;">static</span><span style="color: #000000;"> {
        </span><span style="color: #0000ff;">try</span><span style="color: #000000;">{
            InputStream in </span>= JdbcUtils.<span style="color: #0000ff;">class</span>.getClassLoader().getResourceAsStream("db.properties"<span style="color: #000000;">);
            Properties properties </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> Properties();
            properties.load(in);
    
            driver</span>= properties.getProperty("driver"<span style="color: #000000;">);
            url</span>= properties.getProperty("url"<span style="color: #000000;">);
            username</span>= properties.getProperty("username"<span style="color: #000000;">);
            password</span>= properties.getProperty("password"<span style="color: #000000;">);
    
            </span><span style="color: #008000;">//</span><span style="color: #008000;">1.驅動只用加載一次</span>
    

    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 conn, Statement st, ResultSet rs){
    if(rs!=null){
    try {
    rs.close();
    }
    catch (SQLException throwables) {
    throwables.printStackTrace();
    }
    }
    if(st!=null){
    try {
    st.close();
    }
    catch (SQLException throwables) {
    throwables.printStackTrace();
    }
    }
    if(conn!=null){
    try {
    conn.close();
    }
    catch (SQLException throwables) {
    throwables.printStackTrace();
    }
    }
    }

    }
    //備注:static關鍵字
    /*
    在類中,用static聲明的成員變量為靜態成員變量,也稱為類變量。類變量的生命周期和類相同,在整個應用程序執行期間都有效。

    這里要強調一下:

    static修飾的成員變量和方法,從屬於類

    普通變量和方法從屬於對象

    靜態方法不能調用非靜態成員,編譯會報錯

    static關鍵字的用途
    一句話描述就是:方便在沒有創建對象的情況下進行調用(方法/變量)。

    顯然,被static關鍵字修飾的方法或者變量不需要依賴於對象來進行訪問,只要類被加載了,就可以通過類名去進行訪問。

    static可以用來修飾類的成員方法、類的成員變量,另外也可以編寫static代碼塊來優化程序性能

    static方法
    static方法也成為靜態方法,由於靜態方法不依賴於任何對象就可以直接訪問,因此對於靜態方法來說,是沒有this的,因為不依附於任何對象,既然都沒有對象,就談不上this了,並且由於此特性,在靜態方法中不能訪問類的非靜態成員變量和非靜態方法,因為非靜態成員變量和非靜態方法都必須依賴於具體的對象才能被調用。

    雖然在靜態方法中不能訪問非靜態成員方法和非靜態成員變量,但是在非靜態成員方法中是可以訪問靜態成員方法和靜態成員變量。
    */

     

     

  3. 編寫增刪改的方法,executeUpdate

    insert

package com.kuang.lesson02.utils;

import com.kuang.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 conn
=null;
Statement st
=null;
ResultSet rs
=null;

    </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
        conn </span>=<span style="color: #000000;"> JdbcUtils.getConnection();
        st </span>=conn.createStatement();<span style="color: #008000;">//</span><span style="color: #008000;">獲得SQL的執行對象</span>
        String sql ="INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`)" +
                "VALUES(4,'kuangshen','123456','123456@qq.com','2021-08-09')"<span style="color: #000000;">;

        </span><span style="color: #0000ff;">int</span> i =<span style="color: #000000;">st.executeUpdate(sql);
        </span><span style="color: #0000ff;">if</span> (i&gt;0<span style="color: #000000;">){
            System.out.println(</span>"插入成功!"<span style="color: #000000;">);
        }
    } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (SQLException e) {
        e.printStackTrace();
    }</span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
        JdbcUtils.release(conn,st,rs);
    }
}

}

 

delete

package com.kuang.lesson02.utils;

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 conn
=null;
Statement st
=null;
ResultSet rs
=null;
//只需要變String sql 那一行
try {
conn
= JdbcUtils.getConnection();
st
=conn.createStatement();//獲得SQL的執行對象
String sql ="DELETE FROM users WHERE id=4";

        </span><span style="color: #0000ff;">int</span> i =<span style="color: #000000;">st.executeUpdate(sql);
        </span><span style="color: #0000ff;">if</span> (i&gt;0<span style="color: #000000;">){
            System.out.println(</span>"刪除成功!"<span style="color: #000000;">);
        }
    } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (SQLException e) {
        e.printStackTrace();
    }</span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
        JdbcUtils.release(conn,st,rs);
    }
}

}

 

update

package com.kuang.lesson02.utils;

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 conn
=null;
Statement st
=null;
ResultSet rs
=null;
//只需要變String sql 那一行
try {
conn
= JdbcUtils.getConnection();
st
=conn.createStatement();//獲得SQL的執行對象
String sql ="UPDATE users SET NAME='kuangshen',email='123@qq.com' WHERE id=1";

        </span><span style="color: #0000ff;">int</span> i =<span style="color: #000000;">st.executeUpdate(sql);
        </span><span style="color: #0000ff;">if</span> (i&gt;0<span style="color: #000000;">){
            System.out.println(</span>"更新成功!"<span style="color: #000000;">);
        }
    } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (SQLException e) {
        e.printStackTrace();
    }</span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
        JdbcUtils.release(conn,st,rs);
    }
}

}

 

  1. 查詢executeQuery

package com.kuang.lesson02.utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestSelect {
public static void main(String[] args) {
Connection conn
=null;
Statement st
=null;
ResultSet rs
=null;
try {
conn
=JdbcUtils.getConnection();
st
= conn.createStatement();
//SQL
String sql ="select * from users where id =1";

        rs </span>= st.executeQuery(sql);<span style="color: #008000;">//</span><span style="color: #008000;">查詢完畢會返回一個結果集</span>

        <span style="color: #0000ff;">while</span><span style="color: #000000;">(rs.next()){
            System.out.println(rs.getString(</span>"NAME"<span style="color: #000000;">));
        }

    } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (SQLException e) {
        e.printStackTrace();
    }</span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
        JdbcUtils.release(conn,st,rs);
    }
}

}

 

SQL注入的問題

sql存在漏洞,會被攻擊導致數據泄露 ==本質是因為SQL會被拼接==

SQL注入即是指web應用程序對用戶輸入數據的合法性沒有判斷或過濾不嚴,攻擊者可以在web應用程序中事先定義好的查詢語句的結尾上添加額外的SQL語句,在管理員不知情的情況下實現非法操作,以此來實現欺騙數據庫服務器執行非授權的任意查詢,從而進一步得到相應的數據信息。

package com.kuang.lesson02.utils;

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("kuangshen","123456");這是正常情況
login("'or '1=1","123456");//輸入特殊代碼,將所有數據都輸出了,被盜錄,這就是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

        </span><span style="color: #008000;">//</span><span style="color: #008000;">SELECT * FROM users WHERE `NAME`='' or '1=1' AND `PASSWORD`='123456';</span><span style="color: #008000;">//</span><span style="color: #008000;">SQL注入保證了1=1是true</span>
        String sql ="SELECT * FROM users WHERE `NAME`='"+username+"' AND `PASSWORD`='"+password+"'"<span style="color: #000000;">;

        rs </span>= st.executeQuery(sql);<span style="color: #008000;">//</span><span style="color: #008000;">查詢完畢會返回一個結果集</span>

        <span style="color: #0000ff;">while</span><span style="color: #000000;">(rs.next()){
            System.out.println(rs.getString(</span>"NAME"<span style="color: #000000;">));
            System.out.println(rs.getString(</span>"PASSWORD"<span style="color: #000000;">));
        }

    } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (SQLException e) {
        e.printStackTrace();
    }</span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
        JdbcUtils.release(conn,st,rs);
    }
}

}

 

 

10.5.PreparedStatement對象

PreparedStatement可以防止SQL注入.效率更高!

 

  1. 新增

    package com.kuang.lesson03;
    

    import com.kuang.lesson02.utils.JdbcUtils;

    import java.sql.Connection;
    import java.util.Date;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;

    public class TesrInsert {
    public static void main(String[] args) {
    Connection conn
    = null;
    PreparedStatement st
    = null;
    try {
    conn
    = JdbcUtils.getConnection();

            </span><span style="color: #008000;">//</span><span style="color: #008000;">區別
            </span><span style="color: #008000;">//</span><span style="color: #008000;">使用問號占位符代替參數</span>
            String sql="INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES(?,?,?,?,?)"<span style="color: #000000;"> ;
    
            st </span>= conn.prepareStatement(sql);   <span style="color: #008000;">//</span><span style="color: #008000;">預編譯SQL,先寫sql,然后不執行
    
            </span><span style="color: #008000;">//</span><span style="color: #008000;">手動給參數賦值</span>
            st.setInt(1,4);<span style="color: #008000;">//</span><span style="color: #008000;">id</span>
            st.setString(2,"zzy"<span style="color: #000000;">);
            st.setString(</span>3,"1232112"<span style="color: #000000;">);
            st.setString(</span>4,"zzy@qq.com"<span style="color: #000000;">);
            </span><span style="color: #008000;">//</span><span style="color: #008000;">注意點:sql.Date
            </span><span style="color: #008000;">//</span><span style="color: #008000;">util.Date Java    new Date().getTime()獲得時間戳</span>
            st.setDate(5,<span style="color: #0000ff;">new</span> java.sql.Date(<span style="color: #0000ff;">new</span><span style="color: #000000;"> Date().getTime()));
    
            </span><span style="color: #008000;">//</span><span style="color: #008000;">執行</span>
            <span style="color: #0000ff;">int</span> i =<span style="color: #000000;"> st.executeUpdate();
            </span><span style="color: #0000ff;">if</span> (i&gt;0<span style="color: #000000;">){
                System.out.println(</span>"插入成功"<span style="color: #000000;">);
            }
    
        } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (SQLException e) {
            e.printStackTrace();
        }</span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
            JdbcUtils.release(conn,st,</span><span style="color: #0000ff;">null</span><span style="color: #000000;">);
        }
    }
    

    }

     

     

  2. 刪除

    package com.kuang.lesson03;
    

    import com.kuang.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 conn
    = null;
    PreparedStatement st
    = null;
    try {
    conn
    = JdbcUtils.getConnection();

            </span><span style="color: #008000;">//</span><span style="color: #008000;">區別
            </span><span style="color: #008000;">//</span><span style="color: #008000;">使用問號占位符代替參數</span>
            String sql="delete from users where id =?"<span style="color: #000000;"> ;
    
            st </span>= conn.prepareStatement(sql);   <span style="color: #008000;">//</span><span style="color: #008000;">預編譯SQL,先寫sql,然后不執行
    
            </span><span style="color: #008000;">//</span><span style="color: #008000;">手動給參數賦值</span>
            st.setInt(1,4<span style="color: #000000;">);
    
            </span><span style="color: #008000;">//</span><span style="color: #008000;">執行</span>
            <span style="color: #0000ff;">int</span> i =<span style="color: #000000;"> st.executeUpdate();
            </span><span style="color: #0000ff;">if</span> (i&gt;0<span style="color: #000000;">){
                System.out.println(</span>"刪除成功"<span style="color: #000000;">);
            }
    
        } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (SQLException e) {
            e.printStackTrace();
        }</span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
            JdbcUtils.release(conn,st,</span><span style="color: #0000ff;">null</span><span style="color: #000000;">);
        }
    }
    

    }

     

     

  3. 更新

    package com.kuang.lesson03;
    

    import com.kuang.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 conn
    = null;
    PreparedStatement st
    = null;
    try {
    conn
    = JdbcUtils.getConnection();

            </span><span style="color: #008000;">//</span><span style="color: #008000;">區別
            </span><span style="color: #008000;">//</span><span style="color: #008000;">使用問號占位符代替參數</span>
            String sql="update users set `NAME`=? where id=?"<span style="color: #000000;"> ;
    
            st </span>= conn.prepareStatement(sql);   <span style="color: #008000;">//</span><span style="color: #008000;">預編譯SQL,先寫sql,然后不執行
    
            </span><span style="color: #008000;">//</span><span style="color: #008000;">手動給參數賦值</span>
            st.setString(1,"kuangshen"<span style="color: #000000;">);
            st.setInt(</span>2,1<span style="color: #000000;">);
    
    
            </span><span style="color: #008000;">//</span><span style="color: #008000;">執行</span>
            <span style="color: #0000ff;">int</span> i =<span style="color: #000000;"> st.executeUpdate();
            </span><span style="color: #0000ff;">if</span> (i&gt;0<span style="color: #000000;">){
                System.out.println(</span>"更新成功"<span style="color: #000000;">);
            }
    
        } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (SQLException e) {
            e.printStackTrace();
        }</span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
            JdbcUtils.release(conn,st,</span><span style="color: #0000ff;">null</span><span style="color: #000000;">);
        }
    }
    

    }

     

     

  4. 查詢

    package com.kuang.lesson03;
    

    import com.kuang.lesson02.utils.JdbcUtils;

    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;

    public class TestSelect {
    public static void main(String[] args) {
    Connection conn
    =null;
    PreparedStatement st
    =null;
    ResultSet rs
    =null;

        </span><span style="color: #0000ff;">try</span><span style="color: #000000;">  {
            conn </span>=<span style="color: #000000;"> JdbcUtils.getConnection();
            String sql</span>="select * from users where id = ?"<span style="color: #000000;">;
    
            st</span>=<span style="color: #000000;">conn.prepareStatement(sql);
            st.setInt(</span>1,1);<span style="color: #008000;">//</span><span style="color: #008000;">傳遞參數
            </span><span style="color: #008000;">//</span><span style="color: #008000;">執行</span>
            rs=<span style="color: #000000;">st.executeQuery();
    
            </span><span style="color: #0000ff;">if</span><span style="color: #000000;">(rs.next()){
                System.out.println(rs.getString(</span>"NAME"<span style="color: #000000;">));
            }
    
        } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (SQLException e) {
            e.printStackTrace();
        }</span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
            JdbcUtils.release(conn,st,rs);
        }
    }
    

    }

     

10.6.事務

要么都成功,要么都失敗

ACID原則

原子性:要么全部完成,要么都不完成

 

一致性:總數不變

 

隔離性:多個進程互不干擾

 

持久性:一旦提交不可逆,持久化到數據庫了

 

隔離性的問題:

臟讀:一個事務讀取了另一個沒有提交的事務

不可重復讀:在同一個事務內,重復讀取表中的數據,表數據發生了改變

虛讀(幻讀):在一個事務內,讀取到了別人插入的數據,導致前后讀出來結果不一致

 

代碼實現

  1. 開啟事務conn.setAutoCommit(false);

  2. 一組業務執行完畢,提交事務

  3. 可以在catch語句中顯示的定義回滾語句,但默認失敗就會回滾

 

此處少了一個數據庫account,但代碼正確

package com.kuang.lesson04;

import com.kuang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class TestTransaction {
public static void main(String[] args) {
Connection conn
=null;
PreparedStatement st
=null;
ResultSet rs
=null;

    </span><span style="color: #0000ff;">try</span><span style="color: #000000;">{
        conn </span>=<span style="color: #000000;"> JdbcUtils.getConnection();
        </span><span style="color: #008000;">//</span><span style="color: #008000;">關閉數據庫的自動提交</span>
        conn.setAutoCommit(<span style="color: #0000ff;">false</span><span style="color: #000000;">);

        String sql1</span>="update account set money-100 where name ='A'"<span style="color: #000000;">;
        conn.prepareStatement(sql1);
        st.executeUpdate();
        String sql2</span>="update account set money+100 where name ='B'"<span style="color: #000000;">;
        conn.prepareStatement(sql2);
        st.executeUpdate();

        </span><span style="color: #008000;">//</span><span style="color: #008000;">業務完畢,提交事務</span>

conn.commit();
System.out.println(
"success");

    } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (SQLException e) {
        </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
            conn.rollback();
        } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (SQLException throwables) {
            throwables.printStackTrace();
        }

        e.printStackTrace();
    }</span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
        JdbcUtils.release(conn,st,rs);
    }
}

}

 

 

10.7.數據庫連接池

數據庫連接---執行完畢---釋放

連接 -- 釋放 十分浪費系統資源

池化技術:准備一些預先的資源,過來就連接預先准備好的

 

最小連接數: 10

最大連接數: 15 業務最高承載上限

超過15就要排隊等待

等待超時:100ms

 

編寫連接池,實現一個接口DataSource

 

開源數據源實現(拿來即用)

DBCP

C3P0

Druid:阿里巴巴

使用了這些數據庫連接池之后,我們在項目開發中就不需要編寫連接數據庫的代碼了

 

DBCP

需要用到的jar包

commons-dbcp-1.4 和 commons-pool-1.6

//添加到lib目錄若無法展開,要打開Project Structure的Libraries將lib移除,然后再add as libraries

 

dbcpconfig.properties文件

#連接設置
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

 

 

 

package com.kuang.lesson05.utils;

import com.kuang.lesson02.utils.JdbcUtils;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JdbcUtils_DBCP {

</span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> DataSource dataSource =<span style="color: #0000ff;">null</span><span style="color: #000000;">;

</span><span style="color: #0000ff;">static</span><span style="color: #000000;"> {
    </span><span style="color: #0000ff;">try</span><span style="color: #000000;">{
        InputStream in </span>= JdbcUtils.<span style="color: #0000ff;">class</span>.getClassLoader().getResourceAsStream("dbcpconfig.properties"<span style="color: #000000;">);
        Properties properties </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> Properties();
        properties.load(in);
        
        </span><span style="color: #008000;">//</span><span style="color: #008000;">創建數據源 工廠模式---&gt;創建</span>
        dataSource =<span style="color: #000000;"> BasicDataSourceFactory.createDataSource(properties);


    } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception e) {
        e.printStackTrace();
    }
}
</span><span style="color: #008000;">//</span><span style="color: #008000;">獲取連接</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> Connection getConnection() <span style="color: #0000ff;">throws</span><span style="color: #000000;"> SQLException {
    </span><span style="color: #0000ff;">return</span> dataSource.getConnection();<span style="color: #008000;">//</span><span style="color: #008000;">從數據源中獲取連接</span>

}
//釋放連接資源
public static void release(Connection conn, Statement st, ResultSet rs){
if(rs!=null){
try {
rs.close();
}
catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(st!=null){
try {
st.close();
}
catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
}
catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}

 

 

 

 

package com.kuang.lesson05.utils;

import com.kuang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;

public class TestDBCP {
public static void main(String[] args) {
Connection conn
= null;
PreparedStatement st
= null;
try {
conn
= JdbcUtils_DBCP.getConnection();

        </span><span style="color: #008000;">//</span><span style="color: #008000;">區別
        </span><span style="color: #008000;">//</span><span style="color: #008000;">使用問號占位符代替參數</span>
        String sql="INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES(?,?,?,?,?)"<span style="color: #000000;"> ;

        st </span>= conn.prepareStatement(sql);   <span style="color: #008000;">//</span><span style="color: #008000;">預編譯SQL,先寫sql,然后不執行

        </span><span style="color: #008000;">//</span><span style="color: #008000;">手動給參數賦值</span>
        st.setInt(1,4);<span style="color: #008000;">//</span><span style="color: #008000;">id</span>
        st.setString(2,"zzy"<span style="color: #000000;">);
        st.setString(</span>3,"1232112"<span style="color: #000000;">);
        st.setString(</span>4,"zzy@qq.com"<span style="color: #000000;">);
        </span><span style="color: #008000;">//</span><span style="color: #008000;">注意點:sql.Date
        </span><span style="color: #008000;">//</span><span style="color: #008000;">util.Date Java    new Date().getTime()獲得時間戳</span>
        st.setDate(5,<span style="color: #0000ff;">new</span> java.sql.Date(<span style="color: #0000ff;">new</span><span style="color: #000000;"> Date().getTime()));

        </span><span style="color: #008000;">//</span><span style="color: #008000;">執行</span>
        <span style="color: #0000ff;">int</span> i =<span style="color: #000000;"> st.executeUpdate();
        </span><span style="color: #0000ff;">if</span> (i&gt;0<span style="color: #000000;">){
            System.out.println(</span>"插入成功"<span style="color: #000000;">);
        }

        } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (SQLException e) {
            e.printStackTrace();
        }</span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
            JdbcUtils_DBCP.release(conn,st,</span><span style="color: #0000ff;">null</span><span style="color: #000000;">);
        }
    }

}

 

 

C3P0

需要用到的jar包

c3p0-0.9.5.5 mchange-commons-java-0.2.19.jar

 

c3p0-config.xml

<?xml version="1.0"  encoding="UTF-8"?>
<c3p0-config>
<!--
c3p0的缺省(默認)配置
如果在代碼中ComboPooledDataSource ds=new ComboPooledDataSource();這樣寫就表示使用的是c3p0的缺省(默認)
default-config
-->
<default-config>

<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?userUnicode=true&amp;characterEncoding=utf8&amp;uesSSL=true&amp;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>


<name-config name="MySQL">
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?userUnicode=true&amp;characterEncoding=utf8&amp;uesSSL=true&amp;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>
</name-config>

</c3p0-config>

 

package com.kuang.lesson05.utils;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JdbcUtils_C3P0 {
private static ComboPooledDataSource dataSource =null;

</span><span style="color: #0000ff;">static</span><span style="color: #000000;"> {
    </span><span style="color: #0000ff;">try</span>{<span style="color: #008000;">//</span><span style="color: #008000;">xml不用讀取,會自動匹配

        </span><span style="color: #008000;">//</span><span style="color: #008000;">代碼版配置

// dataSource =new ComboPooledDataSource();
// dataSource.setDriverClass();
// dataSource.setUser();
// dataSource.setPassword();
// dataSource.setJdbcUrl();
// dataSource.setMaxPoolSize();
// dataSource.setMinPoolSize();

        </span><span style="color: #008000;">//</span><span style="color: #008000;">創建數據源 工廠模式---&gt;創建</span>
        dataSource = <span style="color: #0000ff;">new</span> ComboPooledDataSource("MySQL");<span style="color: #008000;">//</span><span style="color: #008000;">配置文件寫法</span>
} catch (Exception e) { e.printStackTrace(); } } //獲取連接 public static Connection getConnection() throws SQLException { return dataSource.getConnection();//從數據源中獲取連接 } //釋放連接資源 public static void release(Connection conn, Statement st, ResultSet rs){ if(rs!=null){ try { rs.close(); }catch (SQLException throwables) { throwables.printStackTrace(); } } if(st!=null){ try { st.close(); }catch (SQLException throwables) { throwables.printStackTrace(); } } if(conn!=null){ try { conn.close(); }catch (SQLException throwables) { throwables.printStackTrace(); } } } }

 

package com.kuang.lesson05;

import com.kuang.lesson05.utils.JdbcUtils_C3P0;
import com.kuang.lesson05.utils.JdbcUtils_DBCP;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;

public class TestC3P0 {
public static void main(String[] args) {
Connection conn
= null;
PreparedStatement st
= null;
try {
conn
= JdbcUtils_C3P0.getConnection();//只有這一行和最后關閉跟TestDBCP不一樣

        </span><span style="color: #008000;">//</span><span style="color: #008000;">區別
        </span><span style="color: #008000;">//</span><span style="color: #008000;">使用問號占位符代替參數</span>
        String sql="INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES(?,?,?,?,?)"<span style="color: #000000;"> ;

        st </span>= conn.prepareStatement(sql);   <span style="color: #008000;">//</span><span style="color: #008000;">預編譯SQL,先寫sql,然后不執行

        </span><span style="color: #008000;">//</span><span style="color: #008000;">手動給參數賦值</span>
        st.setInt(1,4);<span style="color: #008000;">//</span><span style="color: #008000;">id</span>
        st.setString(2,"zzy"<span style="color: #000000;">);
        st.setString(</span>3,"1232112"<span style="color: #000000;">);
        st.setString(</span>4,"zzy@qq.com"<span style="color: #000000;">);
        </span><span style="color: #008000;">//</span><span style="color: #008000;">注意點:sql.Date
        </span><span style="color: #008000;">//</span><span style="color: #008000;">util.Date Java    new Date().getTime()獲得時間戳</span>
        st.setDate(5,<span style="color: #0000ff;">new</span> java.sql.Date(<span style="color: #0000ff;">new</span><span style="color: #000000;"> Date().getTime()));

        </span><span style="color: #008000;">//</span><span style="color: #008000;">執行</span>
        <span style="color: #0000ff;">int</span> i =<span style="color: #000000;"> st.executeUpdate();
        </span><span style="color: #0000ff;">if</span> (i&gt;0<span style="color: #000000;">){
            System.out.println(</span>"插入成功"<span style="color: #000000;">);
        }

    } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (SQLException e) {
        e.printStackTrace();
    }</span><span style="color: #0000ff;">finally</span><span style="color: #000000;"> {
        JdbcUtils_C3P0.release(conn,st,</span><span style="color: #0000ff;">null</span><span style="color: #000000;">);
    }
}

}

 

結論

無論使用什么數據源,本質還是一樣的,DataSource接口不會變,方法就不會變

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM