JDBC连接mysql、创建表、操作数据、PreparedStatement防注入、sql语句返回值类型知识汇总
JDBC連接過程:
import java.sql.*;/*** Description:* Created by CWG on 2020/10/29 21:05*/ public class ConnectionTest {public static void main(String[] args){String user = "root";String password = "cheng";String url = "jdbc:mysql://localhost:3306/mysql?serverTimezone=UTC";String driver = "com.mysql.cj.jdbc.Driver";Connection conn = null;Statement stm = null;try{Class.forName(driver); //1.將mysql驅(qū)動(dòng)注冊到DriverManager中去conn = DriverManager.getConnection(url,user,password); //2. 建立連接stm = conn.createStatement(); // 3. 創(chuàng)建一個(gè)Statement 實(shí)例用于發(fā)送sql語句stm.execute("sql語句") //4.執(zhí)行sql語句} catch (Exception e) {e.printStackTrace();}} }大概流程是這樣:
從源碼看出,其繼承NonRegisteringDriver類并實(shí)現(xiàn)java.sql.Driver接口,可以自查源碼發(fā)現(xiàn)com.mysql.cj.jdbc.Driver類功能都是繼承自NonRegisteringDriver類。JDBC規(guī)范要求Driver類(com.mysql.cj.jdbc)在使用前必須向DriverManger注冊自己。注冊過程在Driver類的靜態(tài)代碼塊中實(shí)現(xiàn)。也就是說只要類被加載,就完成了向驅(qū)動(dòng)管理器的注冊。
(1)步驟3中,除了conn.createStatement() 創(chuàng)建Statement實(shí)例,還可以通過conn.prepareStatement 來創(chuàng)建PreparedStatement實(shí)例。
(2)步驟4中,stm.execute 是一個(gè)通用執(zhí)行sql語句方法,除此之外還有executeQuery與executeUpdate方法。
具體區(qū)別后邊講。
JDBC創(chuàng)建表:
stm.execute("create table users(" +"id int AUTO_INCREMENT," +"name VARCHAR(20), " +"age int," +"sex char(2)," +"PRIMARY KEY (id));");根據(jù)上邊連接好的數(shù)據(jù)庫,執(zhí)行以上語句來創(chuàng)建一個(gè)users用戶表,其語句格式跟mysql完全一樣,只是寫成了字符串。另外注意AUTO_INCREMENT自增約束只能用于主鍵。
JDBC操作數(shù)據(jù):
- 插入數(shù)據(jù)
- 查詢數(shù)據(jù)
問題來了:插入數(shù)據(jù)沒問題,然而查詢數(shù)據(jù)雖然也正常執(zhí)行,但是卻沒返回要查詢的數(shù)據(jù)。另外這里的sql語句只能是靜態(tài)的,若想在sql語句中傳入?yún)?shù),如何處理?這里就是上邊提到的那兩點(diǎn)。下邊具體說明。
Statement和 PreparedStatement:
從功能上來講,PreparedStatement可以通過參數(shù)傳遞方式來執(zhí)行sql語句,參數(shù)位置用占位符? 表示。而Statement沒有這樣的機(jī)制,只能寫實(shí)際的字符串sql語句。
stm = conn.createStatement(); String name = "小白"; String age = "17"; String sex = "男"; String sql = "insert into users(name,age,sex) values('"+ name + "',"+ age +",'"+ sex +"')"; stm.execute(sql);Statement方式傳遞參數(shù),只能通過字符串拼串來實(shí)現(xiàn),整體還是一個(gè)字符串語句。另外注意拼串時(shí),屬性name、sex這些字符串屬性的單引號不可省略。
PreparedStatement ps = null; try{Class.forName(driver);conn = DriverManager.getConnection(url,user,password);String sql = "insert into users(name,age,sex) values(?,?,?)";ps = conn.prepareStatement(sql);ps.setString(1,"小灰");ps.setInt(2,21);ps.setString(3,"女");ps.execute();} catch (Exception e) {e.printStackTrace();}到這里表中數(shù)據(jù)(id不連續(xù)主要自己刪了一行,這里不要在意)
PreparedStatement方式實(shí)現(xiàn)sql語句執(zhí)行,sql語句中先通過?來占位,然后通過setXX方法來拼串,方法中第一個(gè)參數(shù)代表第幾個(gè)參數(shù)。
- 兩種方式區(qū)別:
以上3點(diǎn)摘自:https://www.cnblogs.com/gbb123/p/7053772.html
SQL注入問題:
比如有這樣一個(gè)情況:
Statement進(jìn)行sql語句解析為:select * from user; delete user; -- where name = 'admin'; ,–后面的語句被注釋,而原本查詢用戶的語句變成了查詢所有用戶信息+刪除用戶表的語句,如果存在user用戶表,則信息全被刪了。
而PreparedStatement會(huì)將傳入的參數(shù)全當(dāng)作字符串來處理,不會(huì)對傳入?yún)?shù)進(jìn)行編譯,因此可以避免該問題。雖然這里用一個(gè)惡意表名來舉例,場景感不是很強(qiáng),但是換一種場景,在系統(tǒng)登錄界面,通過用戶名來搞惡意注入,那問題就大了。
executeQuery、executeUpdate 和 execute:
前邊有一個(gè)問題就是返回值問題,execute雖然是全能sql語句操作,可以執(zhí)行任何sql語句,但其返回值類型卻是boolean型,select語句執(zhí)行時(shí),如何得到查詢結(jié)果?
實(shí)際上,Statement和PreparedStatement接口都提供了三種執(zhí)行 SQL 語句的方法:executeQuery、executeUpdate 和 execute。
- executeQuery 用于產(chǎn)生單個(gè)結(jié)果集(ResultSet,不是單行數(shù)據(jù))的語句。
- executeUpdate 用于執(zhí)行 INSERT、UPDATE 或 DELETE 語句,SQL DDL(數(shù)據(jù)定義語言)語句,例如 CREATE TABLE 和 DROP TABLE。INSERT、UPDATE 或 DELETE 語句的效果是修改表中零行或多行中的一列或多列。executeUpdate 的返回值是一個(gè)整數(shù)(int),指示受影響的行數(shù)(即更新計(jì)數(shù))。對于 CREATE TABLE 或 DROP TABLE 等不操作行的語句,executeUpdate 的返回值總為零。
- execute 可用于執(zhí)行任何SQL語句,返回一個(gè)boolean值,表明執(zhí)行該SQL語句是否返回了ResultSet。如果執(zhí)行后第一個(gè)結(jié)果是ResultSet,則返回true,否則返回false。但它執(zhí)行SQL語句時(shí)比較麻煩,通常我們沒有必要使用execute方法來執(zhí)行SQL語句,而是使用executeQuery或executeUpdate更適合,但如果在不清楚SQL語句的類型時(shí)則只能使用execute方法來執(zhí)行該SQL語句了。
以上三者區(qū)別摘自:https://www.cnblogs.com/yunqingtuo/p/10512677.html
- execute實(shí)例:
返回false====true ,看出execute會(huì)在select語句中返回true,表明產(chǎn)生ResultSet結(jié)果集,而insert語句返回false
獲取execute的結(jié)果集:
stm = conn.createStatement(); boolean res1 = stm.execute("SELECT name,age from users where sex = '男'"); ResultSet resultSet = stm.getResultSet(); //注意通過Statement實(shí)例stm獲取結(jié)果集// ResultSetMetaData meta = resultSet.getMetaData(); //獲取每一條元數(shù)據(jù)信息 // int columnCount = meta.getColumnCount(); //統(tǒng)計(jì)一條元數(shù)據(jù)有幾個(gè)字段while (resultSet.next()){System.out.println("name:" + resultSet.getString("name") + ", age:" + resultSet.getInt("age")); }- executeQuery實(shí)例:
executeQuery返回值就是ResultSet,不必像execute通過stm.getResultSet()來獲取結(jié)果集。
- executeUpdate 實(shí)例:
結(jié)果:語句executeUpdate執(zhí)行后受影響的行數(shù)為:3,另外executeUpdate不可以執(zhí)行select操作
與50位技術(shù)專家面對面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖
總結(jié)
以上是生活随笔為你收集整理的JDBC连接mysql、创建表、操作数据、PreparedStatement防注入、sql语句返回值类型知识汇总的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java泛型失效的两种情况
- 下一篇: IDEA创建springboot项目:U