文章目錄
1、JDBC連接數據的步驟
- 加載驅動
- 根據URL、用戶名和密碼建立連接
- 創建處理快,有靜態處理快(Statement)和預處理塊(PreparedStatement)
- 執行數據庫語句
- 處理得到的結果
- 釋放資源
2、連接
2.1、準備工作
-
導入驅動包
-
構建路徑 build path
-
測試用戶是否正確登錄
2.2、建立連接
- 連接字符串
- 加載驅動: oracle.jdbc.driver.OracleDriver
- URL:jdbc:oracle:thin:@db 服務器地址:端口:實例
- 連接URL:jdbc:oracle:thin:@localhost:1521:orcl
- 用戶名和密碼:SCOTT TIGER
- 編寫測試類
- 加載驅動
- 建立連接:Connection con =DriverManager.getConnection(“jdbc:oracle:thin:@locahost:1521:orcl”,“scott”,“tiger”)
3、處理塊
3.1、靜態處理塊
Statement 是 Java 執行數據庫操作的一個重要接口,用於在已經建立數據庫連接的基礎上,向數據庫發送要執行的 SQL 語句。Statement 對象,用於執行不帶參數的簡單 SQL 語句。 執行靜態 SQL 語句並返回它所生成結果的對象。
特點:
- 處理 不變的靜態的 sql 語句
- 優點: 直接查看sql ,方便處理錯誤
- 缺點:性能不高、拼接 sql 麻煩、可能存在 sql 注入
方法的使用:
- 增刪改使用executeUpdate( )函數,返回一個int值,表示影響的行數。
- 查詢使用executeQurey()函數,返回一個ResultSet對象,該對象中封裝着查詢的信息
- ResultSet對象必須先試用
.next()
函數判斷是否有值,才能使用getInt/getString/getBoolean等方法獲取到值(可以簡單的使用getObject()方法獲取到任意類型的數據),如果不使用.next()
函數判斷是否有值就直接獲取值,則會出現java.sql.SQLException: 未調用 ResultSet.next異常。
- ResultSet對象必須先試用
代碼:
/*
* JDBC基本流程:
* 1.加載驅動 (選擇哪一個數據庫)
* 2.獲取連接 (與數據庫連接上)
* 3.準備sql
* 4.獲取處理塊(打包發送)
* 5.接收結果集
* 6.處理結果數據
* 7.關閉
*/
public class Demo01JDBC {
public static void main(String[] args) throws Exception {
//1.加載驅動 (選擇哪一個數據庫)
Class.forName("oracle.jdbc.OracleDriver");
//2.獲取連接 (與數據庫連接上)
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "SCOTT", "TIGER");
//3.準備sql
String sql = "select * from dept";
//4.獲取處理塊(打包發送)
Statement sta = conn.createStatement();
//5.接收結果集
ResultSet result = sta.executeQuery(sql);
//6.處理結果數據
while(result.next()){
int deptno = result.getInt("deptno");
String dname = result.getString("dname");
String loc = result.getString("loc");
System.out.println(deptno+"--->:"+dname+"--->"+loc);
}
//7.關閉資源
result.close();
sta.close();
conn.close();
}
}
注意:
- 釋放資源時,先打開的後關閉。
**優化:**可以將加載數據庫驅動和獲取數據庫連接的操作放在靜態代碼塊中,類只需要加載一次即可,不需要重複加載。
public class Demo02JDBC {
// 聲明連接數據庫的對象
public static Connection conn;
static{
// 加載數據庫
try {
Class.forName("oracle.jdbc.OracleDriver");
// 和數據庫建立連接
conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "SCOTT", "TIGER");
// 準備sql語句
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args)throws Exception {
// 準備sql語句
String sql = "select * from dept where deptno=10";
// 獲取處理塊
Statement sta = conn.createStatement();
// 執行sql語句
ResultSet result = sta.executeQuery(sql);
// 處理數據
while(result.next()){
int deptno = result.getInt(1);
String dname = result.getString(2);
String loc = result.getString(3);
System.out.println(deptno+"--->"+dname+"--->"+loc);
}
//7.關閉資源
result.close();
sta.close();
conn.close();
}
}
3.2、預處理塊
PreparedStatement 接口繼承了 Statement,並與之在兩方面有所不同:有人主張,在 JDBC 應用中,如果你已經是稍有水平開發者,你就應該始終以PreparedStatement 代替 Statement.也就是說,在任何時候都不要使用 Statement。
由於 PreparedStatement 對象已預編譯過,所以其執行速度要快於 Statement 對象。因此,多次執行的 SQL 語句經常創建爲 PreparedStatement 對象,以提高效率。
特點:
- 處理 不變的靜態的 sql 語句 |可變的 sql 語句 帶 ? 的 sql
- 優點:性能高,方便編寫sql 不存在sql注入 安全
- 缺點:不能直接打印sql語句 不方便處理錯誤
例如要查詢的sql語句爲:select * from users where name=? and pwd=?,要查詢的內容使用?做佔位符。
使用的方法:
- 設置值:爲sql語句中的?設置值**setInt(字段名|字段的序號)/setString()/setBolean()等設置響應的值,也可以簡單的使用setObject(字段名|字段的序號)**設置任意類型的值。
- 獲取值:從獲取到的結果集中拿數據,使用函數getInt(字段名|字段的序號)/getSting()/getBoolean(),也可以簡單的使用**getObject(字段名|字段的序號)**獲取任意類型的值。
- 序號是從1開始的。
代碼:
/**
* 使用預處理塊查詢數據庫的數據
*
*/
public class Demo05 {
public static void main(String[] args) throws Exception{
// 加載數據庫驅動
Class.forName("oracle.jdbc.OracleDriver");
// 獲取數據庫的連接
Connection conn =DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "SCOTT", "TIGER");
// 準備sql語句(根據用戶名和密碼查詢用戶信息)
String sql = "select * from users where name=? and pwd=?";
// 獲取預處理塊,對查詢數據的sql語句進行預編譯
PreparedStatement ps = conn.prepareStatement(sql);
// 爲sql語句設置值
ps.setObject(1, "張萬里");
ps.setObject(2, "1314");
// 執行sql語句
ResultSet result = ps.executeQuery();
// 處理獲取到的數據
while(result.next()){
System.out.println("id"+"\tname"+"\tpwd"+"\tbirthday");
System.out.println(result.getObject(1)+"\t"+result.getObject(2)+"\t"+result.getObject(3)+"\t"+result.getObject(4));
}
}
}
3.3、使用db.properties配置文件
db.properties的配置文件
driver=oracle.jdbc.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:xe
uname=SCOTT
pwd=TIGER
使用配置文件獲取數據庫的連接:
/**
* 數據庫工具類,獲取數據庫的Connection連接對象
*/
public class DBUtil {
// 獲取資源配置文件對象
private static Properties p = null;
static{
p = new Properties();
try {
// 獲取配置文件
p.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
} catch (IOException e) {
System.out.println("加載配置文件失敗");
e.printStackTrace();
}
try {
// 加載數據庫
Class.forName(p.getProperty("driver"));
} catch (ClassNotFoundException e) {
System.out.println("加載數據庫失敗");
e.printStackTrace();
}
}
/**
* 獲取數據庫的連接
*/
public static Connection getConnection() throws SQLException{
Connection conn = null;
conn = DriverManager.getConnection(p.getProperty("url"), p.getProperty("uname"), p.getProperty("pwd"));
return conn;
}
3.3.1、模擬註冊賬戶
使用上述的工具類
/**
* 註冊
*/
public static boolean login(){
Scanner sc = new Scanner(System.in);
System.out.print("用戶名:");
String name = sc.next();
System.out.print("密碼:");
String pwd = sc.next();
Connection conn = null;
try {
// 獲取數據庫的連接
conn = DBUtil.getConnection();
} catch (SQLException e) {
System.out.println("連接數據庫失敗");
e.printStackTrace();
}
boolean flag = true;
// 循環檢測要註冊的賬戶是否存在
while(flag){
if(check(name, pwd,conn)){
System.out.println("該用戶已經存在,請重輸入!");
System.out.print("用戶名:");
name = sc.next();
System.out.print("密碼:");
pwd = sc.next();
}else{
flag = false;
}
}
// 準備sql語句
String sql2 = "insert into users values(quecreate_users_id.nextval,?,?)";
PreparedStatement ps = null;
// 操作數據庫影響的行數
int rows = 0;
try {
ps = conn.prepareStatement(sql2);
ps.setObject(1, name);
ps.setObject(2, pwd);
// 返回影響的行數
rows = ps.executeUpdate();
} catch (SQLException e) {
System.out.println("向數據庫插入數據異常");
e.printStackTrace();
}finally{
// 關閉資源(自己封裝的方法)
DBUtil.close(ps, conn);
}
// 更改標誌位
if(rows>0){
System.out.println("註冊成功");
return true;
}else{
System.out.println("註冊失敗");
return false;
}
}
3.3.2、模擬登錄賬戶
/**
* 登錄
*/
public static void enter(){
if(user!=null){
System.out.println("不要重複登錄!");
start();
return;
}
Scanner sc = new Scanner(System.in);
System.out.print("用戶名:");
String name = sc.next();
System.out.print("密碼:");
String pwd = sc.next();
// 連接數據庫
Connection conn = null;
ResultSet result = null;
PreparedStatement sta = null;
try {
conn = DBUtil.getConnection();
boolean flag = true;
while(flag){
// 準備sql語句
String sql = "select * from users where name=? and pwd=?";
sta = conn.prepareStatement(sql);
sta.setObject(1, name);
sta.setObject(2, pwd);
// 執行sql語句
result = sta.executeQuery();
if(result.next()){
System.out.println("登錄成功");
flag = false;
}else{
System.out.println("用戶名或密碼錯誤,請重新輸入完成登錄");
System.out.print("用戶名:");
name = sc.next();
System.out.print("密碼:");
pwd = sc.next();
}
}
} catch (SQLException e) {
System.out.println("登錄異常");
e.printStackTrace();
}finally {
DBUtil.close(result, sta, conn);
}
user = new User(name,pwd);
start();
}
3.3.3、模擬修改密碼
/**
* 修改密碼
*/
public static void modify(){
if(user == null){
System.out.println("登錄後才能修改數據");
start();
return;
}
Scanner sc = new Scanner(System.in);
// 檢測兩次輸入的密碼
boolean flag = true;
String newpwd = null;
while(flag){
System.out.print("新密碼:");
newpwd = sc.next();
System.out.println("請再次輸入新密碼:");
String againPwd = sc.next();
if(!newpwd.equals(againPwd)){
System.out.println("兩次密碼不一致,請重新輸入");
}else{
flag = false;
}
}
Connection conn = null;
PreparedStatement sta = null;
// 執行sql影響的記錄數
int rows = 0;
try {
// 獲取數據庫的連接
conn = DBUtil.getConnection();
// 準備sql語句
String sql = "update users set pwd=? where name=?";
sta = conn.prepareStatement(sql);
sta.setObject(1, newpwd);
sta.setObject(2, user.getName());
// 執行sql語句
rows = sta.executeUpdate();
} catch (SQLException e) {
System.out.println("操作數據庫失敗");
e.printStackTrace();
}
// 判斷時是否修改成功
if(rows > 0){
System.out.println("修改密碼成功!");
user = null;
start();
}
}
3.3.4、模擬註銷用戶
/**
* 註銷用戶
*/
public static void delete(){
if(user == null){
System.out.println("請先登錄!");
start();
}
Connection conn = null;
PreparedStatement sta = null;
// 數據庫操作影響的行
int rows =0;
try {
// 連接數據庫
conn = DBUtil.getConnection();
// 準備sql語句
String sql = "delete from users where name=? and pwd=?";
sta = conn.prepareStatement(sql);
// 設置參數
sta.setObject(1, user.getName());
sta.setObject(2, user.getPwd());
// 執行刪除操作
rows = sta.executeUpdate();
} catch (SQLException e) {
System.out.println("註銷用戶異常");
e.printStackTrace();
}finally {
DBUtil.close(sta, conn);
}
// 判斷是否刪除數據成功
if(rows > 0){
System.out.println("註銷賬戶成功!");
user = null;
start();
return;
}
}
4、事務問題
當涉及到事務問題時可以使用的方法有:
- 使用**conn.setAutoCommit(false)**方法設置手動提交事務
- 使用方法**conn.commit()**提交事務
- 使用方法**conn.rollback()**回滾事務。
模擬轉賬:
/**
* 模擬轉賬
*/
public static void change(){
Connection conn = null;
PreparedStatement sta = null;
try {
// 獲取數據庫的連接
conn = DBUtil.getConnection();
// 設置手動提交
conn.setAutoCommit(false);
// 準備sql語句
String sql1 = "update emp set sal = 2000 where empno = 7369";
sta = conn.prepareStatement(sql1);
int rows1 = sta.executeUpdate();
// 準備sql語句
String sql2 = "update emp set sal = 10000 where empno = 7839";
sta = conn.prepareStatement(sql2);
int rows2 = sta.executeUpdate();
if(rows1 > 0 && rows2 > 0){
// 提交事務
conn.commit();
System.out.println("修改工資成功");
}else{
// 事務回滾
conn.rollback();
System.out.println("修改工資失敗");
}
} catch (SQLException e) {
System.out.println("修改工資異常");
e.printStackTrace();
}finally{
// 關閉資源
DBUtil.close(sta, conn);
}
}