JDBC-Java語言操作資料庫
目錄
一、介紹
概念:Java DataBase Connectivity (JDBC,Java資料庫連線,即使用Java語言操作資料庫)
本質:官方(sun公司)定義的一套操作所有關係型資料庫的規則,即介面。各個資料庫廠商實現這套介面,提供資料庫驅動jar包。使用JDBC介面程式設計,真正執行的程式碼是驅動jar包中的實現類。
快速入門步驟
import java.sql.Connection; import java.sql.DriverManager; import java.sql.Statement; public class JdbcQuickStart { public static void main(String[] args) throws Exception { //1. 匯入驅動jar包【mysql-connector-java-5.1.37-bin.jar】 // * 將jar包複製到專案的libs目錄(自己建立的) //* 在該目錄上右鍵 --> Add As Library (將 jar 包加入到專案中) //2. 註冊驅動 Class.forName("com.mysql.jdbc.Driver"); //3. 獲取資料庫連線物件 Connection Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db3", "root","mysql"); //4. 定義sql(sql語句後面不要加分號) String sql = "update account set balance = 500 where id = 1"; //5. 獲取執行sql語句的物件 Statement Statement statement = conn.createStatement(); //6. 執行sql,接受返回結果 int count = statement.executeUpdate(sql); //7. 處理結果 System.out.println(count); // 1 //8. 釋放資源 statement.close(); conn.close(); } }
二、JDBC各個類詳解
2.1 DriverManager 驅動管理物件
1)註冊驅動:告訴程式該使用哪一個資料庫驅動 jar 包
static void registerDriver(Driver driver)
:向 DriverManager 註冊給定驅動程式。
寫程式碼時使用:Class.forName("com.mysql.jdbc.Driver");
。
通過檢視原始碼發現,在 com.mysql.jdbc.Driver 類中存在靜態程式碼塊:
public class Driver implements java.sql.Driver { public Driver() throws SQLException { } static { try { DriverManager.registerDriver(new Driver()); //註冊資料庫驅動 } catch (SQLException var1) { throw new RuntimeException("Can't register driver!"); } } }
注:在MySQL 5 版本後,可以省略註冊驅動的步驟,即不使用程式碼 Class.forName("com.mysql.jdbc.Driver");
,其可以自動註冊驅動。
2)獲取資料庫的連線
static Connection getConnection(String url, String user, String password)
:試圖建立到給定資料庫 URL 的連線。
-
String url:指定連線的路徑,語法
jdbc:mysql://ip地址(域名):埠號/資料庫
。
如果連線的是本機 mysql 伺服器,並且 mysql 伺服器的預設埠是 3306,則 url 可以簡化為jdbc:mysql:///資料庫
。 -
String user:使用者名稱
-
String password:密碼
2.2 Connection 資料庫連線物件
1)獲取執行 sql 的物件
Statement createStatement()
:建立一個 Statement 物件來將 SQL 語句傳送到資料庫。
PreparedStatement prepareStatement(String sql)
:建立一個 PreparedStatement 物件來將引數化的 SQL 語句傳送到資料庫。
2)管理事務
開啟事務
void setAutoCommit(boolean autoCommit)
呼叫該方法設定引數為false,即開啟事務。
提交事務
void commit()
使所有上一次提交/回滾後進行的更改成為持久更改,並釋放此 Connection 物件當前持有的所有資料庫鎖。
回滾事務
void rollback()
取消在當前事務中進行的所有更改,並釋放此 Connection 物件當前持有的所有資料庫鎖。
2.3 Statement 執行靜態 SQL 語句
用於執行【靜態 SQL 語句】並返回它所生成結果的物件。
靜態 SQL 語句:引數都是給定值。
執行 sql 的三種方法:
boolean execute(String sql) 可以執行任意的 sql,該語句可能返回多個結果。(瞭解,用的不多)
- 如果第一個結果為 ResultSet 物件,則返回 true;如果其為更新計數或者不存在任何結果,則返回 false。
int executeUpdate(String sql) 執行 DML(INSERT、UPDATE、DELETE) 語句、DDL(CREATE、ALTER、DROP)語句
- 返回值:影響的行數。可以通過影響的行數判斷,增刪改查的語句是否執行成功。返回值大於0,則執行成功。
- DDL 語句一般不用此方法,直接使用 mysql 語句執行,因為使用該語句時,一般已經連線了某一資料庫,對資料庫/表的增刪改查不方便用此語句。
ResultSet executeQuery(String sql) 執行給定的 DQL(SELECT) 語句,該語句返回單個 ResultSet 物件。
練習
練習一:account表 新增記錄【insert 語句】
package cn.itcast.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement;
// account表 新增一條記錄 insert 語句
public class JDBCDemo2 {public static void main(String[] args) { Statement stmt = null; Connection conn = null; try { //1. 註冊驅動 Class.forName("com.mysql.jdbc.Driver"); //2. 定義sql String sql = "insert into account values(null,'王五',3000)"; //3.獲取Connection物件 conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root"); //4.獲取執行sql的物件 Statement stmt = conn.createStatement(); //5.執行sql int count = stmt.executeUpdate(sql);//影響的行數 //6.處理結果 System.out.println(count); if(count > 0){ System.out.println("新增成功!"); }else{ System.out.println("新增失敗!"); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); }finally { //stmt.close(); 有可能在conn階段出現異常,stmt未被賦值,呼叫close()造成空指標異常 //7. 釋放資源 //避免空指標異常 if(stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
}
練習二:account表 修改記錄【update 語句】
package cn.itcast.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement;
// account表 修改記錄
public class JDBCDemo3 {public static void main(String[] args) { Connection conn = null; Statement stmt = null; try { //1. 註冊驅動 Class.forName("com.mysql.jdbc.Driver"); //2.獲取連線物件 conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root"); //3.定義sql String sql = "update account set balance = 1500 where id = 3"; //4.獲取執行sql物件 stmt = conn.createStatement(); //5.執行sql int count = stmt.executeUpdate(sql); //6.處理結果 System.out.println(count); if(count > 0){ System.out.println("修改成功!"); }else{ System.out.println("修改失敗"); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { //7.釋放資源 if(stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
}
練習三:account表 刪除記錄【delete 語句】
package cn.itcast.jdbc; import cn.itcast.util.JDBCUtils; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement;
// account表 刪除一條記錄
public class JDBCDemo4 {public static void main(String[] args) { Connection conn = null; Statement stmt = null; try { //1. 註冊驅動 Class.forName("com.mysql.jdbc.Driver"); //2.獲取連線物件 conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root"); //conn = JDBCUtils.getConnection("jdbc:mysql:///db3", "root", "root"); //3.定義sql String sql = "delete from account where id = 3"; //4.獲取執行sql物件 stmt = conn.createStatement(); //5.執行sql int count = stmt.executeUpdate(sql); //6.處理結果 System.out.println(count); if(count > 0){ System.out.println("刪除成功!"); }else{ System.out.println("刪除失敗"); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { //7.釋放資源 if(stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
}
執行DDL語句 update建立表
package cn.itcast.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement;
// 執行DDL語句
public class JDBCDemo5 {public static void main(String[] args) { Connection conn = null; Statement stmt = null; try { //1. 註冊驅動 Class.forName("com.mysql.jdbc.Driver"); //2.獲取連線物件 conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root"); //3.定義sql String sql = "create table student (id int , name varchar(20))"; //4.獲取執行sql物件 stmt = conn.createStatement(); //5.執行sql int count = stmt.executeUpdate(sql); //6.處理結果 System.out.println(count); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { //7.釋放資源 if(stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
}
2.4 ResultSet 結果集物件,封裝查詢的結果
游標初始指向第一行(無資料可獲取),呼叫next()函式指向下一行,不斷獲取資料。每次只能讀取一行的一列資料。
基本使用
1)boolean next() 將游標從當前位置向下移一行,並判斷當前行是否是最後一行之後(是否有資料)。如果是,返回false,說明沒有資料了。如果不是,返回true,說明有資料。
2)getXXX(引數) 獲取資料,其中XXX為根據實際情況的資料型別。
// 以 Java 程式語言中 int 的形式獲取此 ResultSet 物件的當前行中指定列的值。
int getInt(int columnIndex) // 引數代表列的編號,從 1 開始,如 getInt(1);
int getInt(String columnLabel) // 引數為列名稱,如 getInt("balance");
// 以 Java 程式語言中 String 的形式獲取此 ResultSet 物件的當前行中指定列的值。
String getNString(int columnIndex)
String getNString(String columnLabel)
3)ResultSet 結果集也是資源,使用後需要釋放。
一個基本使用示例
package cn.itcast.jdbc; import java.sql.*;
public class JDBCDemo6 {
public static void main(String[] args) { Connection conn = null; Statement stmt = null; ResultSet rs = null; try { //1. 註冊驅動 Class.forName("com.mysql.jdbc.Driver"); //2.獲取連線物件 conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root"); //3.定義sql String sql = "select * from account"; //4.獲取執行sql物件 stmt = conn.createStatement(); //5.執行sql rs = stmt.executeQuery(sql); //6.處理結果 //6.1 讓遊標向下移動一行 rs.next(); //6.2 獲取資料 int id = rs.getInt(1); String name = rs.getString("name"); double balance = rs.getDouble(3); System.out.println(id + "---" + name + "---" + balance); //6.1 讓遊標向下移動一行 rs.next(); //6.2 獲取資料 int id2 = rs.getInt(1); String name2 = rs.getString("name"); double balance2 = rs.getDouble(3); System.out.println(id2 + "---" + name2 + "---" + balance2); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { //7.釋放資源 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(); } } } }
}
存在問題:上述讀取資料,是基於已知資料庫該表中有兩條 資料,但對於未知資料集,讀取資料時要判斷資料是否存在。
使用步驟:
- 遊標向下移動一行
- 判斷是否有資料
- 獲取資料
while(rs.next()){
int id = rs.getInt(1);
String name = rs.getString("name");
double balance = rs.getDouble(3);
System.out.println(id + "---" + name + "---" + balance);
}
使用例項
emp 表結構
emp 表資料
定義一個方法,查詢 emp 表的資料,將其封裝為物件,然後裝載在集合中,返回,列印。
- 定義 Emp 類
- 定義方法 public List
findAll(){} - 實現方法
定義 Emp 類
package cn.itcast.domain;
import java.util.Date;
//封裝Emp表資料的JavaBean
public class Emp {
private int id;
private String ename;
private int job_id;
private int mgr;
private Date joindate;
private double salary;
private double bonus;
private int dept_id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public int getJob_id() {
return job_id;
}
public void setJob_id(int job_id) {
this.job_id = job_id;
}
public int getMgr() {
return mgr;
}
public void setMgr(int mgr) {
this.mgr = mgr;
}
public Date getJoindate() {
return joindate;
}
public void setJoindate(Date joindate) {
this.joindate = joindate;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public int getDept_id() {
return dept_id;
}
public void setDept_id(int dept_id) {
this.dept_id = dept_id;
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
@Override
public String toString() {
return "Emp{" +
"id=" + id +
", ename='" + ename + '\'' +
", job_id=" + job_id +
", mgr=" + mgr +
", joindate=" + joindate +
", salary=" + salary +
", bonus=" + bonus +
", dept_id=" + dept_id +
'}';
}
}
使用例項
package cn.itcast.jdbc;
import cn.itcast.domain.Emp;
import cn.itcast.util.JDBCUtils;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
//定義一個方法,查詢emp表的資料將其封裝為物件,然後裝載集合,返回。
public class JDBCDemo8 {
public static void main(String[] args) {
List<Emp> list = new JDBCDemo8().findAll();
System.out.println(list);
System.out.println(list.size());
}
public List<Emp> findAll(){
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
List<Emp> list = null;
try {
//1.註冊驅動
Class.forName("com.mysql.jdbc.Driver");
//2.獲取連線
conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root");
//3.定義sql
String sql = "select * from emp";
//4.獲取執行sql的物件
stmt = conn.createStatement();
//5.執行sql
rs = stmt.executeQuery(sql);
//6.遍歷結果集,封裝物件,裝載集合
Emp emp = null;
list = new ArrayList<Emp>();
while(rs.next()){
//獲取資料
int id = rs.getInt("id");
String ename = rs.getString("ename");
int job_id = rs.getInt("job_id");
int mgr = rs.getInt("mgr");
Date joindate = rs.getDate("joindate");
double salary = rs.getDouble("salary");
double bonus = rs.getDouble("bonus");
int dept_id = rs.getInt("dept_id");
// 建立emp物件,並賦值
emp = new Emp();
emp.setId(id);
emp.setEname(ename);
emp.setJob_id(job_id);
emp.setMgr(mgr);
emp.setJoindate(joindate);
emp.setSalary(salary);
emp.setBonus(bonus);
emp.setDept_id(dept_id);
//裝載集合
list.add(emp);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
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();
}
}
}
return list;
}
}
2.5 抽取 JDBC 工具類:JDBCUtils
目的:程式碼重複度太高(註冊驅動、釋放資源等),通過抽取工作類簡化書寫。
分析:
-
抽取註冊驅動方法
-
抽取一個方法獲得連線物件
需求:不想傳遞引數(太麻煩),不能寫死(保證工具類的通用性)
解決:配置檔案// jdbc.properties url=jdbc:mysql:///db3 user=root password=root driver=com.mysql.jdbc.Driver
-
抽取一個方法釋放資源
工具類特點:所有方法是靜態的,方便呼叫。
靜態程式碼塊:
靜態程式碼塊隨著類的載入而載入,只會執行一次。
只有靜態變數才能被靜態方法訪問,被靜態程式碼塊訪問。
靜態程式碼塊只能處理異常,不能丟擲異常。丟擲異常需要方法。
JDBC工具類 JDBCUtils
package cn.itcast.util;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
// JDBC工具類
public class JDBCUtils {
private static String url;
private static String user;
private static String password;
private static String driver;
// 檔案的讀取,只需要讀取一次即可拿到這些值。使用靜態程式碼塊
static{
//讀取資原始檔,獲取值。
try {
//1. 建立Properties集合類。
Properties pro = new Properties();
//獲取src路徑下的檔案的方式--->ClassLoader 類載入器
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
URL res = classLoader.getResource("jdbc.properties");
String path = res.getPath();
// System.out.println(path);///D:/IdeaProjects/itcast/out/production/day04_jdbc/jdbc.properties
//2. 載入檔案
pro.load(new FileReader(path));
//3. 獲取資料,賦值
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
driver = pro.getProperty("driver");
//4. 註冊驅動
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
// 獲取連線
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
// 釋放資源
public static void close(Statement stmt,Connection conn){
if( stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if( conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// 釋放資源
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();
}
}
}
}
使用示例
package cn.itcast.jdbc;
import cn.itcast.domain.Emp;
import cn.itcast.util.JDBCUtils;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
//定義一個方法,查詢emp表的資料將其封裝為物件,然後裝載集合,返回。
public class JDBCDemo8 {
public static void main(String[] args) {
List<Emp> list = new JDBCDemo8().findAll2();
System.out.println(list);
System.out.println(list.size());
}
// 演示JDBC工具類
public List<Emp> findAll2(){
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
List<Emp> list = null;
try {
//1.註冊驅動
//2.獲取連線
conn = JDBCUtils.getConnection();
//3.定義sql
String sql = "select * from emp";
//4.獲取執行sql的物件
stmt = conn.createStatement();
//5.執行sql
rs = stmt.executeQuery(sql);
//6.遍歷結果集,封裝物件,裝載集合
Emp emp = null;
list = new ArrayList<Emp>();
while(rs.next()){
//獲取資料
int id = rs.getInt("id");
String ename = rs.getString("ename");
int job_id = rs.getInt("job_id");
int mgr = rs.getInt("mgr");
Date joindate = rs.getDate("joindate");
double salary = rs.getDouble("salary");
double bonus = rs.getDouble("bonus");
int dept_id = rs.getInt("dept_id");
// 建立emp物件,並賦值
emp = new Emp();
emp.setId(id);
emp.setEname(ename);
emp.setJob_id(job_id);
emp.setMgr(mgr);
emp.setJoindate(joindate);
emp.setSalary(salary);
emp.setBonus(bonus);
emp.setDept_id(dept_id);
//裝載集合
list.add(emp);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JDBCUtils.close(rs,stmt,conn);
}
return list;
}
}
練習:
-
通過鍵盤錄入使用者名稱與密碼
-
判斷使用者是否登入成功(有一張表存放使用者與密碼)
select * from User where username="輸入的使用者名稱" and password="輸入的密碼";
如果這個 sql 查詢有結果,則成功。
-- 建立資料庫 USER 表
CREATE TABLE USER(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(32),
PASSWORD VARCHAR(32)
);
INSERT INTO USER VALUES(NULL, 'zhangsan', '123');
INSERT INTO USER VALUES(NULL, 'lisi', '234');
select * from USER;
判斷使用者是否登入成功
package cn.itcast.jdbc; import cn.itcast.util.JDBCUtils; import java.sql.*; import java.util.Scanner;
public class JDBCDemo9 {
public static void main(String[] args) { //1.鍵盤錄入,接受使用者名稱和密碼 Scanner sc = new Scanner(System.in); System.out.println("請輸入使用者名稱:"); String username = sc.nextLine(); System.out.println("請輸入密碼:"); String password = sc.nextLine(); //2.呼叫方法 boolean flag = new JDBCDemo9().login(username, password); //3.判斷結果,輸出不同語句 if(flag){ //登入成功 System.out.println("登入成功!"); }else{ System.out.println("使用者名稱或密碼錯誤!"); } } public boolean login(String username ,String password){ if(username == null || password == null){ return false; } //連線資料庫判斷是否登入成功 Connection conn = null; Statement stmt = null; ResultSet rs = null; //1.獲取連線 try { conn = JDBCUtils.getConnection(); //2.定義sql String sql = "select * from user where username = '"+username+"' and password = '"+password+"' "; System.out.println(sql); //3.獲取執行sql的物件 stmt = conn.createStatement(); //4.執行查詢 rs = stmt.executeQuery(sql); //5.判斷 return rs.next();//如果有下一行,則返回true } catch (SQLException e) { e.printStackTrace(); }finally { JDBCUtils.close(rs,stmt,conn); } return false; }
}
上述【判斷使用者是否登入成功】程式碼存在問題,由 SQL 注入問題引起。
2.6 PreparedStatement 執行 sql 的物件(功能更強大)
SQL注入問題:在拼接 sql 時,有一些 sql 的特殊關鍵字參與字串的拼接,會造成安全性問題。
在【判斷使用者是否登入成功】的練習中,隨便輸入使用者,輸入密碼:a' or 'a' = 'a
,會生成 sql 語句 select * from user where username ='fhdsjkf' and password = 'a' or 'a' = 'a'
false and false or true --> true,因此可以查詢到所有資料。
解決SQL注入問題:使用 PreparedStatement 物件。
public interface PreparedStatement extends Statement
表示預編譯的 SQL 語句的物件。
預編譯的 SQL:引數使用?作為佔位符,執行 sql 時,給?賦值。
如:PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES SET SALARY = ? WHERE ID = ?");
語句不會受傳入字串的關鍵字影響。
步驟:
- 匯入驅動jar包【mysql-connector-java-5.1.37-bin.jar】
- 註冊驅動
- 獲取資料庫連線物件 Connection
- 定義sql(sql語句後面不要加分號)
- sql的引數使用?作為佔位符。如
select * from user where username = ? and password = ?;
- sql的引數使用?作為佔位符。如
- 獲取執行sql語句的物件 PreparedStatement
PreparedStatement prepareStatement(String sql) throws SQLException
conn.prepareStatement(sql)
需要傳遞sql引數,而conn.createStatement()
無需傳參。
- 給?賦值
setXxx(引數1, 引數2)
其中,引數1表示?的位置,從1開始;引數2表示?的值。
- 執行sql,接受返回結果。
- 此時無序再傳遞 sql 語句,在 PreparedStatement 使用時已經傳遞。
- 處理結果
- 釋放資源
PreparedStatement 判斷使用者是否登入成功
package cn.itcast.jdbc;
import cn.itcast.util.JDBCUtils;
import java.sql.*;
import java.util.Scanner;public class JDBCDemo9 {
public static void main(String[] args) { //1.鍵盤錄入,接受使用者名稱和密碼 Scanner sc = new Scanner(System.in); System.out.println("請輸入使用者名稱:"); String username = sc.nextLine(); System.out.println("請輸入密碼:"); String password = sc.nextLine(); //2.呼叫方法 boolean flag = new JDBCDemo9().login2(username, password); //3.判斷結果,輸出不同語句 if(flag){ //登入成功 System.out.println("登入成功!"); }else{ System.out.println("使用者名稱或密碼錯誤!"); } } // 登入方法,使用PreparedStatement實現 public boolean login2(String username ,String password){ if(username == null || password == null){ return false; } //連線資料庫判斷是否登入成功 Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; //1.獲取連線 try { conn = JDBCUtils.getConnection(); //2.定義sql String sql = "select * from user where username = ? and password = ?"; //3.獲取執行sql的物件 pstmt = conn.prepareStatement(sql); //給?賦值 pstmt.setString(1,username); pstmt.setString(2,password); //4.執行查詢,不需要傳遞sql rs = pstmt.executeQuery(); //5.判斷 return rs.next();//如果有下一行,則返回true } catch (SQLException e) { e.printStackTrace(); }finally { JDBCUtils.close(rs,pstmt,conn); } return false; }
}
注意:後期都會使用PreparedStatement來完成增刪改查的所有操作。
- 可以放置 SQL 注入
- 效率更高
三、JDBC管理事務
銀行轉賬案例
展示程式碼
package cn.itcast.jdbc; import cn.itcast.util.JDBCUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException;
// 事務操作
public class JDBCDemo10 {public static void main(String[] args) { Connection conn = null; PreparedStatement pstmt1 = null; PreparedStatement pstmt2 = null; try { //1.獲取連線 conn = JDBCUtils.getConnection(); //開啟事務 conn.setAutoCommit(false); //2.定義sql //2.1 張三 - 500 String sql1 = "update account set balance = balance - ? where id = ?"; //2.2 李四 + 500 String sql2 = "update account set balance = balance + ? where id = ?"; //3.獲取執行sql物件 pstmt1 = conn.prepareStatement(sql1); pstmt2 = conn.prepareStatement(sql2); //4. 設定引數 pstmt1.setDouble(1,500); pstmt1.setInt(2,1); pstmt2.setDouble(1,500); pstmt2.setInt(2,2); //5.執行sql pstmt1.executeUpdate(); // 手動製造異常 int i = 3/0; pstmt2.executeUpdate(); //提交事務 conn.commit(); } catch (Exception e) { //事務回滾 try { if(conn != null) { conn.rollback(); } } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); }finally { JDBCUtils.close(pstmt1,conn); JDBCUtils.close(pstmt2,null); } }
}