1. 程式人生 > >二十、二十一天MySql數據庫、jdbc

二十、二十一天MySql數據庫、jdbc

mysql、jdbc

1 數據約束
              1.1 簡介
                   給表添加數據約束,從而約束用戶操作表數據的行為。
 
              1.2 默認值約束
註意: 當前沒有插入默認值字段的時候,默認值才會起作用
 
-- 1.1 默認值(default)CREATE TABLE test(         NAME  VARCHAR(20),         gender  VARCHAR(2) DEFAULT ‘男‘) INSERT INTO test(NAME) VALUES(‘張三‘);INSERT INTO test(NAME,gender) VALUES(‘張三‘,NULL); SELECT * FROM test; -- 需求:當不插入gender的時候,分配一個‘男’的默認值-- 註意: 1)當沒有插入gender字段的時候,分配一個默認值    
 
              1.3 非空約束
-- 1.2 非空(not null)CREATE TABLE test(         NAME  VARCHAR(20) NOT NULL,         gender  VARCHAR(2))-- 需求: name字段一定要有值(不能不插入數據,不能是null),這是給name添加非空約束-- 1)非空約束,不能不插入值INSERT INTO test(gender) VALUES(‘男‘); -- ERROR 1364 (HY000): Field ‘NAME‘  doesn‘t have a default value -- 2)非空約束,不能插入nullINSERT INTO test(NAME,gender)  VALUES(NULL,‘男‘); -- ERROR 1048  (23000): Column ‘NAME‘ cannot be null    
 
              1.4 唯一約束
CREATE TABLE test(         id  INT UNIQUE,         NAME  VARCHAR(20))-- 需求: id的值不能出現重復值。這時就要給id添加一個唯一約束。INSERT INTO test(id,NAME) VALUES(1,‘張三‘);-- 1)不能插入重復的值INSERT INTO test(id,NAME) VALUES(1,‘李四‘); -- Duplicate entry ‘1‘ for key ‘id‘INSERT INTO test(id,NAME) VALUES(2,‘李四‘);-- 2)唯一約束,可以插入多個null。所以唯一約束不能約束nullINSERT INTO test(id,NAME) VALUES(NULL,‘王五‘);INSERT INTO test(id,NAME) VALUES(NULL,‘陳六‘);    
 
              1.5 主鍵約束
-- 1.4 主鍵約束(primary key)(唯一+非空)-- 註意:-- 1)通常情況下,我們會給每張表都會設置一個主鍵字段,用來標記記錄的唯一性-- 2)但是不建議把業務含義字段作為主鍵,因為隨著業務的變化,業務字段可能會出現重復。-- 3)建議給每張張獨立添加一個叫id的字段,把這個id字段設置成主鍵,用來作為記錄的唯一性。 -- 創建表給id字段施加主鍵CREATE TABLE test(         id  INT PRIMARY KEY,         NAME  VARCHAR(20)) -- 1)唯一性INSERT INTO test(id,NAME) VALUES(1,‘張三‘);INSERT INTO test(id,NAME) VALUES(1,‘張三‘); -- Duplicate entry ‘1‘ for key  ‘PRIMARY‘ -- 2)非空性INSERT INTO test(id,NAME) VALUES(NULL,‘張三‘); -- ERROR 1048 (23000): Column ‘id‘  cannot be null    
  1.6 自增長約束(auto_increment)
-- 1.5 自增長約束(auto_increment)-- 創建表給id字段添加主鍵自增長約束CREATE TABLE test(         id  INT PRIMARY KEY AUTO_INCREMENT,         NAME  VARCHAR(20))-- 自增長約束:初始值為0,每次遞增1-- 需求:id的值不需要我們開發者管理,交給數據庫維護,這時給id添加自增長約束。INSERT INTO test(NAME) VALUES(‘張三‘);INSERT INTO test(NAME) VALUES(‘李四‘);INSERT INTO test(NAME) VALUES(‘王五‘);  -- 刪除數據-- delete from test where id=2;-- 使用truncate table刪除數據的時候,可以把自增長的初始值置為0TRUNCATE TABLE test; SELECT * FROM test;    
 
                  
              1.7 外鍵約束
                   外鍵約束:約束兩種表的情況
                   問題:什麽情況下會出現兩種表?
                   答案:員工表中出現部門名稱的冗余字段!!!!
                   如何解決部門名稱冗余問題?
                   答案:獨立設計一張部門表,把部門名稱放到部門表中,這是員工表只需要關聯部門的id即可!!
                   問題:當插入員工表的部門id的時候,可能會出現不存在的部門id!!這是非法數據!!!如何防止非法數據的插入?
                   答案:這是可以把員工表的部門id設置為外鍵約束。
                  
                   當有了外鍵約束之後,操作數據的順序如下:
                                     插入數據:先插入主表的數據,再插入副表數據
                                     修改數據:先修改主表數據,再修改副表數據
                                    刪除數據:先刪除副表數據,再刪除主表數據
                  
