DriverManager類
java.sql.DriverManager 是用於管理一組JDBC驅動程序的基本服務。
注意: JDBC 2.0 API中新增的DataSource接口提供了另一種連接到數據源的方法。 使用DataSource對象是連接到數據源的首選方法。
DriverManager類功能
注冊驅動
告訴程序該使用什么數據庫驅動jar
可以直接使用DriverManager類的靜態方法注冊驅動:
static void registerDriver(Driver driver)
// 注冊與給定的驅動程序 DriverManager 。
也可以間接使用該方法,如下介紹直接和間接調用DriverManager類的靜態方法注冊驅動。
如我們要連接操作的是MySQL,那么我們就要注冊驅動,告訴程序要使用MySQL驅動架包。如下就是注冊MySQL數據庫驅動:
注冊驅動第一種方法:
Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
// 將字節碼文件Driver.java加載進內存,返回Driver.class對象。
注冊驅動第二種方法:
com.mysql.jdbc.Driver driver = new com.mysql.jdbc.Driver();
DriverManager.registerDriver(driver);
com.mysql.jdbc.Driver類中存在靜態代碼塊,如下:
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
這里可以看出來,兩種驅動方法其實都是一樣的,都要用到靜態方法registerDriver()
備注:MySQL 5 之后的驅動jar包可以省略注冊驅動的步驟。
獲取數據庫連接
方法
static Connection getConnection(String url, String user, String password)
方法說明
這是java.sql.DriverManager類的靜態方法,用來獲取數據庫連接。該方法的返回值是Connection對象。
參數說明:
url:指定連接的路徑
user:用戶名
password:密碼
連接的是MySQL數據庫時,參數url格式舉例說明
語法:jdbc:mysql://ip地址(域名):端口號/數據庫名稱
例子:jdbc:mysql://localhost:3306/Study
細節:如果連接的是本機mysql服務器,並且mysql服務默認端口是3306,則url可以簡寫為:jdbc:mysql:///數據庫名稱
Connection接口
java.sql.Connection接口是一個數據庫連接對象。它與特定數據庫的連接(會話)。 執行SQL語句並在連接的上下文中返回結果。
Connection接口功能
獲取執行SQL的對象
方法:
Statement createStatement()
// 創建一個 Statement對象,用於將SQL語句發送到數據庫。
PreparedStatement prepareStatement(String sql)
// 創建一個 PreparedStatement對象,用於將參數化的SQL語句發送到數據庫。
管理事務
方法:
開啟事務
void setAutoCommit(boolean autoCommit)
// 將此連接的自動提交模式設置為給定狀態。參數為false,即開啟事務
提交事務
void commit()
// 使自上次提交/回滾以來所做的所有更改都將永久性,並釋放此 Connection對象當前持有的任何數據庫鎖。
回滾事務
void rollback()
// 撤消在當前事務中所做的所有更改,並釋放此 Connection對象當前持有的任何數據庫鎖。
Statement接口
java.sql.Statement接口,用於執行靜態SQL語句並返回其生成的結果的對象。
默認情況下,每個Statement
對象只能有一個ResultSet
對象同時打開。 因此,如果一個ResultSet
對象的讀取與另一個對象的讀取交錯,則ResultSet
對象必須由不同的Statement
對象生成。 在所有執行方法Statement
接口隱式關閉當前ResultSet
聲明的對象,如果一個開放的存在。
Statement接口功能
執行靜態SQL語句
方法:
boolean execute(String sql)
// 執行給定的SQL語句,這可能會返回多個結果。該方法可以執行任意的SQL語句。
int executeUpdate(String sql)
// 執行給定的SQL語句。執行的是DML(insert、update、delete)語句、DDL(create,alter、drop)語句
// 返回值是一個int類型的數 ———— 執行的SQL語句影響的行數
ResultSet executeQuery(String sql)
// 執行給定的SQL語句,該語句返回單個ResultSet對象。執行DQL(select)語句
舉例
連接Study數據庫,向account表中的id=1的balance字段值加上500。表數據如下:
Java代碼實現:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcDemo01 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 1、導入jar包:mysql-connector-java-5.1.48.jar
// Add as Library ...
// 2、注冊驅動
Class.forName("com.mysql.jdbc.Driver");
// 3、獲取數據庫連接對象
Connection connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/Study?useSSL=false",
"用戶名", "密碼");
// 4、定義SQL語句
// 將account表中的id=1的balance字段值加上500
String sql = "UPDATE account Set balance = balance + 500 WHERE id = 1;";
// 5、獲取執行sql的對象 Statement
Statement statement = connection.createStatement();
// 6、執行SQL語句:執行成功,返回 1
int returnResult = statement.executeUpdate(sql);
// 7、查看是否執行成功
System.out.println(returnResult);
// 8、釋放資源
statement.close();
connection.close();
}
}
執行成功,控制台輸出:1,說明影響的行數是一行。
查看表中現在的數據:
ResultSet接口
表示數據庫結果集的數據表,通常通過執行查詢數據庫的語句生成。即該接口是結果集對象,用來封裝查詢結果。
ResultSet
對象保持一個光標指向其當前的數據行。 最初,光標位於第一行之前。 next
方法將光標移動到下一行,並且由於在ResultSet
對象中沒有更多行時返回false
,因此可以在while
循環中使用循環來遍歷結果集。
下面介紹幾個具代表性的方法
ResultSet接口功能
游標向下移動一行
boolean next()
// 將光標從當前位置向前移動一行。
獲取數據
getXxx(參數列表) 方法
String getString(int columnIndex)
// 這個檢索的當前行中指定列的值 ResultSet對象為 String的Java編程語言。
// int columnIndex:列的索引,索引從1開始,1對應第一列
String getString(String columnLabel)
// 這個檢索的當前行中指定列的值 ResultSet對象為 String的Java編程語言。
// String columnLabel:指定的列名稱
int getInt(int columnIndex)
// 這個檢索的當前行中指定列的值 ResultSet作為對象 int在Java編程語言。
// int columnIndex:列的索引
舉例
題目:查看account表中的記錄,account表位於本地mysql的Study數據庫下,端口號為3306
account表
account表如下:
CREATE TABLE account (
id INT PRIMARY KEY AUTO_INCREMENT, -- id
NAME VARCHAR(10), -- 名字
balance DOUBLE -- 余額
);
INSERT INTO account (NAME, balance) VALUES ('LeeHua', 1500), ('Tom', 1000);
Java程序實現:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSet;
public class JdbcDemo03 {
public static void main(String[] args) {
Statement statement = null;
Connection connection = null;
ResultSet resultSet = null;
try {
// 1. 注冊驅動
Class.forName("com.mysql.jdbc.Driver");
// 2. 定義SQL語句
String sql = "SELECT * FROM account;";
// 3.獲取Connection對象
connection = DriverManager.getConnection(
"jdbc:mysql:///Study?useSSL=false", "LeeHua", "qq562246926"
);
// 4.獲取執行sql的對象 Statement
statement = connection.createStatement();
// 5.執行sql,返回查詢結果(一個表),用ResultSet對象來封裝。
resultSet = statement.executeQuery(sql);
// 6.處理結果
// 6.1 循環判斷游標是否是最后一行末尾。
while(resultSet.next()){
// 獲取數據
// 6.2 獲取數據
// 獲取 ID 字段的值
int id = resultSet.getInt(1);
// 獲取name字段的值
String name = resultSet.getString("name");
// 獲取balance字段的值
double balance = resultSet.getDouble(3);
// 輸出
System.out.println(id + " --- " + name + " --- " + balance);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 7. 釋放資源
releaseResources(resultSet);
releaseResources(statement);
releaseResources(connection);
}
}
public static <T> void releaseResources (T t){
if(t != null){
try {
// 利用反射,獲取class對象
Class<?> aClass = t.getClass();
// 獲取class對象中的方法對象
Method close = aClass.getMethod("close");
// 執行方法
close.invoke(t);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
PreparedStatement接口
PreparedStatement接口 extends Statement接口,表示預編譯的SQL語句的對象。SQL語句已預編譯並存儲在PreparedStatement
對象中。 然后可以使用該對象多次有效地執行此語句。
預編譯的SQL:參數使用?作為占位符
如:
new Statement.executeQuery(sql1);
new PreparedStatement.executeQuery(sql2);
兩個對象都執行SQL語句,Statement接口是執行靜態SQL的,即已經拼接好的SQL,而PreparedStatement接口是執行預編譯的SQL語句的。
如:
sql1 = "SELECT * FROM account WHERE id = ID AND balance = 賬戶余額;"
sql2 = "SELECT * FROM account WHERE id = ? AND balance = ?;"
sql1是靜態的SQL語句,sql2是預編譯SQL語句。
PreparedStatement接口的用法和其父接口Statement的用法差不多,只是父接口是執行靜態SQL語句的,而PreparedStatement接口是傳入並執行預編譯的SQL語句的。
給?賦值
方法: setXxx(參數1,參數2)
參數說明:
參數1:?的位置編號 從1 開始
參數2:?的值
如:
void setInt(int parameterIndex, int x)
// 將指定的參數設置為給定的Java int值。
void setString(int parameterIndex, String x)
// 將指定的參數設置為給定的Java String值。
舉例
需求:獲取數據庫中字段的記錄,對比用戶輸入,模擬登陸。
實現
自定義一個注解,用於獲取部分值:
package my.view.util;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE) // 注解能作用於類上
@Retention(RetentionPolicy.RUNTIME) // 當前被描述的注解,會保留到class字節碼文件中,並被JVM讀取到
public @interface PropertiesAnnotation {
/* URL */
public abstract String url();
/* 用戶 */
public abstract String user();
/* 密碼 */
public abstract String password();
/* 驅動包 */
public abstract String driver();
}
創建一個MySQL表格:
CREATE TABLE login (
id INT PRIMARY KEY AUTO_INCREMENT, -- id
user VARCHAR(30), -- 用戶名
password VARCHAR(30) -- 密碼
);
向表格中傳入數據:
INSERT INTO login (user, password) VALUES ('LeeHua', '123456'), ('Tom', 'abcdef');
創建一個Jdbc工具類,用來注冊驅動和獲取連接對象:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
@PropertiesAnnotation(
url = "jdbc:mysql:///Study", user = "mysql賬號", password = "mysql密碼", driver = "com.mysql.jdbc.Driver"
)
public class JdbcUtils02 {
private static String url;
private static String user;
private static String password;
private static String driver;
/* 文件的讀取,只需要讀取一次即可拿到這些值。利用反射和注解、使用靜態代碼塊 */
static{
// 讀取資源文件,獲取值。
try {
// 1. 解析注解
// 1.1 獲取JdbcUtils02類的字節碼文件對象
Class<JdbcUtils02> jdbcUtils02Class = JdbcUtils02.class;
// 2. 獲取上邊的注解對象
PropertiesAnnotation annotation = jdbcUtils02Class.getAnnotation(PropertiesAnnotation.class);
// 3. 調用注解中定義的抽象方法,獲取返回值,賦值給靜態成員變量
url = annotation.url();
user = annotation.user();
password = annotation.password();
driver = annotation.driver();
// 4. 注冊驅動
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 獲取連接
* @return 連接對象
*/
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
}
View Code
使用Statement接口,創建一個登錄類:
public boolean login(String user, String password) {
if (user == null || password == null) {
return false;
}
Connection connection =null;
Statement statement = null;
ResultSet resultSet = null;
try {
// 獲取數據庫連接
connection = JdbcUtils02.getConnection();
// 定義SQL
String sql = "SELECT * FROM login WHERE user = '" + user + "' AND password = '" + password + "';";
// 獲取執行SQL對象
statement = connection.createStatement();
// 執行查詢
resultSet = statement.executeQuery(sql);
// 判斷是否存在下一行數據
return resultSet.next();
} catch (SQLException e) {
e.printStackTrace();
}
return false;
}
使用PreparedStatement接口,創建一個登錄類:
public boolean login(String user, String password) {
if (user == null || password == null) {
return false;
}
Connection connection =null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
// 獲取數據庫連接
connection = JdbcUtils02.getConnection();
// 定義SQL
String sql = "SELECT * FROM login WHERE user = ? AND password = ?;";
// 獲取執行SQL語句對象
preparedStatement = connection.prepareStatement(sql);
// 給?賦值
preparedStatement.setString(1, user);
preparedStatement.setString(2, password);
// 執行SQL語句
resultSet = preparedStatement.executeQuery();
// 判斷是否存在下一行數據
return resultSet.next();
} catch (SQLException e) {
e.printStackTrace();
}
return false;
}
模擬測試:登錄方法在Demo類中。
public class Demo {
public static void main(String[] args) {
// 鍵盤錄入,接收用戶名和密碼
Scanner scn = new Scanner(System.in);
System.out.print("請輸入用戶名:");
String userName = scn.nextLine();
System.out.print("請輸入密碼:");
String password = scn.nextLine();
// 調用登錄確認方法
Demo demo08 = new Demo();
if (demo.login(userName, password)) {
System.out.println("登錄成功!");
} else {
System.out.println("登錄失敗!用戶名或密碼額錯誤。");
}
}
}
- 調用使用Statement接口創建的登錄方法測試:
如果正常情況下輸入,那么該方法判斷用戶賬號密碼是否正確是有效的。如果輸入恆等式,那么該方法就失效了,無論輸入什么恆等式,都可以登錄,舉例如:
請輸入用戶名:LeeHua
請輸入密碼:abc' OR 'abc' = 'abc
那么這個時候,被拼接好的SQL語句就如下:
SELECT * FROM login WHERE user = 'LeeHua' AND password = 'abc' OR 'abc' = 'abc';
這是一條恆等式,不論 password是否正確,都可以登錄成功,這是相當危險的,就像別人能夠隨隨便便登錄個人微信一樣,安全隱患很大,所以我們使用預編譯的SQL語句,不使用靜態SQL語句。
運行,控制台輸出:登錄成功!
- 調用使用PreparedStatement接口創建的登錄方法測試:
這個時候無論輸入什么,都會判斷正確,因為這里傳入的是一條預編譯的SQL語句,並不是拼接的SQL語句。
舉例如:
請輸入用戶名:LeeHua
請輸入密碼:abc' OR 'abc' = 'abc
那么這個時候實質傳入的SQL語句是:
SELECT * FROM login WHERE user = 'LeeHua' AND password = 'abc' OR 'abc' = 'abc';
運行,控制台輸出:登錄失敗!用戶名或密碼額錯誤。
所以,判斷用戶名和密碼是准確的。