1.1 JDBC概念和本質
JDBC是sun公司提供的一套操作關係型數據庫的規範(接口),這些接口由各個數據庫生產商實現。數據庫生產商將接口的實現類會打成一個開發包,這個開發包就是jar包。我們要使用哪個數據庫將哪個數據庫廠商提供的jar導入程序就行了。
1.2 JDBC入門程序
public class JdbcDemo1 {
public static void main(String[] args) throws Exception {
//1. 導入驅動jar包
//2.註冊驅動
Class.forName("com.mysql.jdbc.Driver");
//3.獲取數據庫連接對象 假設獲取連接的時候要Driver對象
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db3", "root", "root");
//4.定義sql語句
String sql = "update account set balance = 500 where id=1";
//5.獲取執行sql的對象 Statement
Statement stmt = conn.createStatement();
//6.執行sql
int count = stmt.executeUpdate(sql);
//7.處理結果
System.out.println(count);
//8.釋放資源
stmt.close();
conn.close();
}
}
jar 的導入: 在項目的根目錄下新建一個lib目錄,把mysql-connector-java-5.1.37-bin.jar放進去
2.JDBC中API
2.1 com.sql.DriverManager作用
1、註冊驅動:DriverManager.registerDriver(new Driver()),但是我們不使用,在開發中使用Class.forName("com.mysql.jdbc.Driver"),因爲使用DriverManager的registerDriver註冊驅動會註冊兩次。
2、獲取連接:
static Connection getConnection(String url, String user, String password);
String url:連接數據庫的路徑
語法:jdbc:mysql://localhost:3306/數據庫名稱
如果是本機的數據庫,可以簡寫:jdbc:mysql:///數據庫名稱
String user:用戶名
String password:密碼
2.2 com.sql.Connetion作用
1、獲取執行sql語句的對象
Statement createStatement();
PreparedStatement preparedStatement(String sql);
2、事務管理(下面專題6講解)
2.3 com.sql.Statement作用
作用:執行sql語句
1. boolean execute(String sql) :可以執行任意的sql 瞭解,如果執行的是查詢語句,就返回
2. true,如果執行的是DML或者DDL語句,那麼就返回false。
3. int executeUpdate(String sql) :執行DML(insert、update、delete)語句、
DDL(create,alter、drop)語句
* 返回值:影響的行數,可以通過這個影響的行數判斷DML語句是否執行成功 返回值>0的
則執行成功,反之,則失敗。
5. ResultSet executeQuery(String sql) :執行DQL(select)語句
2.4 com.sql.ResultSet作用
1、判斷是否有下一條數據
2、獲取當前行數據
while (rs.next()){
//獲取id
int id = rs.getInt("id");
//獲取name
String name = rs.getString("name");
//獲取balance
double balance = rs.getDouble("balance");
//打印結果
System.out.println(id+","+name+","+balance);
}
注意:如果該列的數據類型是int類型,也可以使用getString(“列名”)來獲取,但是反過來就不行。getInt(1)表示獲取第一列的值,而getInt(“1”)表示獲取列名爲1的這一列的值,二者有區別。
3.使用Statement對象執行增、刪、改、查操作
3.1 執行增、刪、改的步驟
1、註冊驅動:Class.forName("com.mysql.jdbc.Driver");
2、獲取鏈接:DriverManager.getConnection("jdbc:mysql://localhost:3306/數據庫名","root","root");
3、獲取執行sql的Statement對象:stmt = conn.createStatement();
4、執行sql語句,獲取結果
5、處理結果
6、釋放資源
3.2 執行查詢的步驟
1、註冊驅動:Class.forName("com.mysql.jdbc.Driver");
2、獲取鏈接:DriverManager.getConnection("jdbc:mysql://localhost:3306/數據庫名","root","root");
3、獲取執行sql的Statement對象:stmt = conn.createStatement();
4、執行sql語句,獲取結果集
5、遍歷結果集獲取數據
6、釋放資源
4.JDBCUtils工具類
- 目標和分析
/*
將jdbc操作重複的代碼封裝到此工具類中
封裝如下操作:
加載配置文件 只需要加載一次就行了,放到靜態代碼塊中
註冊驅動:Class.forName("com.mysql.jdbc.Driver"); 只需要註冊一次就行了,放到靜態代碼塊中
獲取連接:conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db3","root","root");
釋放資源
目的:簡化jdbc代碼的數據
*/
- 在JDBCUtils工具類的靜態代碼塊中讀取配置文件和註冊驅動(核心代碼)
static {
try {
//加載配置文件
//1 創建Properties 對象
Properties properties=new Properties();
//2 調用load方法加載配置文件
//使用類加載器獲取src路徑中文件的輸入流對象
//ClassLoader loader = JDBCUtils.class.getClassLoader();
//獲取流
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
properties.load(is);
//3 調用getProperty方法根據key獲取value值
String driver = properties.getProperty("driver");
url=properties.getProperty("url");
user=properties.getProperty("user");
password=properties.getProperty("password");
// 註冊驅動
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
- 在JDBCUtils工具類中對外提供獲取連接和釋放資源的方法
//對外提供一個獲取連接的方法
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,user,password);
}
//對外提供一個釋放資源的方法
public static void close(Statement stmt,Connection conn){
close(null,stmt,conn);
}
//重載
public static void close(ResultSet rs, Statement stmt,Connection conn){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
5.使用PreparedStatement對象執行增、刪、改、查操作
5.1 sql注入漏洞的原因和解決辦法
原因:在使用Statement對象執行sql語句時,如果sql語句中拼接的變量包含sql關鍵字,那麼就可能會出現sql注入漏洞。
解決:不使用Statement對象,使用PreparedStatement對象執行sql。
PreparedStatement相比Statement的優點
1、不會產生sql注入漏洞問題
2、效率高
5.2 PreparedStatement對象執行增、刪、改
1、通過工具類獲取連接
2、獲取PreparedStatement對象,預編譯sql語句
3、如果sql語句中有?佔位符,那麼就設置參數
4、執行增刪改,獲取影響的行數,int count=pstmt.executeUpdate();
5、處理結果
6、釋放資源
public class InsertTest {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
//1 通過工具類獲取連接
conn = JdbcUtils.getConnection();
//2 獲取PreparedStatement對象,預編譯sql語句
pstmt = conn.prepareStatement("insert into account values(null,?,?)");
//3 如果sql語句中有?,那麼就設置參數
pstmt.setString(1,"小迷妹");
pstmt.setDouble(2,0.5);
//4 執行sql,獲取結果
int count = pstmt.executeUpdate();
//5 處理結果
System.out.println(count>0?"添加成功":"添加失敗");
} catch (SQLException e) {
e.printStackTrace();
} finally {
//6 釋放資源
JdbcUtils.close(pstmt,conn);
}
}
}
5.3 PreparedStatement對象執行查詢
1、通過工具類獲取連接
2、獲取PreparedStatement對象,預編譯sql語句
3、如果sql語句中有?佔位符,那麼就設置參數
4、執行查詢操作,獲取結果集對象;ResultSet rs = pstmt.executeQuery();
5、遍歷結果集,獲取數據
6、釋放資源
//定義一個登錄的方法
public static boolean login(String name,String password){
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
//1 通過工具類獲取連接
conn = JdbcUtils.getConnection();
//2 獲取PreparedStatement對象,預編譯sql語句
pstmt = conn.prepareStatement("select * from user where name=? and password=?");
//3 如果有?佔位符就設置參數
pstmt.setString(1,name);
pstmt.setString(2,password);
//4 執行sql 獲取結果
rs = pstmt.executeQuery();
//5 處理結果,返回結果
return rs.next();
} catch (SQLException e) {
e.printStackTrace();
} finally {
//6 釋放資源,
JdbcUtils.close(rs,pstmt,conn);
}
return false;
}
6.jdbc事務管理
1 事務管理的概念
一組sql操作要麼同時成功要麼同時失敗,那麼就需要統一管理,這就是事務管理。
6.2 事務管理API
獲取到連接對象之後開啓事務:conn.setAutoCommit(false);
一組sql執行完成之後提交事務:conn.commit();
在catch中回滾事務:conn.rollback();
注意:在執行事務管理的時候,一般是捕獲一個最大的Exception異常,出現任何異常都要回滾。
6.3 代碼示例
public class TransactionTest {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
//1 通過工具類獲取連接
conn = JdbcUtils.getConnection();
//開啓事務-------------------------------
conn.setAutoCommit(false);
//2 獲取PreparedStatement對象,預編譯sql語句
pstmt = conn.prepareStatement("update account set balance=balance+? where name=?");
//1、張三的賬戶-500
//3 如果有?,就設置參數
pstmt.setDouble(1,-500);
pstmt.setString(2,"張三");
//4 執行sql
pstmt.executeUpdate();
//製造異常
//int i=10/0;
//2、楊鋅怒的賬戶+500
//3 如果有?,就設置參數
pstmt.setDouble(1,500);
pstmt.setString(2,"楊鋅怒");
//4 執行sql
pstmt.executeUpdate();
//提交事務-------------------------------
conn.commit();
} catch (Exception e) {
// e.printStackTrace();
System.out.println("事務回滾了");
//回滾事務---------------------------------
if (conn!=null) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
} finally {
//6 釋放資源
JdbcUtils.close(pstmt,conn);
}
}
}
總結
1、JDBCUtils工具類封裝 註冊驅動、獲取連接、釋放資源
private static String url;
private static String user;
private static String password;
static {
//1 加載配置文件 只需要加載一次
//1.1 創建Properties對象
Properties properties=new Properties();
//1.2 調用load方法加載配置文件
InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
try {
properties.load(is);
//1.3 調用getProperty方法,根據key獲取value值
String driver = properties.getProperty("driver");
url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("password");
//2 註冊驅動 只需要註冊一次 可以放到靜態代碼塊中
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
2、使用PreparedStatement對象執行增刪改查的思路
增刪改的思路:
1、通過工具類獲取連接
2、獲取PreparedStatement對象,預編譯sql語句
3、如果sql語句中有?佔位符,那麼就設置參數
4、執行增刪改,獲取影響的行數,int count=pstmt.executeUpdate();
5、處理結果
6、釋放資源
查詢的思路:
1、通過工具類獲取連接
2、獲取PreparedStatement對象,預編譯sql語句
3、如果sql語句中有?佔位符,那麼就設置參數
4、執行查詢操作,獲取結果集對象;ResultSet rs = pstmt.executeQuery();
5、遍歷結果集,獲取數據
6、釋放資源
3、使用JDBC完成事務管理