-- 1.6 外鍵約束-- 外鍵作用: 約束兩種表的數據-- 問題: 約束哪種情況下的兩種表呢?-- 員工表CREATE TABLE employee(         id  INT PRIMARY KEY AUTO_INCREMENT,         NAME  VARCHAR(20),         deptName  VARCHAR(20))  INSERT INTO employee(NAME,deptName)  VALUES(‘張三‘,‘軟件開發部‘);INSERT INTO employee(NAME,deptName)  VALUES(‘李四‘,‘軟件維護部‘);INSERT INTO employee(NAME,deptName)  VALUES(‘王五‘,‘軟件開發部‘);INSERT INTO employee(NAME,deptName)  VALUES(‘陳六‘,‘軟件開發部‘); -- 問題:每次插入員工數據時,部門名稱數據會出現重復(冗余),如果數據出現冗余,那麽會浪費數據庫存儲空間。-- 如何解決部門名稱數據冗余的問題? 這時就可以設計一張獨立的 部門表,把部門名稱放到部門表中。 -- 員工表CREATE TABLE employee(         id  INT PRIMARY KEY AUTO_INCREMENT,         NAME  VARCHAR(20),         deptId  INT) -- 部門表CREATE TABLE dept(         id  INT PRIMARY KEY AUTO_INCREMENT,         NAME  VARCHAR(20)) SELECT * FROM employee;SELECT * FROM dept; INSERT INTO dept(NAME) VALUES(‘軟件開發部‘);INSERT INTO dept(NAME) VALUES(‘軟件維護部‘);INSERT INTO employee(NAME,deptId)  VALUES(‘陳六‘,1);INSERT INTO employee(NAME,deptId)  VALUES(‘王五‘,1); INSERT INTO employee(NAME,deptId)  VALUES(‘張三‘,3); -- 問題:在插入員工表的部門id的時候,插入了不存在的部門id,如何防止這種非法數據的插入,這時就添加外鍵約束了。 -- 添加外鍵約束(foreign key)-- 需求:deptId字段值來自於dept表的id字段的值,這時可以給deptId字段添加外鍵約束。-- 員工表(副表: 被別的表約束。外鍵設置在副表)CREATE TABLE employee(         id  INT PRIMARY KEY AUTO_INCREMENT,         NAME  VARCHAR(20),         deptId  INT,         CONSTRAINT employee_dept_fk FOREIGN KEY(deptId) REFERENCES  dept(id)         --          外鍵名稱                     外鍵字段  參考           ) -- 部門表(主表:約束別人的表)CREATE TABLE dept(         id  INT PRIMARY KEY AUTO_INCREMENT,         NAME  VARCHAR(20)) SELECT * FROM employee;SELECT * FROM dept; INSERT INTO employee(NAME,deptId)  VALUES(‘陳六‘,1);INSERT INTO employee(NAME,deptId)  VALUES(‘王五‘,1);-- 插入數據INSERT INTO employee(NAME,deptId)  VALUES(‘張三‘,3); -- 違反外鍵約束:a foreign key constraint fails-- 修改數據UPDATE employee SET deptId=5 WHERE id=2;  -- a foreign key constraint fails-- 刪除數據DELETE FROM dept WHERE id=1; -- a foreign  key constraint fails -- 外鍵約束在什麽情況下,會其作用?-- 插入數據:當往副表插入了主表不存在的數據時,外鍵起作用-- 修改數據:當往副表修改為主表不存在的數據時,外鍵起作用-- 刪除數據: 副表中有關聯主表的數據的時候,當刪除主表數據,外鍵其作用 -- 當有了外鍵之後,應該如何管理數據呢?-- 插入數據: 先插入主表的數據,再插入副表數據-- 修改數據: 先修改主表數據,再修改副表數據UPDATE employee SET deptId=3 WHERE id=5;UPDATE dept SET id=3 WHERE id=2;-- 刪除數據:先刪除副表數據,再刪除主表數據DELETE FROM dept WHERE id=3;DELETE FROM employee WHERE deptId=3;    
 
              1.8 級聯技術
                   級聯:當有了外鍵的時候,我們希望修改或刪除數據的時候,修改或刪除了主表的數據,同時能夠影響副表的數據,這時就可以使用級聯。
                  
CREATE TABLE employee(         id  INT PRIMARY KEY AUTO_INCREMENT,         NAME  VARCHAR(20),         deptId  INT,         --  添加級聯修改: ON UPDATE CASCADE         --  添加級聯刪除: ON DELETE CASCADE         CONSTRAINT  employee_dept_fk FOREIGN KEY(deptId) REFERENCES dept(id) ON UPDATE CASCADE ON DELETE CASCADE          --          外鍵名稱                     外鍵字段  參考           )    
 
