JDBC:
Java提供的一套操作數據庫數據的應用編程接口,作用在於通過Java代碼操作數據庫;dk所提供的相應的編程接口;
JDBC組件:
- DriverManager:一系列的數據驅動程序,匹配連接使用通信協議從Java應用程序中獲取合適的數據庫驅動;
- Connection:所有和數據庫相關的上下文操作通過該接口提供,提供數據庫的事務操作,Statment對象等接口方法;
- Statment:使用創建該接口的對象來進行SQL語句的提交到數據庫;
- ResultSet:存放使用SQL查詢數據庫返回的結果,本身是一個Set集合,多條數據是需要遍歷才能拿到對應結果的;
- SQLException:所有JDBC操作異常的同意處理類;
JDBC編程步驟:
數據庫連接的4個核心配置:
- 提供JDBC連接MySQL數據庫,需要MySQL的驅動包;
- 請求數據庫的URL;
- 數據庫賬號;
- 數據庫密碼;
數據庫編程:
- 加載數據庫驅動;
- 獲取數據庫的連接;
- 創建Statement對象;
- 執行SQL語句;
- 處理結果集 ;
代碼:
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test4", "root", "123456");
Statement statement = connection.createStatement();
String sql = "select * from student";
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
int sid = resultSet.getInt("sid");
String sname = resultSet.getString("sname");
int sage = resultSet.getInt("sage");
String ssex = resultSet.getString("ssex");
System.out.println(sid+"\t"+sname+"\t"+sage+"\t"+ssex);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
運行結果:
1 趙雷 20 男
2 前殿 20 男
3 孫風 21 男
4 吳蘭 18 女
5 孫蘭 17 女
注意:
getString()、getInt()等這些方法會將數據一次性裝入內存,所以數據量過大的時候,內存會裝不下就會拋出異常,而getObject()方法是每次調用就去數據庫獲取數據,不會將數據一次性全部裝入內存;
SQL注入問題
SQL注入問題::
由於dao層中執行的SQL語句是拼接出來的,其中一部分內容是用戶從客戶端輸入的,當傳入的數據中包含SQL關鍵字,就有可能通過這些關鍵字來改變SQL語句,從而執行一些特殊的操作,這種就稱爲SQL注入問題;
比如,有如下這樣一張user表:
public class TestDemo4 {
public static void main(String[] args) {
//前端輸入 用戶名和祕密
String name = "zhangsan";
String passwd = "1=1 or 2345";
boolean login = login(name, passwd);
if (login) System.out.println("登陸成功");
else System.out.println("登陸失敗");
}
/**
* 模擬前後臺交互接口
*
* @param userName:用戶名
* @param passwd:祕密
* @return true:登陸成功 false:登陸失敗
*/
public static boolean login(String userName, String passwd) {
boolean result = false;
try {
//加載驅動
Class.forName("com.mysql.jdbc.Driver");
//獲取Connection連接
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test5", "root", "123456");
//獲取Statement對象
Statement statement = connection.createStatement();
String sql = " select * from user where name='"+userName+"' and passwd="+passwd+"";
boolean b = statement.execute(sql);
if(b) {
result = true;
}
/*
String sql = "select * from user where name = ? and passwd=?";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1, userName);
statement.setString(2, passwd);
//執行SQL
ResultSet resultSet = statement.executeQuery();
//結果處理
if (resultSet.next()) {
result = true;
}*/
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return result;
}
}
運行結果:
密碼明明是錯的,但是因爲SQL語句的改變1=1是成立的,所以它也能登陸成功,這就是SQL的注入問題,解決辦法就是用PreparedStatement(屏蔽的那部分代碼);
如何解決SQL注入問題:
- 採用預編譯的Statement對象;PreparedStatement採用預編譯機制將SQL語句的主幹和參數分別傳輸給數據庫,數據庫是可以分辨SQL語句中的主幹和參數,這樣即使SQL中帶有關鍵字,數據庫也僅僅是將其當作參數使用,關鍵字就不起作用;
與Statement語句一樣,PreparedStatement語句同樣可以完成向數據庫發送SQL語句,獲取數據庫操作結果的功能。PreparedStatement語句習慣地稱爲預處理語句。
Statement對象在每次執行SQL語句時都將該語句傳送給數據庫,然後數據庫解釋器負責將SQL語句轉換成內部命令,並執行該命令,完成相應的數據庫操作,這種機制,每次向數據庫發送一條SQL語句時,都要先轉化成內部命令,如果不斷的執行程序,就會加重解釋器的負擔,影響執行的速度。
而PreparedStatement對象,將SQL語句傳送給數據庫進行預編譯,以後需要執行同一條語句時就不再需要重新編譯,直接執行就可以了,這樣就大大提高了數據庫的執行速度。
儘量使用預編譯的PreparedStatement,PreparedStatement的主要優勢如下:
- 防止SQL注入問題;
- 使用預編譯機制可以提高執行效率(執行前已經完成解析,到時候直接運行即可);
- SQL語句中的參數值是通過?的形式來代替參數,再使用PreparedStatement方法的set方法來設置參數值,相對於SQL直接拼接更加優雅;
PreparedStatement和Statement的區別:
- 語法不同:PreparedStatement使用預編譯的SQL,Statement使用靜態的SQL;
- 效率不同:PreparedStatement執行效率較高;
- 安全性不同:PreparedStatement可以防止SQL注入;
JDBC提供的事務相關的操作:
通過Connection接口下的方法提供的,比如設置手動、自動提交、事務的提交、回滾等等;