JDBC筆記(1)
jdbc介紹
JDBC 是 Java 訪問數(shù)據(jù)庫的標準規(guī)范,真正怎么操作數(shù)據(jù)庫還需要具體的實現(xiàn)類轮蜕,也就是數(shù)據(jù)庫驅(qū)動。每個數(shù)據(jù)庫廠商根據(jù)自家數(shù)據(jù)庫的通信格式編寫好自己數(shù)據(jù)庫的驅(qū)動。所以我們只需要會調(diào)用JDBC 接口中的方法即可削解,數(shù)據(jù)庫驅(qū)動由數(shù)據(jù)庫廠商提供营勤。
使用 JDBC 的好處:
- 程序員如果要開發(fā)訪問數(shù)據(jù)庫的程序灵嫌,只需要會調(diào)用 JDBC 接口中的方法即可壹罚,不用關注類是如何實現(xiàn)的。
- 使用同一套 Java 代碼寿羞,進行少量的修改就可以訪問其他 JDBC 支持的數(shù)據(jù)庫
jdbc簡單入門
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
* 步驟:
1. 導入驅(qū)動jar包 mysql-connector-java-5.1.37-bin.jar
1.復制mysql-connector-java-5.1.37-bin.jar到項目的libs目錄下
2.右鍵-->Add As Library
2. 注冊驅(qū)動
3. 獲取數(shù)據(jù)庫連接對象 Connection
4. 定義sql
5. 獲取執(zhí)行sql語句的對象 Statement
6. 執(zhí)行sql猖凛,接受返回結果
7. 處理結果
8. 釋放資源
public class JdbcDemo01 {
public static void main(String[] args) throws Exception {
//1.導入jar包 建立lib目錄
//2.注冊驅(qū)動 Class.forName(數(shù)據(jù)庫驅(qū)動實現(xiàn)類) 加載和注冊數(shù)據(jù)庫驅(qū)動,數(shù)據(jù)庫驅(qū)動由 mysql 廠商
// "com.mysql.jdbc.Driver" jdk3.0后可以不寫
Class.forName("com.mysql.jdbc.Driver");
//3.獲取數(shù)據(jù)庫連接對象 協(xié)議名:子協(xié)議://服務器名或 IP 地址:端口號/數(shù)據(jù)庫名?參數(shù)=參數(shù)值
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db4", "root", "root");
//4.定義sql語句
String sql = "update stu2 set age = 50 where id=1";
//5.獲取執(zhí)行sql的對象Statement
Statement stat = conn.createStatement();
//6.執(zhí)行sql
int i = stat.executeUpdate(sql);
//7.處理結果
System.out.println(i);
//8.釋放資源
stat.close();
conn.close();
}
}
jdbc案例:實現(xiàn)登錄
工具類:連接方法绪穆,釋放資源方法
package cn.itcast.util;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
public class JdbsUtils {
private static String url;
private static String user;
private static String password;
private static String driver;
static {
try {
//1.創(chuàng)建properties集合類
Properties pro = new Properties();
//2.獲取src路徑下文件的位置辨泳,用ClassLoader類加載器
ClassLoader classLoader = JdbsUtils.class.getClassLoader();
URL res = classLoader.getResource("jdbc.properties");
String path = res.getPath();
//3.加載文件
pro.load(new FileReader(path));
//4.獲取數(shù)據(jù),賦值
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
driver = pro.getProperty("driver");
//5.注冊驅(qū)動
Class.forName(driver);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,user,password);
}
/**
* 釋放資源
* @param stat
* @param conn
*/
public static void close(Statement stat, Connection conn){
if(stat != null){
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(Statement stat, Connection conn, ResultSet rs){
if(stat != null){
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(rs!= null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
配置文件jdbc.properties
url = jdbc:mysql:///db4
user = root
password = root
driver = com.mysql.jdbc.Driver
測試類
login沒使用 PreparedStatement 接口玖院,可以sql注入
login2使用了 PreparedStatement 接口
PreparedStatement 是 Statement 接口的子接口菠红,繼承于父接口中所有的方法。它是一個預編譯的 SQL 語句
PreparedSatement 的好處
- prepareStatement()會先將 SQL 語句發(fā)送給數(shù)據(jù)庫預編譯难菌。PreparedStatement 會引用著預編譯后的結果试溯。
可以多次傳入不同的參數(shù)給 PreparedStatement 對象并執(zhí)行。減少 SQL 編譯次數(shù)郊酒,提高效率遇绞。 - 安全性更高,沒有 SQL 注入的隱患燎窘。
- 提高了程序的可讀性
使用 PreparedStatement 的步驟:
- 編寫 SQL 語句摹闽,未知內(nèi)容使用?占位:"SELECT * FROM user WHERE name=? AND password=?";
- 獲得 PreparedStatement 對象
- 設置實際參數(shù):setXxx(占位符的位置, 真實的值)
- 執(zhí)行參數(shù)化 SQL 語句
- 關閉資源
package cn.itcast.jdbc;
import cn.itcast.util.JdbsUtils;
import java.sql.*;
import java.util.Scanner;
public class JdbcDemoUserLogin {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("請輸入用戶名");
String username = sc.nextLine();
System.out.println("請輸入密碼");
String password = sc.nextLine();
boolean flg = new JdbcDemoUserLogin().login2(username, password);
if (flg){
System.out.println("登錄成功");
}else {
System.out.println("用戶名或密碼錯誤");
}
}
public boolean login(String username,String password){
Connection conn = null;
Statement stat = null;
ResultSet rs = null;
if(username==null || password == null){
return false;
}
try {
conn = JdbsUtils.getConnection();
stat = conn.createStatement();
String sql = "select *from user where username = '"+username+"' and password = '"+password+"'";
rs = stat.executeQuery(sql);
/*if (rs.next()){
return true;
}
else {
return false;
}*/
return rs.next();
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbsUtils.close(stat,conn,rs);
}
return false;
}
public boolean login2(String username,String password){
Connection conn = null;
PreparedStatement pstat = null;
ResultSet rs = null;
if(username==null || password == null){
return false;
}
try {
conn = JdbsUtils.getConnection();
String sql = "select *from user where username = ? and password = ?";
pstat = conn.prepareStatement(sql);
pstat.setString(1,username);
pstat.setString(2,password);
rs = pstat.executeQuery();
/*if (rs.next()){
return true;
}
else {
return false;
}*/
return rs.next();
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbsUtils.close(pstat,conn,rs);
}
return false;
}
}
jdbc事務處理
使用了JdbcUtils工具類
Connection 接口中與事務有關的方法
void setAutoCommit(boolean autoCommit) 參數(shù)是 true 或 false 如果設置為 false,表示關閉自動提交荠耽,相當于開啟事務
void commit() 提交事務
void rollback() 回滾事務
開發(fā)步驟
1) 獲取連接
2) 開啟事務
3) 獲取到 PreparedStatement
4) 使用 PreparedStatement 執(zhí)行兩次更新操作
5) 正常情況下提交事務
6) 出現(xiàn)異彻澈В回滾事務
7) 最后關閉資源
package cn.itcast.jdbc;
import cn.itcast.util.JdbsUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class JdbcDemo06 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstat1 = null;
PreparedStatement pstat2 = null;
try {
conn = JdbsUtils.getConnection();
//開啟事務
conn.setAutoCommit(false);
String sql1 = "update shuzhi set num = num-? where id = ?";
String sql2 = "update shuzhi set num = num+? where id = ?";
pstat1 = conn.prepareStatement(sql1);
pstat2 = conn.prepareStatement(sql2);
pstat1.setInt(1,500);//表示sql1第1個問號所代表得數(shù)值
pstat1.setInt(2,1);//表示sql2第2個問號所代表得數(shù)值
pstat2.setInt(1,500);
pstat2.setInt(2,4);
pstat1.executeUpdate();
pstat2.executeUpdate();
//提交事務
conn.commit();
} catch (Exception e) {
try {
//事務回滾
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
}finally {
JdbsUtils.close(pstat1,conn);
JdbsUtils.close(pstat2,conn);
}
}
}
***詳解各個對象:
1. DriverManager:驅(qū)動管理對象
* 功能:
1. 注冊驅(qū)動:告訴程序該使用哪一個數(shù)據(jù)庫驅(qū)動jar
static void registerDriver(Driver driver) :注冊與給定的驅(qū)動程序 DriverManager 。
寫代碼使用: Class.forName("com.mysql.jdbc.Driver");
通過查看源碼發(fā)現(xiàn):在com.mysql.jdbc.Driver類中存在靜態(tài)代碼塊
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
注意:mysql5之后的驅(qū)動jar包可以省略注冊驅(qū)動的步驟铝量。
2. 獲取數(shù)據(jù)庫連接:
* 方法:static Connection getConnection(String url, String user, String password)
* 參數(shù):
* url:指定連接的路徑
* 語法:jdbc:mysql://ip地址(域名):端口號/數(shù)據(jù)庫名稱
* 例子:jdbc:mysql://localhost:3306/db3
* 細節(jié):如果連接的是本機mysql服務器倘屹,并且mysql服務默認端口是3306,則url可以簡寫為:jdbc:mysql:///數(shù)據(jù)庫名稱
* user:用戶名
* password:密碼
2. Connection:數(shù)據(jù)庫連接對象
1. 功能:
1. 獲取執(zhí)行sql 的對象
* Statement createStatement()
* PreparedStatement prepareStatement(String sql)
2. 管理事務:
* 開啟事務:setAutoCommit(boolean autoCommit) :調(diào)用該方法設置參數(shù)為false慢叨,即開啟事務
* 提交事務:commit()
* 回滾事務:rollback()
3. Statement:執(zhí)行sql的對象
1. 執(zhí)行sql
1. boolean execute(String sql) :可以執(zhí)行任意的sql 了解
2. int executeUpdate(String sql) :執(zhí)行DML(insert纽匙、update、delete)語句拍谐、DDL(create烛缔,alter、drop)語句
* 返回值:影響的行數(shù)轩拨,可以通過這個影響的行數(shù)判斷DML語句是否執(zhí)行成功 返回值>0的則執(zhí)行成功践瓷,反之,則失敗亡蓉。
3. ResultSet executeQuery(String sql) :執(zhí)行DQL(select)語句