2 數據庫設計
              2.1 引入
                   需求分析:原始需求 -> 業務需求
                                     客戶                                     業務模型:客戶(姓名   登記時間郵箱  微信號)
                   需求設計:
                                     業務模型(客戶業務模型): -》 抽取實體模型: classCustomer{name email weixin} 
                                     業務模型(客戶業務模型) ->  數據模型:設計數據庫表(customer表:字段)
 
              2.2 數據庫設計的三大範式
                            第一範式: 要求表的每個字段必須獨立的不可分割的單元
 
                                                        學生表: student    name             --違反第一範式
                                                                                              張三|狗娃
                                                                                              王含|張小含
 
                                               查詢:現用名中包含‘張’的學生
                                                                 select* from student where name like ‘%張%‘;
 
 
                                                        學生表: student  name   old_name             --符合第一範式
                                                                                              張三      狗娃
                                                                                              王含      張小含
 
                   第二範式:在第一範式的基礎上,要求表的除主鍵以外的字段都和主鍵有依賴關系的。
                                                                 一張表應該只表達一個意思!!!!
 
                                               員工表:employee
                                                        員工編號  員工姓名  部門名稱   訂單名稱     --違反第二範式
 
                                               員工表:employee
                                                        員工編號  員工姓名  部門名稱        --符合第二範式
 
                                               訂單表:
                                                        訂單編號  訂單名稱
 
                   第三範式:在第二範式基礎上,要求表的除主鍵外的字段都只能和主鍵有直接決定的依賴關系。
 
                                              
                                               員工表:employee                                  --不符合第三範式(出現數據冗余)
                                                        員工編號  員工姓名  部門編號部門名稱
                                                        1       張三        1    軟件開發部
                                                        2       李四                   1     軟件開發部        
 
                                               員工表:employee                                  --符合第三範式(降低數據冗余)
                                                        員工編號  員工姓名  部門編號
                                                        1       張三        1    
                                                        2       李四                    1   
                                               部門表: dept
                                                        部門編號  部門名稱
                                                                 1    軟件開發部
 
                                     數據庫存儲空間  和數據查詢效率
3 多表查詢
                  
-- 1.1 交叉連接查詢(笛卡爾乘積: 4*3=12,產生笛卡爾積的原因是沒有足夠的連接條件)-- 需求: 員工及其部門SELECT employee.name,dept.name FROM  employee,dept; -- 多表查詢的步驟: 1)確定查詢哪些表  2)確定查詢哪些字段  3)確定連接條件(規則: 表數量-1)-- 內連接效果:只有滿足連接條件的數據才會顯示出來-- 1.2內連接查詢(使用最多)SELECT e.name,d.name         FROM  employee e,dept d         WHERE  e.deptId=d.id; -- 另一種語法SELECT e.name,d.name         FROM  employee e         INNER  JOIN dept d         ON  e.deptId=d.id;        -- 1.3 左外連接查詢(其次)-- 需求: 查詢部門及其部門的員工(部門全部顯示)-- 左外連接查詢效果:  左表(部門表)的數據全部顯示,右表(員工)的數據當滿足連接條件的時候,          -- 就顯示滿足條件的的數據,但是如果不滿足連接條件,則顯示null-- 預期結果:         --  軟件開發部   張三         --  軟件開發部   王五         --  軟件維護部   李四         --  軟件維護部   陳六         --  秘書部       nullSELECT d.name,e.name         FROM  dept d         LEFT  OUTER JOIN employee e         ON  d.id=e.deptId;    -- 1.4 右外連接查詢-- 右外連接查詢效果:  右表(部門表)的數據全部顯示,左表(員工)的數據當滿足連接條件的時候,          -- 就顯示滿足條件的數據,但是如果不滿足連接條件,則顯示nullSELECT d.name,e.name         FROM  employee e         RIGHT  OUTER JOIN dept d         ON  d.id=e.deptId;                      -- 1.5 自連接查詢-- 需求: 查詢員工姓名及其上司姓名(沒有上司的員工也顯示)-- 預期結果:            員工    上司         --  張三    null         --  李四   張三         --  王五   李四         --  陳六   王五SELECT e.name AS ‘員工‘,b.name AS ‘上司‘         FROM  employee e         LEFT  OUTER JOIN employee b         ON  e.bossId=b.id;    
 
4 mysql存儲過程
              4.1 引入
                   存儲過程,其實就是帶邏輯的(多個)sql語句。也是sql編程。
              4.2 存儲過程的特點
                   1)存儲過程保存到數據庫服務器端,通過數據庫客戶端工具調用存儲過程
                   2)存儲過程的效率會非常高!因為存儲過程是在數據庫服務器端執行。
                   3)存儲過程的移植性非常差的!
              4.3 存儲過程語法
                  
創建存儲過程-- 定義結束符號DELIMITER 結束符號CREATE PROCEDURE 存儲過程名稱 (形式參數列表)BEGIN         多個sql語句END 結束符號 -- 調用存儲過程CALL 存儲過程名稱(實際參數列表); 參數類型:IN: 輸入參數,可以攜帶數據到存儲過程中OUT: 輸出參數,可以攜帶數據到存儲過程外面。INOUT: 輸入輸出參數。    
 
                  
-- 3.1 帶有輸入參數的存儲過程-- 需求: 傳入員工id查詢對應的員工DELIMITER $CREATE PROCEDURE pro_testByIn(IN eid  INT)  -- 參數類型(IN) 參數名稱 數據類型(int)BEGIN         SELECT  * FROM employee WHERE id=eid;END $ -- 調用CALL pro_testByIn(2); -- 3.2 帶有輸出參數的存儲過程DELIMITER $CREATE PROCEDURE pro_testByOut(OUT n  VARCHAR(20))BEGIN         --  修改變量n         SET  n = ‘輸出參數‘;END $ -- 問題: 如何接收存儲過程的輸出參數???-- 定義變量去接收輸出參數數據。 -- mysql數據庫三種變量:         --  1)全局變量。mysql內置的變量,mysql程序關閉的時候全局變量才會失效!!            -- show variables:產看全局變量                            --  character_set_client: mysql接收的客戶端的數據編碼                            --  character_set_results: mysql使用什麽編碼輸出給客戶端數據                 -- 查看某個全局變量: select @@變量名                 -- 修改某個全局變量: set @@變量名=值         --  2) 會話變量。變量只在某次登錄的會話中有效!退出連接,會話變量數據失效!!                         -- 查看某個會話變量: select @變量名                 -- 修改/定義某個會話變量: set @變量名=值             -- 案例:演示查詢和更改會話變量         --  3) 局部變量:在存儲過程中定義的變量。存儲過程結束局部變量失效!!                       -- 查看某個局部變量: select 變量名                 -- 修改某個局部變量: set 變量名=值                 -- 定義某個局部變量: declare 變量名 數據類型;                -- 定義會話變量去接收輸出參數數據                -- set @n=‘eric‘;CALL pro_testByOut(@n);-- 查看會話變量nSELECT @n; -- 3.3 帶有輸入輸出參數的存儲過程DELIMITER $CREATE PROCEDURE pro_testByInOut(INOUT n  VARCHAR(20))BEGIN         --  查看n變量         SELECT  n;         --  修改n變量         SET  n = ‘500‘;END $ -- 定義會話變量調用存儲過程SET @n=‘100‘;CALL pro_testByInOut(@n);-- 查看nSELECT @n; -- 3.4 帶有判斷條件的存儲過程-- 需求: 輸入一個num整數,num=1 ,輸出‘星期一’,num=2,輸出‘星期二’,num=3,輸出‘星期三’,否則,輸出‘錯誤參數’DELIMITER $CREATE PROCEDURE pro_testByIf(IN num  INT,OUT str VARCHAR(20))BEGIN         IF  num=1 THEN                   SET  str = ‘星期一‘;         ELSEIF  num= 2 THEN                   SET  str =‘星期二‘;         ELSEIF  num=3 THEN                   SET  str = ‘星期三‘;         ELSE                   SET  str = ‘錯誤參數‘;         END  IF;END $ CALL pro_testByIf(5,@str);SELECT @str; -- 3.5 帶有循環條件的存儲過程-- 需求: 輸入一個num,計算從1到num的總和。DELIMITER $CREATE PROCEDURE pro_testByWhile(IN num  INT,OUT score INT)BEGIN         --  int result =0;         --  for(int i=1;i<=100;i++){         --      result += i;         --  }                 --  定義局部變量         DECLARE i INT DEFAULT 1;         DECLARE  result INT DEFAULT 0;         WHILE  i<=num DO                   SET  result = result + i;                   SET  i = i+1;         END  WHILE;         SET  score = result;END $  CALL pro_testByWhile(200,@score);SELECT @score; -- 3.6 攜帶數據庫的數據給輸出參數(INTO)-- 需求: 傳入員工id,查詢對應的員工,輸出員工姓名DELIMITER $CREATE PROCEDURE pro_testByData(IN eid  INT,OUT sname VARCHAR(20))BEGIN         SELECT  NAME INTO sname FROM employee WHERE id=eid;END $ CALL pro_testByData(2,@sname);SELECT @sname;ss -- 練習存儲過程練習在student表的數據基礎上,設計一個存儲過程:          1)計算出所有學生的英語平均分         2)                   如果平均分,大於80分,且小於等於100分,輸出‘優秀‘                   如果平均分,大於等於60分,且小於等於80分,輸出‘良好‘                   如果平均分,小於60分,輸出‘不及格‘USE day14; SELECT * FROM student2; DELIMITER $CREATE PROCEDURE pro_testByAvg(OUT str  VARCHAR(20),OUT tavg FLOAT)BEGIN         DECLARE  savg FLOAT DEFAULT 0.0;         SELECT  AVG(english) INTO savg FROM student2;         IF  savg>80 AND savg<=100 THEN                   SET  str = ‘優秀‘;         ELSEIF  savg>=60 AND savg<=80 THEN                   SET  str = ‘良好‘;         ELSE                     SET  str = ‘不及格‘;         END  IF;         SET  tavg = savg;      END $ -- 刪除存儲過程DROP PROCEDURE pro_testByAvg;  CALL pro_testByAvg(@str,@tavg);SELECT   @str;SELECT @tavg;     
 
5 觸發器
              5.1 簡介
                   當往員工表插入/修改/刪除一條數據的時候,同時往日誌表記錄下來,這時就要使用觸發器完成。
