JDBC和連接池02 3.ResultSet[結果集] 基本介紹 表示資料庫結果集的數據表,通常通過執行查詢資料庫的語句生成 ResultSet對象保持一個游標指向其當前的數據行,最初,游標位於第一行的之前 next方法將游標移動到下一行,並且由於在ResultSet對象中沒有更多行時返回false ...
JDBC和連接池02
3.ResultSet[結果集]
- 基本介紹
- 表示資料庫結果集的數據表,通常通過執行查詢資料庫的語句生成
- ResultSet對象保持一個游標指向其當前的數據行,最初,游標位於第一行的之前
- next方法將游標移動到下一行,並且由於在ResultSet對象中沒有更多行時返回false,因此可以在while迴圈中使用迴圈來遍歷結果集
例子
首先在資料庫的actor表中添加兩行數據
INSERT INTO actor VALUES(NULL,'劉德華','男','1970-12-12','110'),
(NULL,'jack','男','1990-11-11','112')
package li.jdbc.resultset_;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Date;
import java.util.Properties;
@SuppressWarnings("all")
public class ResultSet_ {
public static void main(String[] args) throws Exception {
//通過Properties對象拿到配置文件的信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
//獲取相關的值
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url = properties.getProperty("url");
String driver = properties.getProperty("driver");
//1.註冊驅動
Class.forName(driver);//建議寫上
//2.得到連接
Connection connection = DriverManager.getConnection(url, user, password);
//3.得到statement
Statement statement = connection.createStatement();
//4.組織sql
String sql = "select id,name,sex,borndate from actor";
//執行給定的sql語句,該語句返回單個ResultSet對象
/**
+----+-----------+-----+----------------------+
| id | name | sex | borndate |
+----+-----------+-----+----------------------+
| 1 | 劉德華 | 男 | 1970-12-12 00:00:00 |
| 2 | jack | 男 | 1990-11-11 00:00:00 |
+----+-----------+-----+----------------------+
*/
/**
* resultset源碼 ResultSet對象的結構
*
*/
ResultSet resultSet = statement.executeQuery(sql);
//5.使用while迴圈取出數據
//最開始時next指向表頭(第一行之前)
while (resultSet.next()) {//讓游標向後移動,如果沒有更多行,則返回false
int id = resultSet.getInt(1);//獲取該行的第1列數據
String name = resultSet.getString(2);//獲取該行的第2列數據
String sex = resultSet.getString(3);//獲取該行的第3列數據
Date date = resultSet.getDate(4);//獲取該行的第4列數據
System.out.println(id+"\t"+name+"\t"+sex+"\t"+date);
}
//6.關閉連接
resultSet.close();
statement.close();
connection.close();
}
}
運行結果如下:
在語句ResultSet resultSet = statement.executeQuery(sql);
旁打上斷點,點擊debug,點擊step over,選擇resultset數組,再選擇rowdata。
可以看到底層是arraylist的一個對象數組。
4.Statement
- 基本介紹
- Statement對象,用於執行靜態SQL語句並返回其生成的結果的對象
- 在建立連接後,需要對資料庫進行訪問,執行命名或是SQL語句,可以通過
- Statement [存在SQL註入問題]
- PreparedStatement [預處理]
- CallableStatement [存儲過程]
- Statement對象執行SQL語句,存在SQL註入風險
- SQL註入是利用某些系統沒有對用戶輸入的數據進行充分的檢查,而在用戶輸入數據中註入非法的SQL語句段或命令,惡意攻擊資料庫
- 要防範SQL註入,只要用PreparedStatement(從Statement擴展而來)取代Statement就可以了
例子1-sqlyog演示sql註入
-- 演示sql註入
-- 創建一張表
CREATE TABLE admin( -- 管理員表
NAME VARCHAR(32) NOT NULL UNIQUE,
pwd VARCHAR(32) NOT NULL DEFAULT ''
)CHARACTER SET utf8;
-- 添加數據
INSERT INTO admin VALUES('tom','123');
-- 正常情況下,查找某個管理是否存在
SELECT * FROM admin
WHERE NAME = 'tom' AND pwd = '123';
-- SQL註入
-- 輸入用戶名為 1' or
-- 輸入密碼為 or '1'='1
-- 這樣就變成了下麵的語句,可以將所有的數據都查找出來
SELECT * FROM admin
WHERE NAME = '1' OR' AND pwd = 'OR '1'='1';
例子2-java程式演示SQL註入
package li.jdbc.statement;
//演示statement的註入問題
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
import java.util.Scanner;
public class Statement_ {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
//讓用戶輸入管理員的名字和密碼
System.out.print("請輸入管理員的名字:");
String admin_name = scanner.nextLine();//如果希望看到SQL註入,這裡需要使用nextLine,如果用next():當接收到空格或者 '就是表示結束
System.out.print("請輸入管理員的密碼:");
String admin_pwd = scanner.nextLine();
//通過Properties對象拿到配置文件的信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
//獲取相關的值
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url = properties.getProperty("url");
String driver = properties.getProperty("driver");
//1.註冊驅動
Class.forName(driver);
//2.獲取連接
Connection connection = DriverManager.getConnection(url, user, password);
//3.得到Statement對象
Statement statement = connection.createStatement();
//4.組織SQL語句
String sql = "select name,pwd from admin where name='"
+ admin_name + "' and pwd ='" + admin_pwd + "'";
ResultSet resultSet = statement.executeQuery(sql);
if (resultSet.next()) {//如果查詢到一條記錄,則說明該管理員存在
System.out.println("恭喜,登錄成功");
} else {
System.out.println("對不起,登錄失敗");
}
//5.關閉連接
resultSet.close();
statement.close();
connection.close();
}
}
5.PreparedStatement[預處理查詢]
- 基本介紹
-
PreparedStatement執行的SQL語句中的 參數用問號(?)來表示,調用PreparedStatement對象的setXxx()方法來設置這些參數。
setXxx()方法有兩個參數,第一個參數是要設置的SQL語句中的參數的索引(從1開始),第二個參數是設置的SQL語句中的參數的值
-
調用executeQuery(),返回ResultSet對象
-
調用executeUpdate():執行更新,包括增,刪,修改
- 預處理的好處
- 不再使用+拼接sql語句,減少語法錯誤
- 有效地解決了SQL註入問題
- 大大減少了編譯次數,效率較高
例子-解決SQL註入問題
package li.jdbc.preparedstatement_;
import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;
import java.util.Scanner;
//演示PreparedStatement的使用
@SuppressWarnings("all")
public class PreparedStatement_ {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
//讓用戶輸入管理員的名字和密碼
System.out.print("請輸入管理員的名字:");
String admin_name = scanner.nextLine();
System.out.print("請輸入管理員的密碼:");
String admin_pwd = scanner.nextLine();
//通過Properties對象拿到配置文件的信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
//獲取相關的值
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url = properties.getProperty("url");
String driver = properties.getProperty("driver");
//1.註冊驅動
Class.forName(driver);
//2.獲取連接
Connection connection = DriverManager.getConnection(url, user, password);
//3.得到PreparedStatement對象
//3.1組織SQL語句,sql語句的問號就相當於占位符
String sql = "select name,pwd from admin where name= ? and pwd = ?";
//3.2preparedStatement對象是實現了 PreparedStatement介面的 實現類的 對象
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//3.3給 ? 賦值
preparedStatement.setString(1,admin_name);
preparedStatement.setString(2,admin_pwd);
//4.執行select語句使用 executeQuery
// 如果執行的是dml(update,insert,delete)語句使用executeUpdate
// 這裡執行 executeQuery,不用再寫sql進去了
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {//如果查詢到一條記錄,則說明該管理員存在
System.out.println("恭喜,登錄成功");
} else {
System.out.println("對不起,登錄失敗");
}
//5.關閉連接
resultSet.close();
preparedStatement.close();
connection.close();
}
}
5.1預處理DML
package li.jdbc.preparedstatement_;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Properties;
import java.util.Scanner;
//演示PreparedStatement的使用
@SuppressWarnings("all")
public class PreparedStatementDML_ {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
//讓用戶輸入管理員的名字和密碼
System.out.print("請輸入管理員的名字:");
String admin_name = scanner.nextLine();
// System.out.print("請輸入管理員的密碼:");
// String admin_pwd = scanner.nextLine();
//通過Properties對象拿到配置文件的信息
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
//獲取相關的值
String user = properties.getProperty("user");
String password = properties.getProperty("password");
String url = properties.getProperty("url");
String driver = properties.getProperty("driver");
//1.註冊驅動
Class.forName(driver);
//2.獲取連接
Connection connection = DriverManager.getConnection(url, user, password);
//3.得到PreparedStatement對象
//3.1組織SQL語句,sql語句的問號就相當於占位符
//添加記錄
//String sql = "insert into admin values (?,?)";
//更改
//String sql = "update admin set pwd=? where name =?";
//刪除
String sql = "delete from admin where name=?";
//3.2preparedStatement對象是實現了 PreparedStatement介面的 實現類的 對象
PreparedStatement preparedStatement = connection.prepareStatement(sql);
//3.3給 ? 賦值
preparedStatement.setString(1, admin_name);
// preparedStatement.setString(2, admin_pwd);
//4.執行dml(update,insert,delete)語句使用executeUpdate
int rows = preparedStatement.executeUpdate();
System.out.println(rows > 0 ? "執行成功" : "執行失敗");
//5.關閉連接
preparedStatement.close();
connection.close();
}
}
- 練習
參考上面的代碼
- 創建admin表
- 使用PreparedStatement添加5條數據
- 修改tom的記錄,將name改成King
- 刪除一條記錄
- 查詢全部記錄,並顯示在控制台
6.JDBC API
7.JDBCUtils開發
7.1封裝JDBCUtils
- 說明
在jdbc操作中,獲取連接和釋放資源是經常使用到的,可以將其封裝為JDBC連接的工具類JDBCUtils
例子
封裝的工具類JDBCUtils:
package li.jdbc.utils;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
/**
* 這是一個工具類,完成mysql的連接和關閉資源
*/
public class JDBCUtils {
//定義相關的屬性(4個),因為只需要一份,因此我們將其做成static屬性
private static String user;//用戶名
private static String password;//密碼
private static String url;//url
private static String driver;//驅動名
//在static代碼塊去初始化
static {
Properties properties = new Properties();
try {
properties.load(new FileInputStream("src\\mysql.properties"));
user = properties.getProperty("user");
password = properties.getProperty("password");
url = properties.getProperty("url");
driver = properties.getProperty("driver");
} catch (IOException e) {
//在實際開發中往往會這樣處理
// 1.將 編譯異常 轉為 運行異常
// 2.這時調用者可以選擇捕獲該異常,亦可以選擇預設處理該異常,比較方便
// (對於運行異常,程式中如果沒有處理,預設就是throw的方式處理)
throw new RuntimeException(e);
}
}
//連接資料庫,返回Connection
public static Connection getConnection() {
try {
return DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
//將 編譯異常 轉為 運行異常,原因同上
throw new RuntimeException(e);
}
}
//關閉相關資源
/**
* 1.ResultSet 結果集
* 2.Statement 或者 PreparedStatement
* 3.Connection
* 4.如果需要關閉資源,就傳入對象,否則就傳入null
*/
//這裡用Statement作為參數接收,是因為Statement是PreparedStatement的父介面,
// 因此Statement參數既可以接收Statement的對象實現,也可以接收PreparedStatement類型的對象實現
public static void close(ResultSet set, Statement statement, Connection connection) {
//判斷是否為null
try {
if (set != null) {
set.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
//將 編譯異常 轉為 運行異常,原因同上
throw new RuntimeException(e);
}
}
}
使用測試JDBCUtils_Use:
package li.jdbc.utils;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
/**
* 該類演示如何使用JDBCUtils工具類,完成 dml和 select
*/
public class JDBCUtils_Use {
@Test
public void testSelect() {//insert update delete
//1.得到連接
Connection connection = null;
//2.組織一個sql語句
String sql = "Select * from actor";
//3.創建PreparedStatement對象
PreparedStatement preparedStatement = null;
ResultSet set = null;
try {
connection = JDBCUtils.getConnection();
preparedStatement = connection.prepareStatement(sql);
//執行sql,得到結果集
set = preparedStatement.executeQuery();
//遍歷該結果集
while (set.next()) {
int id = set.getInt("id");
String name = set.getString("name");
String sex = set.getString("sex");
Date borndate = set.getDate("borndate");
String phone = set.getString("phone");
System.out.println(id + "\t" + name + "\t" + sex + "\t" + borndate + "\t" + phone);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
//關閉資源
JDBCUtils.close(set, preparedStatement, connection);
}
}
@Test
public void testDML() {//insert update delete
//1.得到連接
Connection connection = null;
//2.組織一個sql語句
String sql = "update actor set name=? where id=?";
//3.創建PreparedStatement對象
PreparedStatement preparedStatement = null;
try {
connection = JDBCUtils.getConnection();
preparedStatement = connection.prepareStatement(sql);
//給占位符賦值
preparedStatement.setString(1, "周星星");//第1個占位符的值為周星星
preparedStatement.setInt(2, 1);//第2個占位符的值為1
//執行sql
preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
//關閉資源
JDBCUtils.close(null, preparedStatement, connection);
}
}
}
運行結果: