MySQL JDBC常用知識,封裝工具類,時區問題配置,SQL注入問題
JDBC
JDBC介紹
Sun公司為了簡化開發人員的(對數據庫的統一)操作,提供了(Java操作數據庫的)規範,俗稱JDBC,這些規範的由具體由具體的廠商去做
對於開發人員來說,我們只需要掌握JDBC接口的操作即可

所需要的jar包
- java.sql(默認有)
- javax.sql(默認有)
還需要導入數據庫驅動包
java程序鏈接mySQL
注意! 增刪改操作都需要提交事務
步驟:
- 加載驅動
- 登陸鏈接數據庫對象
- 創建statement對象,用於執行sql語句 statement(清單)
- 執行sql語句
- 返回結果集,結果集中封裝了我們查詢的所有結果
- 釋放鏈接
// 1.加載驅動
Class.forName("com.mysql.jdbc.Driver");
//協議://主機:端口/數據庫名?編碼設置&使用安全的鏈接
String url = "url=jdbc:mysql://localhost:3306/db01?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=true";
String use = "root"; //用戶名
String password = "123456"; //密碼
//2.登陸鏈接數據庫對象
Connection connection = DriverManager.getConnection(url, use, password);
//3.創建statement對象,用於執行sql語句 statement(清單)
Statement statement = connection.createStatement();
//4.執行sql語句
String sql = "SELECT * from class"; //sql語句
//5.返回結果集,結果集中封裝了我們查詢的所有結果
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()){
System.out.println("classno:"+resultSet.getNString("classno"));
System.out.println("classname:"+resultSet.getNString("classname"));
System.out.println("department:"+resultSet.getNString("department"));
System.out.println("monitor(班長):"+resultSet.getNString("monitor(班長)"));
System.out.println("==========================================================");
}
//6.釋放鏈接
resultSet.close();
statement.close();
connection.close();
}
}
幾個重要對象
DirverManager 驅動管理
Class.forName("com.mysql.jdbc.Driver");
DriverManager.registerDriver(new Driver()); //這是Driver源碼
URL 資源地址
//協議://主機:端口/數據庫名?時區設置&編碼設置&使用安全的鏈接
String url = "url=jdbc:mysql://localhost:3306/db01?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=true";
Connection 鏈接對象,操作數據庫的對象
connection.commit(); //提交事務
connection.rollback(); //回滾事務
connection.setAutoCommit(); //自動提交事務
/* Statemen 清單,執行sql的對象 */
```java
statement.executeQuery("sql"); //執行查詢,返回結果集
statement.executeUpdate("sql"); //執行更新(插入和刪除也算更新),返回受影響的行數
statement.execute("sql"); //執行全部的sql語句
ResultSet:查詢後的結果集
獲取數據:
resultSet.getNString();
resultSet.getObject(); //不知道什麼類型的情況下使用
resultSet.getInt();
resultSet.getDate();
resultSet.getFloat();
指針移動:
resultSet.next();
resultSet.previous();
resultSet.absolute();
resultSet.beforeFirst();
resultSet.afterLast();
關閉鏈接
resultSet.close();
statement.close();
connection.close();
SQL注入的問題
SQL注入即是指web應用程序對用戶輸入數據的合法性沒有判斷或過濾不嚴,攻擊者可以在web應用程序中事先定義好的查詢語句的結尾上添加額外的SQL語句,在管理員不知情的情況下實現非法操作,以此來實現欺騙數據庫服務器執行非授權的任意查詢,從而進一步得到相應的數據信息。
即:通過sql語句的漏洞來實現一些非法操作.
// 欲根據用戶id來進行獲取用戶的其他信息,但是使用如下語句就會將所有用戶的信息都查詢到
select * from db01.user where (id =' 'or 1=1)"; --sql注入
PreparedStatement對象
可以防止sql注入,並且效率更高,如:在編輯sql語句時使用?代表佔位符,並且預編譯sql語句,隨後在設置參數防止sql注入
常用方法:
preparedStatement.executeQuery();
preparedStatement.executeUpdate();
preparedStatement.setString(); //給參數傳遞字符串類型的值
preparedStatement.setInt(); //給參數傳遞 int 類型的值
preparedStatement.setDate(); //給參數傳遞 Date 類型的值
... 等等
例子:
//帶參數的sql語句
String sql = "select * from db01.user where(id = ?)" ;
//預編譯sql語句並且返回一個PreparedStatement對象
preparedStatement = con.prepareStatement(sql);
//給參數傳遞值(適當的使用對應類型的方法能提高效率)
preparedStatement.setString(1,id); //注意下標從1開始
//運行sql語句
resultSet = preparedStatement.executeQuery();
解藕,封裝工具類
我們可以將配置信息編寫成配置文件(xxx.properties),然後通過Properties類讀取文件內容對應參數來配置信息
配置文件db.properties, 我們需要將此配置文件放入位元組碼的相同路徑(maven項目的resources目錄下)
# 驅動類名
driver=com.mysql.cj.jdbc.Driver
# //協議://主機:端口/數據庫名?設置時區&編碼設置&使用安全的鏈接協議
url=jdbc:mysql://localhost:3306/db01?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=true
user=root
password=123456
JdbcUtil類
package SQL_injection;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtility {
// 初始化變量,並且避免作用域問題
static Properties properties = new Properties();
static Connection con = null;
static PreparedStatement preparedStatement = null;
static ResultSet resultSet = null;
static String username = null;
static String password = null;
//初始化配置
static {
// 獲取輸入流, 通過此類的類加載器獲取類加載路徑,進而獲取到配置文件的輸入流
InputStream in = JdbcUtility.class.getClassLoader().getResourceAsStream("db.properties");
try {
// 通過properties對象加載配置文件的輸入流
properties.load(in);
//相當於加載驅動Class.forName("com.mysql.jdbc.Driver"); 只不過是將配置文件的driver參數獲取出來
JdbcUtility.class.forName(properties.getProperty("driver"));
} catch (Exception e) {
e.printStackTrace();
}
}
//使用配置文件內容信息鏈接數據庫
public JdbcUtility(){
try {
//獲取配置文件信息
String url = properties.getProperty("url");
String user = properties.getProperty("user");
String password = properties.getProperty("password");
// 根據參數鏈接數據庫
con = DriverManager.getConnection(url,user,password);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
//使用自定義的用戶名和密碼登陸數據庫
public JdbcUtility(String username,String password){
try {
con = DriverManager.getConnection(properties.getProperty("url"), username, password);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
public boolean select(String id){
String sql = "select * from db01.user where(id = ?)" ;
//執行查詢語句
try {
preparedStatement = con.prepareStatement(sql);
preparedStatement.setString(1,id);
resultSet = preparedStatement.executeQuery();
if(!resultSet.next()) {
System.out.println("查詢失敗!");
return false;
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return true;
}
public void getResult(){
try {
do {
System.out.print("id:"+resultSet.getString(1)+"\t");
//System.out.println("password:"+resultSet.getString(0)+"\t");
System.out.print("name:"+resultSet.getString(3)+"\t");
System.out.print("sex:"+resultSet.getString(4)+"\t");
System.out.print("birthday:"+resultSet.getString(5)+"\t");
System.out.println();
}
while (resultSet.next());
}
catch (Exception e){
e.printStackTrace();
}
}
public void insert(String id ,String name,String sex ){
String sql = "insert into db01.user (id,name,sex,birthday) " +
"values(?,?,?,?)" ;
try {
preparedStatement = con.prepareStatement(sql);
preparedStatement.setString(1,id);
preparedStatement.setString(2,name);
preparedStatement.setString(3,sex);
Date date = new Date(new java.util.Date().getTime());
preparedStatement.setDate(4,date);
int n = preparedStatement.executeUpdate();
if (n == 0) System.out.println("插入失敗!");
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
//刪除
public void delete(String id){
String sql = "delete from db01.user where(id = ?);" ;
try {
preparedStatement = con.prepareStatement(sql);
preparedStatement.setString(1,id);
if (preparedStatement.executeUpdate()==0) System.out.println("刪除失敗!");
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
public void update(String id,String columnname,String value){
String sql = "update db01.user set "+columnname +" = ? where (id = ? )" ;
try {
preparedStatement = con.prepareStatement(sql);
//preparedStatement.setString(1,columnname);
preparedStatement.setString(1,value);
preparedStatement.setString(2,id);
if(preparedStatement.executeUpdate()==0) System.out.println("更新失敗");
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
//關閉
public void close(){
try {
resultSet.close();
con.close();
preparedStatement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
JDBC操作事務
注意! 增刪改操作都需要提交事務
常用方法
connection.setAutoCommit(boolean flag); //設置事務是否自動提交,默認是提交的
connection.commit(); //提交事務
connection.rollback(); //回滾事務,一般不用設置,事務一般發送錯誤會自動回滾
下面代碼是模擬一筆轉賬操作,A賬戶減少100元,B賬戶增加100元,兩個sql操作為一個事務,同時執行成功或者失敗(失敗事務發生回滾)
JdbcUtility jdbc = new JdbcUtility();
try {
//關閉自動提交事務
jdbc.con.setAutoCommit(false);
//進行一筆轉賬操作,其中update()方法,參數1代表付款或者收款人,參數2代表是否收款
jdbc.update("A",true);
jdbc.update("B",false);
//提交一筆轉賬事務
jdbc.con.commit();
} catch (SQLException throwables) {
try {
//實際上事務會自動回滾當出現錯誤時
jdbc.con.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
throwables.printStackTrace();
}