5.2 觸發器語法
-- 員工日誌表CREATE TABLE emp_log(         id  INT PRIMARY KEY AUTO_INCREMENT,         content  VARCHAR(20)) -- 需求: 當往員工表插入一條數據時,往員工日誌插入一條記錄。-- 創建增加觸發器CREATE TRIGGER tri_empAdd AFTER INSERT ON  employee FOR EACH ROW         INSERT  INTO emp_log(content) VALUES(‘員工被插入了一條記錄‘);-- 創建修改觸發器CREATE TRIGGER tri_empUpd AFTER UPDATE ON  employee FOR EACH ROW         INSERT  INTO emp_log(content) VALUES(‘員工被修改了一條記錄‘);-- 創建刪除觸發器CREATE TRIGGER tri_empDel AFTER DELETE ON  employee FOR EACH ROW         INSERT  INTO emp_log(content) VALUES(‘員工被刪除了一條記錄‘);  DROP TRIGGER tri_empAdd; SELECT * FROM employee;SELECT * FROM emp_log;  INSERT INTO employee(NAME,deptId,bossId)  VALUES(‘李七‘,5,1);UPDATE employee SET NAME=‘張三‘ WHERE id=10;DELETE FROM employee WHERE id=10;    
 
5.3 數據庫的權限問題
-- 五、mysql權限問題-- root用戶: 超級管理員。     權限: 增刪改查(數據庫,表,數據)-- 給mysql數據庫分配不同權限的不同用戶  -- mysql數據庫:存放mysql配置信息,包括用戶信息USE mysql;-- 用戶表SELECT * FROM USER; -- 加密函數(md5算法--單向加密)SELECT PASSWORD(‘root‘); --  *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B -- 修改用戶密碼UPDATE USER SET  PASSWORD=PASSWORD(‘123456‘) WHERE USER=‘root‘; -- 分配權限給不同的用戶-- 需求: 分配查詢day15數據庫的employee表的權限給eric用戶,密碼為‘123456’GRANT SELECT ON day15.employee TO  [email protected]
/* */ IDENTIFIED BY ‘123456‘;GRANT DELETE ON day15.employee TO [email protected] IDENTIFIED BY ‘123456‘; SHOW TABLES; 1 JDBC入門 1.1 回顧 之前操作mysql數據庫: 1)使用mysql客戶端工具 2)使用客戶端連接mysql服務器 3)發送sql語句到mysql服務器,執行 1.2 什麽是JDBC? 使用java程序發送sql語句到數據庫服務器端執行,這叫用到了JDBC技術!!!! jdbc是Oracle-Sun公司設計的一套專門用於java程序操作數據庫的接口。 1.3 使用jdbc發送sql條件 連接mysql數據庫: 數據庫主機 端口 數據庫用戶名 數據庫密碼 連接的數據庫 1.4JDBC的核心API |-Driver接口:數據庫驅動程序的接口,所有具體數據庫廠商需要的驅動程序需要實現此接口。 Connectionconnect(String url, Properties info) 用於獲取數據庫連接 |-Connection接口:與具體的數據庫的連接對象。 StatementcreateStatement() 創建一個靜態sql語句對象 PreparedStatementprepareStatement(String sql) 創建預編譯的sql語句對象 CallableStatementprepareCall(String sql) 創建存儲過程的sql語句對象 |-Statement接口:用於執行靜態 SQL 語句 intexecuteUpdate(String sql) 執行更新操作的sql語句 (create/alter/drop) DDL語句 (insert/update/delete)DML語句 ResultSetexecuteQuery(String sql) 執行查詢操作的sql語句 (select)(DQL查詢語句) |-PreparedStatement接口:用於執行預編譯的 SQL 語句(是Statement的子接口) intexecuteUpdate() 執行更新操作的sql語句 ResultSetexecuteQuery() 執行查詢操作的sql語句 |-CallableStatement接口:用於執行 SQL 存儲過程的接口(是PreparedStatement的子 接口) ResultSetexecuteQuery() 執行存儲過程的sql語句 |- ResultSet接口:結果集對象。 存儲所有數據庫查詢的結果,用該對象進行數據遍歷。 booleannext() : 把光標移動到下一行。如果下一行有數據,返回true,如果沒有下一行數 據,返回false。 getXXX(列索引|列字段名稱): 獲取字段的數據 2 Statement對象執行SQL操作 2.1 執行DDL操作 /** * 通過jdbc執行DDL語句 * @author APPle * */publicclass Demo1 { //數據庫的連接的URL privatestatic String url = "jdbc:mysql://localhost:3306/day17"; //數據庫用戶名 privatestatic String user = "root"; //數據庫密碼 privatestatic String password = "root"; publicstaticvoid main(String[] args){ Connection conn = null; Statement stmt = null; try { //1.驅動驅動程序 Class.forName("com.mysql.jdbc.Driver"); //2.從驅動程序管理類獲取連接 conn = DriverManager.getConnection(url, user, password); //3.通過Connection對象獲取Statement對象 stmt = conn.createStatement(); //4.準備sql語句 String sql = "CREATE TABLE student(id INT PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR(20),gender VARCHAR(2))"; //5.執行sql語句,返回結果 int count = stmt.executeUpdate(sql); System.out.println("影響了"+count+"行"); } catch (Exception e) { e.printStackTrace(); thrownew RuntimeException(e); } finally{ //6.關閉資源(先關閉statement,再關閉connection) if(stmt!=null) try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); thrownew RuntimeException(e); } if(conn!=null) try { conn.close(); } catch (SQLException e) { e.printStackTrace(); thrownew RuntimeException(e); } } }} 2.2 執行DML操作 /** * 通過jdbc執行DML語句(insert/update/delete) * @author APPle * */publicclass Demo2 { //數據庫的連接的URL privatestatic String url = "jdbc:mysql://localhost:3306/day17"; //數據庫用戶名 privatestatic String user = "root"; //數據庫密碼 privatestatic String password = "root"; /** * 執行插入操作 */ @Test publicvoid test1(){ Connection conn = null; Statement stmt = null; try { //註冊驅動 Class.forName("com.mysql.jdbc.Driver"); //獲取連接 conn = DriverManager.getConnection(url, user, password); //創建Statment對象 stmt = conn.createStatement(); //準備sql String sql = "INSERT INTO student(NAME,gender) VALUES(‘張三‘,‘男‘)"; //執行sql,返回結果 int count = stmt.executeUpdate(sql); System.out.println("影響了"+count+"行"); } catch (Exception e) { e.printStackTrace(); thrownew RuntimeException(e); } finally{ //關閉資源 if(stmt!=null) try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); thrownew RuntimeException(e); } if(conn!=null) try { conn.close(); } catch (SQLException e) { e.printStackTrace(); thrownew RuntimeException(e); } } } /** * 執行更新操作 */ @Test publicvoid test2(){ Connection conn = null; Statement stmt = null; //聲明外部變量 String name = "陳六"; int id=2; try { //註冊驅動 Class.forName("com.mysql.jdbc.Driver"); //獲取連接 conn = DriverManager.getConnection(url, user, password); //創建Statment對象 stmt = conn.createStatement(); //準備sql String sql = "UPDATE student SET NAME=‘"+name+"‘ WHERE id="+id+""; //變量和String拼接sql //執行sql,返回結果 int count = stmt.executeUpdate(sql); System.out.println("影響了"+count+"行"); } catch (Exception e) { e.printStackTrace(); thrownew RuntimeException(e); } finally{ //關閉資源 if(stmt!=null) try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); thrownew RuntimeException(e); } if(conn!=null) try { conn.close(); } catch (SQLException e) { e.printStackTrace(); thrownew RuntimeException(e); } } } /** * 執行刪除操作 */ @Test publicvoid test3(){ Connection conn = null; Statement stmt = null; //聲明外部變量 int id=2; try { //註冊驅動 Class.forName("com.mysql.jdbc.Driver"); //獲取連接 conn = DriverManager.getConnection(url, user, password); //創建Statment對象 stmt = conn.createStatement(); //準備sql String sql = "DELETE FROM student WHERE id="+id+""; //變量和String拼接sql //執行sql,返回結果 int count = stmt.executeUpdate(sql); System.out.println("影響了"+count+"行"); } catch (Exception e) { e.printStackTrace(); thrownew RuntimeException(e); } finally{ //關閉資源 if(stmt!=null) try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); thrownew RuntimeException(e); } if(conn!=null) try { conn.close(); } catch (SQLException e) { e.printStackTrace(); thrownew RuntimeException(e); } } }} 2.3 執行DQL查詢操作 /** * 使用jdbc執行DQL語句(select) * @author APPle * */publicclass Demo3 { //數據庫的連接的URL privatestatic String url = "jdbc:mysql://localhost:3306/day17"; //數據庫用戶名 privatestatic String user = "root"; //數據庫密碼 privatestatic String password = "root"; publicstaticvoid main(String[] args) { Connection conn = null; Statement stmt = null; ResultSet rs = null; try { //註冊驅動 Class.forName("com.mysql.jdbc.Driver"); //獲取連接 conn = DriverManager.getConnection(url, user, password); //創建Statement對象 stmt = conn.createStatement(); //準備sql String sql = "SELECT * FROM student"; rs = stmt.executeQuery(sql); //移動光標到下一行 //rs.next(); /** * 註意: * 1)如果光標在第一行之前,使用rs.getXX()獲取列值,報錯:Before start of result set * 2)如果光標在最後一行之後,使用rs.getXX()獲取列值,報錯:After end of result set */ //獲取列值 /*if(rs.next()){ //使用列索引 int id = rs.getInt(1); String name = rs.getString(2); String gender = rs.getString(3); //使用列名稱 int id = rs.getInt("id"); String name = rs.getString("name"); String gender = rs.getString("gender"); System.out.println(id+"\t"+name+"\t"+gender+"\t"); }*/ //叠代結果集 while(rs.next()){ //使用列索引 /* int id = rs.getInt(1); String name = rs.getString(2); String gender = rs.getString(3); */ //使用列名稱 int id = rs.getInt("id"); String name = rs.getString("name"); String gender = rs.getString("gender"); System.out.println(id+"\t"+name+"\t"+gender+"\t"); } } catch (Exception e) { e.printStackTrace(); thrownew RuntimeException(e); } finally{ if(rs!=null) try { rs.close(); } catch (SQLException e1) { e1.printStackTrace(); thrownew RuntimeException(e1); } //關閉資源 if(stmt!=null) try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); thrownew RuntimeException(e); } if(conn!=null) try { conn.close(); } catch (SQLException e) { e.printStackTrace(); thrownew RuntimeException(e); } } }} 2.4jdbc工具類的抽取 privatestatic String url = "jdbc:mysql://localhost:3306/day18"; privatestatic String user = "root"; privatestatic String password = "root"; privatestatic String className = "com.mysql.jdbc.Driver"; static{ //註冊驅動,註冊一次就可以了 //註冊驅動 try { Class.forName(className); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //獲取連接 publicstatic Connection getConnection(){ try { //獲取連接 Connection conn = DriverManager.getConnection(url, user, password); //返回conn return conn; } catch (Exception e) { e.printStackTrace(); thrownew RuntimeException(); } } //釋放資源 publicstaticvoid close(ResultSet rs,Statement stmt,Connection conn){ //先判空後釋放 if (rs!=null) { try { rs.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); thrownew RuntimeException(); } } if (stmt!=null) { try { stmt.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); thrownew RuntimeException(); } } if (conn!=null) { try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); thrownew RuntimeException(); } } } 2.5 課堂練習 1.使用jdbc創建一張員工表員工表字段:編號,姓名,性別,年齡,職位,郵箱,電話 2.使用jdbc對員工表執行以下操作: 1)插入一條數據 2)修改一條數據 3)刪除一條數據 4)查詢並打印所有員工數據 3 PreparedStatement對象執行SQL操作 /** * 使用PreparedStatement執行sql語句 * @author APPle * */publicclass Demo1 { /** * 插入操作 */ @Test publicvoid test1(){ Connection conn = null; PreparedStatement stmt = null; try{ //獲取連接 conn = JdbcUtil.getConnection(); String sql = "INSERT INTO student(NAME,gender) VALUES(?,?)"; //預編譯sql:使用?號代替參數值。一個?號代表一個參數值 //創建PreparedStatement對象,執行預編譯的sql語句 stmt = conn.prepareStatement(sql); //設置參數 /** * 參數一:參數位置。從1開始 * 參數二:參數實際值 * 註意:所有參數必須要賦值 */ stmt.setString(1, "rose"); stmt.setString(2, "女"); //發送參數,執行sql語句 int count = stmt.executeUpdate(); System.out.println(count); }catch(Exception e){ e.printStackTrace(); thrownew RuntimeException(e); }finally{ //關閉資源 JdbcUtil.close(conn, stmt, null); } } /** * 修改操作 */ @Test publicvoid test2(){ Connection conn = null; PreparedStatement stmt = null; //聲明變量 String name = "jacky"; int id = 8; try{ //獲取連接 conn = JdbcUtil.getConnection(); String sql = "UPDATE student SET NAME=? WHERE id=?"; //預編譯sql:使用?號代替參數值。一個?號代表一個參數值 //創建PreparedStatement對象,執行預編譯的sql語句 stmt = conn.prepareStatement(sql); //設置參數 stmt.setString(1,name); stmt.setInt(2, id); //發送參數,執行sql語句 int count = stmt.executeUpdate(); System.out.println(count); }catch(Exception e){ e.printStackTrace(); thrownew RuntimeException(e); }finally{ //關閉資源 JdbcUtil.close(conn, stmt, null); } } /** * 刪除操作 */ @Test publicvoid test3(){ Connection conn = null; PreparedStatement stmt = null; //聲明變量 int id = 8; try{ //獲取連接 conn = JdbcUtil.getConnection(); String sql = "DELETE FROM student WHERE id=?"; //預編譯sql:使用?號代替參數值。一個?號代表一個參數值 //創建PreparedStatement對象,執行預編譯的sql語句 stmt = conn.prepareStatement(sql); //設置參數 //任何類型都可以使用setObject進行賦值 stmt.setObject(1, id); //發送參數,執行sql語句 int count = stmt.executeUpdate(); System.out.println(count); }catch(Exception e){ e.printStackTrace(); thrownew RuntimeException(e); }finally{ //關閉資源 JdbcUtil.close(conn, stmt, null); } } /** * 查詢操作 */ @Test publicvoid test4(){ Connection conn = null; PreparedStatement stmt = null; //聲明變量 String name = "張%"; try{ //獲取連接 conn = JdbcUtil.getConnection(); String sql = "SELECT * FROM student WHERE NAME LIKE ?"; //創建PreparedStatement,預編譯sql語句 stmt = conn.prepareStatement(sql); //設置參數 stmt.setObject(1, name); //發送參數,執行sql,返回結果集 ResultSet rs = stmt.executeQuery(); //遍歷結果集 while(rs.next()){ int id = rs.getInt("id"); String nameStr = rs.getString("name"); String gender = rs.getString("gender"); System.out.println(id+"\t"+nameStr+"\t"+gender+"\t"); } }catch(Exception e){ e.printStackTrace(); thrownew RuntimeException(e); }finally{ //關閉資源 JdbcUtil.close(conn, stmt, null); } } } ==============Statement和PreparedStatement的區別========================================== 一、語法結構不同 1)Statment執行靜態sql語句,且sql可以拼接。 2)PreparedStatement可以先執行預編譯的sql語句,在預編譯sql語句中使用?進行參數占位,後面 在進行參數賦值 二、原理不同 1)Statement不能進行sql緩存 2)而PreparedStatement可以進行sql緩存,執行效率會比Statement快!!! 三、安全性不同 1)Statement存在sql註入的風險(使用登錄註冊講解sql註入) 2)而PreparedStatement可以有效防止用戶註入。 -- 創建一張user表(sql註入)CREATE TABLE USER(id INT PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR(20),PASSWORD VARCHAR(20)); -- 給用戶表中插入數據INSERT INTO USER(NAME,PASSWORD) VALUES(‘james‘,‘123456‘);INSERT INTO USER(NAME,PASSWORD) VALUES(‘mayun‘,‘123456‘); -- 查詢表SELECT * FROM USER WHERE NAME=‘james‘ AND PASSWORD=‘123456‘; -- 查詢全部表,基於肯定條件SELECT * FROM USER WHERE 1=1; -- 查詢全張表給予否定條件SELECT * FROM USER WHERE 1<>1; -- 查詢表(sql註入)SELECT * FROM USER WHERE NAME=‘james‘ OR 1=1-- ‘ AND PASSWORD=‘123456‘; 4 CallableStatement對象執行存儲過程 4.1 執行帶輸入參數的存儲過程 /** * 執行帶有輸入參數存儲過程 */ @Test publicvoid test1(){ Connection conn = null; CallableStatement stmt = null; ResultSet rs = null; try{ //獲取連接 conn = JdbcUtil.getConnection(); //創建CallableStatement對象 String sql = "CALL pro_findById(?)";//預編譯sql、可以帶?號 //執行預編譯的sql stmt = conn.prepareCall(sql); //設置參數 stmt.setInt(1, 4); //發送參數,執行sql,返回結果 rs = stmt.executeQuery();// 註意:執行存儲過程必須使用exeuteQuery!!!! //遍歷結果 while(rs.next()){ int id = rs.getInt("id"); String name = rs.getString("name"); String gender = rs.getString("gender"); System.out.println(id+"\t"+name+"\t"+gender+"\t"); } }catch(Exception e){ e.printStackTrace(); thrownew RuntimeException(e); }finally{ //關閉資源 JdbcUtil.close(conn, stmt, rs); } } 4.2 執行帶有輸出參數的存儲過程 /** * 執行帶有輸出參數存儲過程 */ @Test publicvoid test2(){ Connection conn = null; CallableStatement stmt = null; try{ //獲取連接 conn = JdbcUtil.getConnection(); String sql = "CALL pro_findById2(?,?)"; // 第一個參數時輸入參數,第二個參數是輸出參數 //創建CallableStatement對象 stmt = conn.prepareCall(sql); //設置輸入參數 stmt.setObject(1, 4); //註冊一個輸出參數 /** * 參數一:參數位置 * 參數二:表示存儲過程中的OUT參數的數據庫類型 */ stmt.registerOutParameter(2, java.sql.Types.VARCHAR); //發送參數,執行存儲過程 stmt.executeQuery(); /** * 如何獲取存儲過程的返回值:OUT參數值。使用getXXX方法 */ String name = stmt.getString(2);//和預編譯語句中的參數位置保持一致!!!! System.out.println("結果:"+name); }catch(Exception e){ e.printStackTrace(); thrownew RuntimeException(e); }finally{ //關閉資源 JdbcUtil.close(conn, stmt, null); } } 5 優化jdbc工具類 privatestatic String url = null; privatestatic String user = null; privatestatic String password = null; privatestatic String className = null; static{ //註冊驅動,註冊一次就可以了 //註冊驅動 try { //給成員變量賦值,將文件中的鍵值對加載到properties集合中 Properties prop = new Properties(); InputStream in = new FileInputStream("db.properties"); prop.load(in); url = prop.getProperty("url"); user = prop.getProperty("user"); password = prop.getProperty("password"); className = prop.getProperty("className"); System.out.println(url); System.out.println(user); System.out.println(password); System.out.println(className); Class.forName(className); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } //獲取連接 publicstatic Connection getConnection(){ try { //獲取連接 Connection conn = DriverManager.getConnection(url, user, password); //返回conn return conn; } catch (Exception e) { e.printStackTrace(); thrownew RuntimeException(); } } //釋放資源 publicstaticvoid close(ResultSet rs,Statement stmt,Connection conn){ //先判空後釋放 if (rs!=null) { try { rs.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); thrownew RuntimeException(); } } if (stmt!=null) { try { stmt.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); thrownew RuntimeException(); } } if (conn!=null) { try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); thrownew RuntimeException(); } } }


二十、二十一天MySql數據庫、jdbc