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);
}
}
}
運行結果:
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/514252.html
標籤:其他
上一篇:力扣 兩數之和 Go實作
