JDBC
概念:
Java Data Base Connectivity (Java 連接數(shù)據(jù)庫)
JDBC伐坏,其實就是Java定義的一套和數(shù)據(jù)庫建立連接的規(guī)范(接口),
那么各家數(shù)據(jù)庫廠商桨昙,想要Java去操作各家的數(shù)據(jù)庫骡楼,
必須實現(xiàn)這套接口扎拣,
我們把數(shù)據(jù)庫廠商寫的這套實現(xiàn)類赴肚,稱之為數(shù)據(jù)庫驅(qū)動
在沒有jdbc之前,
我們想用Java連接數(shù)據(jù)庫二蓝,需要進行如下步驟:
雖然也不是非常麻煩誉券,但是:
- 針對不同的數(shù)據(jù)庫,我們需要編寫不同的驅(qū)動代碼
- 每當任意一家數(shù)據(jù)庫更新時侣夷,維護起來也是十分麻煩的
正是因為上述兩點致命麻煩横朋,Java針對連接數(shù)據(jù)庫,提出了一套機制 —— JDBC
因此百拓,JDBC有如下優(yōu)點:
優(yōu)點:
- 維護方便
- 數(shù)據(jù)庫廠商的底層實現(xiàn)改變琴锭,不影響Java應(yīng)用程序
一般地,jdbc的接口衙传,都存放在:
JDK提供的
- java.sql.*
- javax.sql.*
包下
那么决帖,現(xiàn)在本人來講解下使用JDBC的使用步驟:
使用步驟:
使用步驟:
- 導入數(shù)據(jù)庫的驅(qū)動jar包
- 加載驅(qū)動jar包
- 獲取連接對象
- 獲取操作對象
- 開始操作
- 釋放資源
那么,現(xiàn)在本人來展示下JDBC的使用:
package edu.youzg.about_jdbc.core;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class Demo {
public static void main(String[] args) throws Exception {
//2. 加載驅(qū)動jar包
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/dbstudy";
String userName = "root";
String password = "123456";
//3. 獲取連接對象
Connection connection = DriverManager.getConnection(url, userName, password);
//4. 獲取操作對象
Statement statement = connection.createStatement();
String sql = "update test set emp_fname='Youzg'";
//5. 開始操作
int i = statement.executeUpdate(sql);
if(i>0){
System.out.println(i);
System.out.println("修改成功");
}else{
System.out.println("修改失敗");
}
//6. 釋放資源
connection.close();
statement.close();
}
}
本人先來展示下運行前的表內(nèi)容:
現(xiàn)在蓖捶,本人來展示下運行后的表中數(shù)據(jù):
那么地回,本人對上述步驟的第2步進行下講解:
- execute(sql):
用來執(zhí)行所有的SQL語句
返回:
如果第一個結(jié)果為 ResultSet 對象,則返回 true俊鱼;
如果其為更新刻像、計數(shù)或者不存在任何結(jié)果,則返回 false- executeUpdate(sql):
用來執(zhí)行DML語句
用來對表中數(shù)據(jù)進行增并闲、刪细睡、改
返回值:
影響的行數(shù)- executeQuery(sql):
用來執(zhí)行DQl語句
結(jié)果集對象 ResultSet:
概念:
結(jié)果集對象,是我們執(zhí)行了查詢語句之后返回的一個查詢結(jié)果對象
ResultSet 對象具有指向其當前數(shù)據(jù)行的光標
最初帝火,光標被置于第一行之前溜徙。
next()方法將光標移動到下一行;
因為該方法在 ResultSet 對象沒有下一行時返回 false犀填,
所以可以在 while循環(huán)中使用它來迭代結(jié)果集
例如:
現(xiàn)在我要查詢表中數(shù)據(jù):
package edu.youzg.about_jdbc.core;
import java.sql.*;
public class Demo2 {
public static void main(String[] args) throws Exception{
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/dbstudy", "root", "123456");
Statement statement = connection.createStatement();
String sql = "select * from test";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
System.out.println(resultSet.getInt(1)
+ "==" + resultSet.getString(2)
+ "==" + resultSet.getString(3)
+ "==" + resultSet.getString(4));
}
connection.close();
statement.close();
resultSet.close();
}
}
那么蠢壹,本人現(xiàn)在來展示下運行結(jié)果:
那么,還記得本人在《Java SE》專欄最后說的嗎九巡?
等我們學習了數(shù)據(jù)庫的相關(guān)知識后图贸,
用戶登錄信息就可以保存在數(shù)據(jù)庫中,就不用用一張配置表來保存了
這樣既簡化了注冊用戶的問題,也保證了用戶賬號信息的安全性
本人來給出一張保存用戶登錄信息的表:
那么求妹,現(xiàn)在本人僅來展示下檢驗用戶信息的代碼:
package edu.youzg.about_jdbc.core;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
public class LoginDemo {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
System.out.println("請輸入用戶名");
String username = sc.nextLine().trim();
System.out.println("請輸入密碼");
String password = sc.nextLine().trim();
//使用JDBC登錄
Class.forName("com.mysql.jdbc.Driver");
//建立連接
Connection conn = DriverManager.getConnection("jdbc:mysql:///dbstudy", "root", "123456");
//獲取操作對象
Statement statement = conn.createStatement();
//發(fā)送sql語句判斷是否登錄成功
String sql="select * from users where username='"+username+"' and password='"+password+"'";
ResultSet resultSet = statement.executeQuery(sql);
if(resultSet.next()){
System.out.println("登錄成功");
}else{
System.out.println("登錄失敗");
}
//釋放資源
conn.close();
statement.close();
resultSet.close();
}
}
那么乏盐,本人來展示下運行結(jié)果:
其實佳窑,上面的做法也是不安全的
本人現(xiàn)在來展示下為什么說是不安全的:
相信同學們這時候就疑惑了:為什么用戶登錄信息表中并沒有保存該登錄信息制恍,卻能夠登陸呢?
答曰:
請看我們最后拼出來的sql字符串:
select * from users where username='1' or '1'='1' and password='1' or '1'='1';
相信看到這里神凑,同學們就明白了登陸成功的原因了净神。
而這種現(xiàn)象,我們也有專門的名詞來形容它 —— sql注入
那么溉委,有沒有什么辦法能夠防止sql注入呢鹃唯?
答曰:
預(yù)編譯操做對象 PreparedStatement
那么,現(xiàn)在本人來介紹下 預(yù)編譯操做對象 PreparedStatement:
PreparedStatement:
使用步驟:
- 連接對象.prepareStatement(sql);
- sql語句中的字段的值用?問號占位
- 給sql語句中的問號賦值
本人現(xiàn)在來展示下PreparedStatement的使用:
package edu.youzg.about_jdbc.core;
import java.sql.*;
import java.util.Scanner;
public class LoginDemo1 {
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
System.out.println("請輸入用戶名");
String username = sc.nextLine().trim();
System.out.println("請輸入密碼");
String password = sc.nextLine().trim();
//使用JDBC登錄
Class.forName("com.mysql.jdbc.Driver");
//建立連接
Connection conn = DriverManager.getConnection("jdbc:mysql:///dbstudy", "root", "123456");
//獲取操作對象
String sql="SELECT * FROM users WHERE username=? AND PASSWORD=?";
//獲取一個預(yù)編譯操作對象 PreparedStatement
PreparedStatement preparedStatement = conn.prepareStatement(sql); //把SQL語句給給這個預(yù)編譯操作對象
//下來給問號賦值 參1.問號的順序瓣喊,從1開始數(shù) 參數(shù)2 問號的值
preparedStatement.setString(1,username);
preparedStatement.setString(2,password);
ResultSet resultSet = preparedStatement.executeQuery(); //這里就不要再傳入SQL語句
if(resultSet.next()){
System.out.println("登錄成功");
}else{
System.out.println("登錄失敗");
}
//釋放資源
conn.close();
preparedStatement.close();
resultSet.close();
}
}
那么坡慌,本人再來進行下sql注入,來展示下運行結(jié)果:
可以看到:預(yù)編譯操作對象的使用藻三,放置了sql注入洪橘!
那么,為了方便我們之后的操作棵帽,本人來給出一個方便我們JDBC操作的工具類:
package edu.youzg.about_jdbc.utils;
import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;
/**
* 此工具用于實現(xiàn)JDBC的基本 增熄求、刪、改逗概、查 操作
*/
public class JDBCUtils {
private static String url;
private static String user;
private static String password;
private JDBCUtils() {
}
static {
try {
//讀取配置文件中數(shù)據(jù)庫的配置
Properties properties = new Properties();
properties.load(new FileInputStream("JDBCStudy/src/jdbcConfig.properties"));
//注冊驅(qū)動
Class.forName(properties.getProperty("driver"));
url = properties.getProperty("url");
user = properties.getProperty("user");
password =properties.getProperty("password");
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
Connection connection = DriverManager.getConnection(url, user, password);
return connection;
}
public static void close(Connection connection, Statement statement) throws SQLException {
if (connection != null) {
connection.close();
}
if (statement != null) {
statement.close();
}
}
public static void close(Connection connection, Statement statement, ResultSet resultSet) throws SQLException {
if (connection != null) {
connection.close();
}
if (statement != null) {
statement.close();
}
if (resultSet != null) {
resultSet.close();
}
}
}
那么弟晚,相應(yīng)地,本人來給出一個配置文件:
driver=com.mysql.jdbc.Driver
#注意:這里的url是本人根據(jù)本人的數(shù)據(jù)庫信息配置的逾苫,同學們請根據(jù)自己的數(shù)據(jù)庫信息來給url賦值
url=jdbc:mysql://localhost:3306/dbstudy
user=root
password=123456
在本篇博文的最后卿城,本人來講解下如何在JDBC中獲取自增長鍵的值:
獲取自增長鍵的值:
步驟:
- 要獲取自增長鍵的值,需要在獲取操作對象時聲明一個參數(shù):
Statement.RETURN_GENERATED_KEYS
即:
PreparedStatement preparedStatement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
- 當數(shù)據(jù)插入成功后铅搓,就可以取出這個自增長鍵的值:
//獲取自增長鍵的結(jié)果集
ResultSet generatedKeys = preparedStatement.getGeneratedKeys();
while (generatedKeys.next()){
keyValue = generatedKeys.getInt(1);
}
- 之后就可以對循環(huán)中每次取出的自增長鍵值做處理了