JDBC基础入门
課程筆記Day29
- JDBC快速入門
- JDBC相關API
- SQL注入問題
- JDBC工具類
第一章 JDBC快速入門
第01節 基礎理論
1、JDBC介紹
2、JDBC步驟
操作步驟
1. 導入jar包 2. 找到驅動 Driver 3. 獲取連接 Connection 4. 獲取操作 Statement 5. 查詢結果 ResultSet 6. 釋放資源第02節 案例代碼
1、準備數據
-- 1. 創建數據庫 DROP DATABASE IF EXISTS mydb08; CREATE DATABASE IF NOT EXISTS mydb08; USE mydb08;-- 2. 創建表 DROP TABLE IF EXISTS student; CREATE TABLE IF NOT EXISTS student(sid INT PRIMARY KEY AUTO_INCREMENT,sname VARCHAR(20) NOT NULL,sage INT );-- 3. 插入數據 INSERT INTO student VALUES (NULL,'定浩',18); INSERT INTO student VALUES (NULL,'郭龍',19); INSERT INTO student VALUES (NULL,'黃杰',17);-- 4. 查詢結果 SELECT * FROM student;2、代碼實現
//JDBC的快速入門 public class Demo {//啟動的順序: C->S->Rpublic static void main(String[] args) throws Exception {String username = "root";String password = "root";String url = "jdbc:mysql://localhost:3306/mydb08";String sql = "SELECT * FROM student";//----------------------//找到驅動的對象Class.forName("com.mysql.jdbc.Driver");//通過驅動管理者,獲取到連接 ConnectionConnection conn = DriverManager.getConnection(url, username, password);//通過連接 conn 獲取到操作的對象 StatementStatement stat = conn.createStatement();//執行SQL語句,查詢數據庫ResultSet resu = stat.executeQuery(sql);//循環遍歷結果集,獲取到結果集當中的數據while (resu.next()) { //判斷是否還存在下一行的數據,如果存在,則進入循環//獲取到指定的數據, 通過列名獲取到指定的數據值int id = resu.getInt("sid");String name = resu.getString("sname");int age = resu.getInt("sage");System.out.println(id + "\t" + name + "\t" + age);}//釋放資源,關閉的順序是相反的。R->S->Cresu.close();stat.close();conn.close();} }第二章 JDBC相關API
第01節 DriverManager類
底層代碼 DriverManager.getConnection(url,username,password)
public static Connection getConnection(String url,String user, String password) throws SQLException {//1. 創建了 Properties的對象 infojava.util.Properties info = new java.util.Properties();//2. 判斷用戶名是否為空, 如果不為空,則存放到properties當中if (user != null) {info.put("user", user);}//3. 判斷密碼是否為空, 如果不為空,則存放到properties當中if (password != null) {info.put("password", password);}//4. 調用自己的方法 getConnection(三個參數方法)return (getConnection(url, info, Reflection.getCallerClass())); }發現問題:
底層會將 username 和 password 進行 Properties 的封裝
底層實現
//構造方法,私有化修飾了 private DriverManager(){} //靜態代碼塊,只要類加載的時候,都會加載靜態代碼塊,加載靜態代碼塊的之后,才會調用 getConnection()方法 static {loadInitialDrivers();println("JDBC DriverManager initialized"); }//調用下面的方法 private static void loadInitialDrivers() {String drivers;try {drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {public String run() {return System.getProperty("jdbc.drivers");}});} catch (Exception ex) {drivers = null;}AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);Iterator<Driver> driversIterator = loadedDrivers.iterator();try{while(driversIterator.hasNext()) {driversIterator.next();}} catch(Throwable t) {}return null;}});//這里,什么時候驅動為null呢?就是上面出現異常之后為空。println("DriverManager.initialize: jdbc.drivers = " + drivers);if (drivers == null || drivers.equals("")) {return;}String[] driversList = drivers.split(":");println("number of Drivers:" + driversList.length);//底層在遍歷驅動for (String aDriver : driversList) {try {println("DriverManager.Initialize: loading " + aDriver);//核心代碼:底層會加載所有的驅動,通過ClassLoader去加載驅動Class.forName(aDriver, true,ClassLoader.getSystemClassLoader());} catch (Exception ex) {println("DriverManager.Initialize: load failed: " + ex);}} }注意事項:
Class.forName("com.mysql.jdbc.Driver");
可以省略不寫的,在高版本的JDBC當中,找驅動的底層會自動完成。
底層代碼當中,會有掃描驅動的操作。(底層在遍歷驅動)
Class.forName(aDriver, true,ClassLoader.getSystemClassLoader());
第02節 Connection 接口
1、核心方法
1. Statement createStatement() //獲取到操作數據的對象 Statement 接口對象 2. PreparedStatement prepareStatement(String sql) //預置操作數據的對象 PreparedStatement 接口對象 ------------------- 3. void setAutoCommit(boolean autoCommit) //是否開啟自動提交事務,如果傳遞值是 false 表示手動開啟事務,默認true 4. void commit() //提交事務的操作,多組SQL語句執行,沒有問題的情況下,則提交 5. void rollback() //回滾事務的操作,當SQL語句執行過程當中,出現異常的時候,則回滾2、事務處理
//目標:學習JDBC當中的事務處理方式 @SuppressWarnings("all") public class Test01 {public static void main(String[] args) {String username = "root";String password = "root";String url = "jdbc:mysql://localhost:3306/mydb08";String sql = "INSERT INTO student VALUES (3,'佳佳',18)";Connection conn = null;Statement stat = null;//----------------------try {//通過驅動管理者,獲取到連接 Connectionconn = DriverManager.getConnection(url, username, password);//****[1]開啟事務手動提交****conn.setAutoCommit(false);//************************//獲取到操作數據的對象stat = conn.createStatement();//執行SQL語句//執行增刪改 采用的方法是 executeUpdate 返回的結果是影響的行數int count = stat.executeUpdate(sql);//****[2]執行成功,則提交事務****conn.commit();//************************System.out.println(count > 0 ? "執行成功" : "執行失敗");} catch (SQLException e) {e.printStackTrace();//****[3]如果出現了異常,需要事務的回滾****try {conn.rollback();System.out.println("事務回滾執行了...");} catch (SQLException e1) {e1.printStackTrace();}//************************}finally {//進行資源的釋放if (stat!=null){try {stat.close();System.out.println("資源釋放stat...");} catch (SQLException e) {e.printStackTrace();}}if (conn!=null){try {conn.close();System.out.println("資源釋放conn...");} catch (SQLException e) {e.printStackTrace();}}}} }第03節 Statement 接口
1、核心方法
1. void addBatch(String sql) //可以用于批量執行SQL語句 2. int[] executeBatch() //與上面的方法搭配使用 3. int executeUpdate(String sql) //執行更新操作。增、刪、改 的SQL語句,需要使用此方法,返回的是影響行數 4. ResultSet executeQuery(String sql) //執行查詢的方法。返回的是結果集 ResultSet2、方法演示
//目標:學習Statement的常用方法 @SuppressWarnings("all") public class Test02 {String username = "root";String password = "root";String url = "jdbc:mysql://localhost:3306/mydb08";Connection conn = null;Statement stat = null;ResultSet resu = null;@Beforepublic void start() throws Exception {//通過驅動管理者,獲取到連接 Connectionconn = DriverManager.getConnection(url, username, password);//通過conn去獲取到操作數據庫的對象 statstat = conn.createStatement();}@Testpublic void testAddBatch() throws Exception{String sql1 = "INSERT INTO student VALUES (NULL,'佳佳1',18)";String sql2 = "INSERT INTO student VALUES (NULL,'佳佳2',18)";//將SQL語句批量的添加進去stat.addBatch(sql1);stat.addBatch(sql2);//執行操作int[] array = stat.executeBatch();System.out.println(Arrays.toString(array));}@Testpublic void testExecuteUpdate() throws Exception {String sql = "INSERT INTO student VALUES (NULL,'佳佳',18)";//executeUpdate 執行的是增刪改int count = stat.executeUpdate(sql);System.out.println("count = " + count);Assert.assertEquals(1, count);}@Testpublic void testExecuteQuery() throws Exception {String sql = "SELECT * FROM student";//執行的是查詢resu = stat.executeQuery(sql);//循環查找while (resu.next()) {int id = resu.getInt("sid");String name = resu.getString("sname");int age = resu.getInt("sage");System.out.println(id + "\t" + name + "\t" + age);}}@Afterpublic void end() throws Exception {//釋放資源,關閉的順序是相反的。R->S->Cif (resu != null) {resu.close();}if (stat != null) {stat.close();}if (conn != null) {conn.close();}} }第04節 ResultSet接口
1、核心方法
1. boolean next() //判斷是否還存在下一行的數據,可以作用在while循環判斷和if判斷語句當中 2. int getInt(int columnIndex) //獲取到int類型的數據,參數是查詢結果集的第幾個索引 3. int getInt(String columnLabel) //獲取到int類型的數據,參數是需要查詢的列的名稱 4. String getString(int columnIndex) //獲取到String類型的數據,參數是查詢結果集的第幾個索引 5. String getString(String columnLabel) //獲取到String類型的數據,參數是需要查詢的列的名稱2、方法演示
//目標:學習ResultSet的常用方法 @SuppressWarnings("all") public class Test03 {String username = "root";String password = "root";String url = "jdbc:mysql://localhost:3306/mydb08";Connection conn = null;Statement stat = null;ResultSet resu = null;@Beforepublic void start() throws Exception {//通過驅動管理者,獲取到連接 Connectionconn = DriverManager.getConnection(url, username, password);//通過conn去獲取到操作數據庫的對象 statstat = conn.createStatement();}@Testpublic void testNext() throws Exception{String sql = "SELECT * FROM student";ResultSet resu = stat.executeQuery(sql);boolean flag1 = resu.next();System.out.println("flag1 = " + flag1);boolean flag2 = resu.next();System.out.println("flag2 = " + flag2);boolean flag3 = resu.next();System.out.println("flag3 = " + flag3);boolean flag4 = resu.next();System.out.println("flag4 = " + flag4);}@Testpublic void testGetInt() throws Exception{String sql = "SELECT sname,sid FROM student";ResultSet resu = stat.executeQuery(sql);while (resu.next()) {int id1 = resu.getInt("sid");//System.out.println(id1);int id2 = resu.getInt(2);System.out.println(id1+","+id2);}}@Testpublic void testGetString() throws Exception{String sql = "SELECT sid,sname FROM student";ResultSet resu = stat.executeQuery(sql);while (resu.next()) {String name1 = resu.getString("sname");System.out.println("name1 = " + name1);String name2 = resu.getString(2);System.out.println("name2 = " + name2);}}@Afterpublic void end() throws Exception {//釋放資源,關閉的順序是相反的。R->S->Cif (resu != null) {resu.close();}if (stat != null) {stat.close();}if (conn != null) {conn.close();}} }第三章 SQL注入問題
第01節 數據準備
1、數據庫準備
-- 1. 創建新表 DROP TABLE IF EXISTS t_user; CREATE TABLE IF NOT EXISTS t_user(uid INT PRIMARY KEY AUTO_INCREMENT,uname VARCHAR(20),upass VARCHAR(20) );-- 2. 插入數據 INSERT INTO t_user VALUES (NULL,'zhangsan','333'); INSERT INTO t_user VALUES (NULL,'lisi','444');-- 3. 查詢數據 SELECT * FROM t_user;/*需求:做一個登錄的效果,如果輸入用戶名和密碼,只有都是正確的才能登錄成功 */ SELECT * FROM t_user WHERE uname = 'zhangsan' AND upass = '333'; SELECT * FROM t_user WHERE uname = 'zhangsan' OR '1=1' AND upass = '隨便寫都可以的';2、演示問題
//目標: 演示SQL注入的問題 @SuppressWarnings("all") public class Test01 {public static void main(String[] args) throws Exception {Scanner sc = new Scanner(System.in);System.out.println("請輸入用戶名: zhangsan' OR '1=1 ");String nameStr = sc.nextLine();System.out.println("請輸入密碼:");String passStr = sc.nextLine();String username = "root";String password = "root";String url = "jdbc:mysql://localhost:3306/mydb08";String sql = "SELECT * FROM t_user WHERE uname = '" + nameStr + "' AND upass = " + passStr;//通過驅動管理者,獲取到連接 ConnectionConnection conn = DriverManager.getConnection(url, username, password);//通過連接 conn 獲取到操作的對象 StatementStatement stat = conn.createStatement();//執行SQL語句,查詢數據庫ResultSet resu = stat.executeQuery(sql);//判斷是否存在數據呢?String message = "Sorry 登錄失敗,請檢查賬號和密碼";//只要存在下一條的記錄,則表示登錄成功if (resu.next()) {message = "登錄成功:" + nameStr;}System.out.println("message = " + message);//釋放資源resu.close();stat.close();conn.close();} }第02節 解決問題
1、需要使用API
//1. 當我們獲取到conn的對象之后,需要獲取到預置語句的對象PreparedStatement PreparedStatement prepareStatement(String sql) //2. 提前定義好SQL語句,采用占位符,占據位置。最后去設置占位符的值 void setInt(int parameterIndex, int x) //參數1: 第幾個問號, 參數2: 需要插入的值 void setString(int parameterIndex, String x) //參數1: 第幾個問號,參數2: 需要插入的值 //3. 執行SQL的操作 int executeUpdate() //執行 增、刪、改操作 ResultSet executeQuery() //執行 查詢操作2、解決問題
//目標: 解決SQL注入的問題 @SuppressWarnings("all") public class Test02 {public static void main(String[] args) throws Exception {Scanner sc = new Scanner(System.in);System.out.println("請輸入用戶名: zhangsan' OR '1=1");String nameStr = sc.nextLine();System.out.println("請輸入密碼:");String passStr = sc.nextLine();String username = "root";String password = "root";String url = "jdbc:mysql://localhost:3306/mydb08";//預置的SQL語句,里面的變量由問號(英文) 去代替String sql = "SELECT * FROM t_user WHERE uname = ? AND upass = ?";//通過驅動管理者,獲取到連接 ConnectionConnection conn = DriverManager.getConnection(url, username, password);//*********************//通過連接 conn 獲取到操作的對象 PreparedStatementPreparedStatement stat = conn.prepareStatement(sql);//設置參數值stat.setString(1,nameStr);stat.setString(2,passStr);//執行SQL語句,查詢數據庫ResultSet resu = stat.executeQuery();//*********************//判斷是否存在數據呢?String message = "Sorry 登錄失敗,請檢查賬號和密碼";//只要存在下一條的記錄,則表示登錄成功if (resu.next()) {message = "登錄成功:" + nameStr;}System.out.println("message = " + message);//釋放資源resu.close();stat.close();conn.close();} }第四章 JDBC工具類
第01節 配置文件
位置: src/jdbc.properties
url=jdbc:mysql://localhost:3306/mydb08 username=root password=root第02節 工具類
//定義JDBC的工具類 @SuppressWarnings("all") public class JDBCUtils {private static String url = null;private static String username = null;private static String password = null;private static Connection conn = null;private static PreparedStatement stat = null;private static ResultSet resu = null;/*** 靜態代碼塊,只加載一次。*/static{try {//在反射章節講過的類加載器,專門加載src下面的文件 properties,加載成為流對象InputStream is = ClassLoader.getSystemResourceAsStream("jdbc.properties");Properties pp = new Properties();pp.load(is);is.close();url = pp.getProperty("url");username = pp.getProperty("username");password = pp.getProperty("password");} catch (IOException e) {e.printStackTrace();}}/*** 自定義的方法,用于獲取數據庫的連接對象 Connection** @return*/public static Connection getConnection() {try {conn = DriverManager.getConnection(url, username, password);} catch (SQLException e) {e.printStackTrace();}return conn;}/*** 自定義的方法,用于操作 增刪改數據*/public static int exeUpdate(String sql, Map<Integer, Object> map) {//INSERT INTO 表名稱 VALUES (NULL,?,?,?);//map.put(1,1001);//map.put(2,"張三");//map.put(3,23);int lineNumber = -1;try {PreparedStatement stat = getConnection().prepareStatement(sql);//詢問map集合到底有多少個數據for (int i = 0; map != null && i < map.size(); i++) {//得到索引值int index = i + 1;stat.setObject(index, map.get(index));}//執行SQL語句lineNumber = stat.executeUpdate();} catch (SQLException e) {e.printStackTrace();}return lineNumber;}/*** 自定義的方法,用于操作*/public static ResultSet exeQuery(String sql) {//調用下面的重載方法return exeQuery(sql,null);}/*** 自定義的方法,用于操作 查詢數據*/public static ResultSet exeQuery(String sql, Map<Integer, Object> map) {//SELECT * FROM 表名 WHERE 列名1=? AND 列名2 = ?;try {PreparedStatement stat = getConnection().prepareStatement(sql);//詢問map集合到底有多少個數據for (int i = 0; map != null && i < map.size(); i++) {//得到索引值int index = i + 1;stat.setObject(index, map.get(index));}//具體的查詢操作resu = stat.executeQuery();} catch (SQLException e) {e.printStackTrace();}return resu;}/**** 釋放資源*/public static void close() {//判斷if (resu != null) {try {resu.close();} catch (SQLException e) {e.printStackTrace();}}//判斷if (stat != null) {try {stat.close();} catch (SQLException e) {e.printStackTrace();}}//判斷if (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}} }第03節 測試類
//測試類 @SuppressWarnings("all") public class Test {public static void main(String[] args) throws Exception {//測試添加數據的操作String sql1 = "INSERT INTO t_user VALUES (NULL,'zhaoliu',666)";int lineNumber = JDBCUtils.exeUpdate(sql1, null);System.out.println("lineNumber = " + lineNumber);System.out.println(lineNumber > 0 ? "成功" : "失敗");//2.釋放資源JDBCUtils.close();System.out.println("------------");//測試查詢所有的操作String sql2 = "SELECT * FROM t_user";ResultSet resu1 = JDBCUtils.exeQuery(sql2);while (resu1.next()){int uid = resu1.getInt("uid");String uname = resu1.getString("uname");String upass = resu1.getString("upass");System.out.println(uid+","+uname+","+upass);}//2.釋放資源JDBCUtils.close();} }第04節 打jar包
操作步驟1
操作步驟2
操作步驟3
操作步驟4
總結
- 上一篇: l启动进程 linux,《日子》. li
- 下一篇: API网关如何实现对服务下线实时感知