JavaWeb(篇第二週)之JDBC

JDBC

一、引言


1.1 如何操作數據

使用客戶端工具訪問數據庫,需要手工建立鏈接,輸入用戶名和密碼登陸,編寫SQL語句,點擊執行,查看操作結果(結果集或受影響行數)。

1.2實際開發中,會採用客戶端操作數據庫嗎?

在實際開發過程中,當用戶的數據發生改變時,不會通過客戶端操作執行SQL語句,因爲操作量過大,無法保證效率和正確性。

二、JDBC (JAVA DATABASE CONNECTIVITY)


2.1 什麼是JDBC?

JDBC(Java DataBase Connectivity) JAVA 連接數據庫,可以使用Java語言連接數據庫完成CRUD操作

2.2 JDBC核心思想

JAVA 中定義了訪問數據庫的而接口,可以爲多種關係型數據庫提供了統一的訪問方式

由數據庫廠商提供數據庫驅動實現類(Driver驅動)

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-sz7KqPgm-1585619491326)(C:\Users\fanhu\AppData\Roaming\Typora\typora-user-images\1585381106311.png)]

2.2.1 MySQL 數據庫驅動
  • mysql-connector-java-5.1.x 適用於5.x版本
  • mysql-connector-java-8.0.x 適用於8.x 版本
2.2.2 JDBC API

JDBC 是由多個接口和類進行功能實現

類型 全限定名 簡介
class java.sql.DriverManage 管理多個數據庫驅動類,提供了獲取數據庫連接的方法
interface java.sql.Connection 代表一個數據庫連接(當Connection不是NULL時,標識已連接一個數據)
interface java.sql.Statement 發送SQL語句到數據庫的工具
interface java.sql.ResultSet 保存SQL查詢語句的結果數據(結果集)
class java.sql.SQLException 處理數據庫應用程序時所發生的異常
2.3 環境搭建

1.在項目中創建一個lib文件夾用於存放jar文件

2.將jar包放輸入lib文件夾下

3.將lib文件夾作爲library

三、JDBC開發步驟[重點]


3.1 註冊驅動

使用Class.forName(“com.mysql.jdbc.Driver”)手動加載字節碼文件到JVM中

Class.forName("com.mysql.jdbc.Driver");
3.2 連接數據庫
  • 通過DriverManager.getConnection(url,user,password) 獲得數據庫連接對象
    • URL:jdbc:mysql://主機名(ip):端口號/數據庫名
    • user:用戶名
    • password:密碼
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/database?useUnicode=true&characterEncoding=utf8","root","123");
3.3 獲取發送SQL的對象

通過Connection對象獲得Statement對象,用於對數據庫進行通用訪問的

Statement statement = connection.createStatement();
3.4執行SQL語句

編寫SQL語句,並執行,接收執行後的數據

int result = statement.executeUpdate("update stu set student_name='李敢敢',sex='女' where
student_id = 'S1003'");
3.5處理結果

接收並處理操作結果

if(result > 0){
	System.out.println("執行成功");
}
3.6釋放資源

遵循的是先開後關的原則,釋放過程中用到的資源連接

statement.close()
connection.close()
3.7綜合案例

綜合六步:實現增刪改

public class BasicJDBC {
    public static void main(String[] args) {
        try {
            // 註冊驅動
            Class.forName("com.mysql.jdbc.Driver");
            // 連接數據庫
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/companydb?useUnicode=true&characterEncoding=utf-8","root","root");
            // 獲取發送SQL對象
            Statement statement = connection.createStatement();
            // 編寫SQL語句,執行SQL語句(返回受影響行數)
            String sql = "";
            int i = statement.executeUpdate(sql);
            //處理數據
            if(i>0){
                System.out.println("執行成功");
            }
            //釋放資源
            statement.close();
            connection.close();
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }
}

四、ResultSet(結果集)

在執行查詢SQL後,存放查詢到的查詢結果集數據

4.1接收結果集

ResultSet rs = statement.executeQuery(sql)

Result rs =statement.executeQuery("");
4.2 遍歷ResultSet中的數據

ResultSet以表(Table)結構進行臨時結果的存儲,需要通過JDBC API將其中的數據進行依此獲取

  • 數據行指針:初始位置在第一行數據前,沒調用依此boolean next()方法,ResultSet中指針向下移動一行,結果true,表示當前行有數據
  • rs.getXxx(“列名”); 根據列名獲得數
  • rs.getXxx(“整數下標”);根據列的編號舒徐獲得!從1開始
boolean next() throws SQLException;//判斷rs結果集中下一行是否有數據
4.2.1遍歷方法
int getInt(int columnIndex) throws SQLException;// 獲取當前行的第N列的int值
int getInt(String columnLabel) throws SQLException;//獲得當前行column
4.3綜合案例

對stu表所有數據進行遍歷

4.3.1根據列的名稱進行遍歷

public class TestDql {
    public static void main(String[] args) {
        try {
            //1.註冊驅動
            Class.forName("com.mysql.jdbc.Driver");
            //2.獲得連接
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/companyDB?useUnicode=true&characterEncoding=utf-8","root","lixiaoning12144014");
            //3.獲得SQL執行對象
            Statement statement = connection.createStatement();
            //4.執行SQL語句
            String sql = "select * from `Student`";
            ResultSet resultSet = statement.executeQuery(sql);
            //5.對結果集進行處理
            while(resultSet.next()){ // 判斷結果集中是否有下一行!
                // 根據列名獲取當前行的每一列數據
                String id= (String)resultSet.getObject("student_id");
                String name = (String)resultSet.getObject("student_name");
                String sex = (String)resultSet.getObject("sex");
                Date borndate = resultSet.getDate("borndate");
                String phone = (String)resultSet.getObject("phone");
                Integer gradeid = (Integer)resultSet.getObject("GradeId");
                System.out.println(id+"\t"+name+"\t"+sex+"\t"+borndate.toString()+"\t"+phone+"\t"+gradeid);
            }
            //6.釋放資源
            resultSet.close();
            statement.close();
            connection.close();
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }
}
4.3.2根據列的編號獲取
public class BasicJDBC {
    public static void main(String[] args) {
        try {
            // 註冊驅動
            Class.forName("com.mysql.jdbc.Driver");
            // 連接數據庫
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/companydb?useUnicode=true&characterEncoding=utf-8","root","lixiaoning12144014");
            // 獲取發送SQL對象
            Statement statement = connection.createStatement();
            // 編寫SQL語句,執行SQL語句(返回受影響行數)
            String sql = "";
            int i = statement.executeUpdate(sql);
            //處理數據
            if(i>0){
                System.out.println("執行成功");
            }
            //釋放資源
            statement.close();
            connection.close();
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }
}

五、常見的錯誤

  • java.lang.ClassNotFoundException 找不到類 或者 沒有導入jar包
  • com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:Unkonen colum ‘列名’ 與SQL語句相關的錯誤(表名 列名 書寫錯誤 、約束錯誤、插入的值是String類型,但是沒有加單引號)
  • com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:Duplicate entry ‘S1003’ for key ‘PRIMARY’ 原因:主鍵值已經存在!更改要插入的主鍵值
  • com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:Unknown column ‘password’ in
    • 可能輸入的值的類型不對,確定插入元素時,對應的值的類型是否爭取

六、綜合案例登陸


6.1創建表
  • 創建一張用戶表User
    • id:主鍵 自增長
    • username 字符串類型 非空
    • password 字符串類型 非空
    • phone 字符串類型 11爲
  • 插入兩條數據
6.2實現登錄
  • 通過控制檯,用戶輸入用戶名和密碼
  • 用戶輸入的用戶名和密碼作爲參數,編寫SQL語句
  • 如果查詢到用戶,則用戶存在,提示登陸成功,反之,提示失敗

七、SQL注入問題

7.1什麼是SQL注入

當用戶輸入的數據中有SQL關鍵字或語法時,並且參與了SQL語法的編譯,導致SQL語句編譯後條件結果爲true時

7.2 如何避免SQL注入

由於編寫的SQL語句,是在用戶輸入數據後,整合後再編譯成SQL語句。所以爲了避免SQL注入的問題,使得SQL語句再用戶輸入數據前,SQL語句已經完成編譯,成爲了完整的SQL語句,在進行填充數據。

八、PreparedStatement[重點]

PreparedStatement接口繼承了Statement接口,執行SQL語句的方法沒有區別!

8.1 PreparedStatement 的應用

作用:1.預編譯SQL語句,效率高!

​ 2.安全,可以避免SQL注入

​ 3.可以動態的填充數據,執行多個同構的SQL語句

8.1.1參數標記
//1.預編譯SQL語句
PreparedStatement pstms = connection.prepareStatement(sql);
8.1.2 動態參數綁定

pstmt.setXxx(下標,值); 參數下標是從1開始,爲指定佔位符下標綁定值

//2.爲佔位符下標賦值
pstm.setString(1,username)
pstm.setString(2,password)

九、綜合練習


9.1創建數據庫、表

數據庫 Account

  • 創建一張表Account,有以下列
    • cardId:字符串,主鍵
    • password:字符串,非空
    • username,字符串,非空
    • balance:小數,非空
    • phone:字符串,非空
9.2.創建項目通過JDBC實現功能

創建AccountSystem類,完成下列功能

  • 開戶:控制檯輸入所有的賬戶信息,使用PreparedStatement添加至t_account表
  • 存款:控制檯輸入卡號、密碼、存儲金額進行修改
  • 取款:輸入卡號、密碼、取款金額
  • 轉賬:輸入卡號、密碼、對方卡號、轉賬金額進行修改
  • 修改密碼:控制檯輸入卡號、密碼、在輸入新密碼進行修改
  • 註銷:控制檯輸入卡號、密碼,刪除對應的賬戶信息
創建表
CREATE DATABASE if not exists Account CHARACTER SET utf8;
USE Account;
CREATE TABLE t_account(
	`cardId` VARCHAR(20) PRIMARY KEY not null,
	`password` varchar(20) not null,
	`balance` DOUBLE NOT NULL,
	`phone` varchar(11)
	)charset=utf8;
	
	try-catch  ctrl+alt+t
	代碼格式化  ctrl+alt+L
	快速定位異常處: F2
package com.qfedu.jdbc.t4;

import java.sql.*;
import java.util.Scanner;

public class AccountSystem {
    Scanner scanner = new Scanner(System.in);
    private static Connection connection = null;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;
    static {
        // 1.註冊驅動
        try {
            Class.forName("com.mysql.jdbc.Driver");
            // 2.創建數據庫連接
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/Account?useUnicode=true&characterEncoding=utf-8","root","lixiaoning12144014");
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }
    // 開戶
    public void regiter(){
        System.out.println("請輸入卡號:");
        String cardId = scanner.next();
        System.out.println("請輸入密碼");
        String password = scanner.next();
        System.out.println("請輸入用戶名");
        String username = scanner.next();
        System.out.println("請輸入存款金額");
        String balance = scanner.next();
        System.out.println("請輸入預留手機號碼:");
        String phone = scanner.next();
        try {
           //3.創建Preparement
            String sql ="insert into `t_account`(`cardId`,`password`,`username`,`balance`,`phone`) values(?,?,?,?,?)";
            preparedStatement = connection.prepareStatement(sql);
            //4.爲佔位符賦值
            preparedStatement.setString(1,cardId);
            preparedStatement.setString(2,password);
            preparedStatement.setString(3,username);
            preparedStatement.setString(4,balance);
            preparedStatement.setString(5,phone);
            //5.執行SQL語句
            int i = preparedStatement.executeUpdate();
            if(i>0){
                System.out.println("開戶成功");

            }else{
                System.out.println("開戶失敗");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
                try {
                    if(preparedStatement!=null){
                        preparedStatement.close();
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
        }
    }
    // 更新
    public void saveMoney(){
        System.out.println("請輸入卡號:");
        String cardId = scanner.next();
        System.out.println("請輸入密碼:");
        String pasword = scanner.next();
        System.out.println("請輸入存款金額");
        double money = scanner.nextDouble();
        if(money > 0){
        //存款操作
            String sql = "update t_account set balance = balance + ? where cardId=? and password=?";
            try {
                preparedStatement = connection.prepareStatement(sql);
                preparedStatement.setDouble(1,money);
                preparedStatement.setString(2,cardId);
                preparedStatement.setString(3,pasword);
                // 執行,接收返回結果
                int i = preparedStatement.executeUpdate();
                if(i>0){
                    System.out.println("存款成功");
                }else{
                    System.out.println("存款失敗!用戶名和密碼請覈對!");
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                if(preparedStatement!=null){
                    try {
                        preparedStatement.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
        }else{
            System.out.println("您輸入的金額不正確");
        }
    }
    // 取款
    public void takeMoney(){
        System.out.println("請輸入卡號:");
        String cardId = scanner.next();
        System.out.println("請輸入密碼:");
        String password = scanner.next();
        System.out.println("請輸入取款金額");
        double money = scanner.nextDouble();
        if(money > 0){
            String sql = "select balance from t_account where cardId=? and password=?";
            try {
                preparedStatement =connection.prepareStatement(sql);
                preparedStatement.setString(1,cardId);
                preparedStatement.setString(2,password);
                resultSet = preparedStatement.executeQuery();
                if(resultSet.next()){
                    double balance = resultSet.getDouble(1);
                    if(money<=balance){
                        //取款成功
                        String sql2="update t_account set balance = balance-? where cardId=? and password=?";
                        preparedStatement = connection.prepareStatement(sql2);
                        preparedStatement.setDouble(1,money);
                        preparedStatement.setString(2,cardId);
                        preparedStatement.setString(3,password);
                        int i = preparedStatement.executeUpdate();
                        if(i>0){
                            System.out.println("取款成功!");
                        }else{
                            System.out.println("取款失敗!");
                        }
                    }else{
                        System.out.println("餘額不足!");
                    }
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                if(resultSet!=null){
                    try {
                        resultSet.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }

                }
                if(preparedStatement!=null){
                    try {
                        preparedStatement.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }

                }
            }
        }else{
            System.out.println("輸入金額有誤!");
        }
    }
    // 轉賬
    public void transferAccountS() {
        System.out.println("請輸入轉賬方卡號:");
        String cardId = scanner.next();
        System.out.println("請輸入轉賬方密碼:");
        String pasword = scanner.next();
        System.out.println("請輸入轉賬金額");
        double money = scanner.nextDouble();
        System.out.println("請輸入接收方卡號:");
        String cardId2 = scanner.next();
        // 確定轉賬金額大於0
        if(money > 0){
            // 查詢轉賬方是否存在
            String sql =  "select balance from t_account where password=? and cardId=?";
            try {
                preparedStatement = connection.prepareStatement(sql);
                preparedStatement.setString(1,pasword);
                preparedStatement.setString(2,cardId);
                resultSet = preparedStatement.executeQuery();
                if(resultSet.next()){
                    // 賬號密碼存在
                    double aDouble = resultSet.getDouble(1);
                    // 判斷轉賬金額是否小於銀行卡金額
                    connection.setAutoCommit(false);
                    if(aDouble >= money){
                        // 關閉事務的自動提交
                        // 減錢
                        String sql2="update t_account set balance = balance-? where password=? and cardId=?";
                        preparedStatement = connection.prepareStatement(sql2);
                        preparedStatement.setDouble(1,money);
                        preparedStatement.setString(2,pasword);
                        preparedStatement.setString(3,cardId);
                        int num1 = preparedStatement.executeUpdate();
                        // 加錢
                        String sql3="update t_account set balance = balance+? where cardId=?";
                        preparedStatement = connection.prepareStatement(sql3);
                        preparedStatement.setDouble(1,money);
                        preparedStatement.setString(2,cardId2);
                        int num2 = preparedStatement.executeUpdate();
                        if(num1>0 && num2>0){
                            System.out.println("轉賬成功!");
                        }else {
                            System.out.println("轉賬失敗");
                        }
                        connection.commit();
                    }else{
                        System.out.println("餘額不足");
                    }
                }else{
                    System.out.println("賬號或密碼不存在");
                }
            } catch (SQLException e) {
                try {
                    if(connection!=null){
                        connection.rollback();
                    }
                } catch (SQLException ex) {
                    ex.printStackTrace();
                }
                e.printStackTrace();
            }finally {
                if(resultSet!=null){
                    try {
                        resultSet.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
                try {
                    connection.setAutoCommit(true);
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                if(preparedStatement!=null){
                    try {
                        preparedStatement.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
            // 轉賬金額是否小於卡內餘額
            //
        }else{
            System.out.println("轉賬金額輸入有誤");
        }

    }
    // 關閉Connection
    public void closeConnection(){
        if(connection!=null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    // 修改密碼
    public void changePassword() {
        System.out.println("請輸入卡號:");
        String cardId = scanner.next();
        System.out.println("請輸入密碼:");
        String password = scanner.next();

        String sql = "select * from t_account where cardId=? and password=?";
        try {
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,cardId);
            preparedStatement.setString(2,password);
            ResultSet resultSet = preparedStatement.executeQuery();
            if(resultSet.next()){
                System.out.println("用戶名密碼正確");
                System.out.println("請輸入新密碼:");
                String newPassword = scanner.next();
                System.out.println("請再次輸入新密碼:");
                String newRewardPassword = scanner.next();
                if(newPassword.equals(newRewardPassword)){
                    String sql1 ="update t_account set password=? where cardId=?";
                    preparedStatement = connection.prepareStatement(sql1);
                    preparedStatement.setString(1,newRewardPassword);
                    preparedStatement.setString(2,cardId);
                    int i = preparedStatement.executeUpdate();
                    if(i>0){
                        System.out.println("修改成功");
                    }else{
                        System.out.println("修改失敗");
                    }
                }else{
                    System.out.println("兩次密碼輸入不一致,修改失敗!");
                }
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {

            if(resultSet!=null){
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                if(preparedStatement!=null){
                    try {
                        preparedStatement.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

    }
    // 註銷
    public void writeOff() {
        System.out.println("請輸入卡號:");
        String cardId = scanner.next();
        System.out.println("請輸入密碼:");
        String password = scanner.next();
        String sql = "select * from t_account where cardId=? and password=?";
        try {
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,cardId);
            preparedStatement.setString(2,password);
            boolean execute = preparedStatement.execute();
            if(execute){
                System.out.println("是否一定要註銷此賬號? 1.是 2.否");
                int result = scanner.nextInt();
                if(result==1){
                 // 確認註銷
                    String sql1 ="delete from t_account where cardId=?";
                    preparedStatement =connection.prepareStatement(sql1);
                    preparedStatement.setString(1,cardId);
                    int i = preparedStatement.executeUpdate();
                    if(i>0){
                        System.out.println("銷戶成功!");
                    }else{
                        System.out.println("銷戶失敗!");
                    }

                }

            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(preparedStatement!=null){
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(resultSet!=null){
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}




package com.qfedu.jdbc.t4;

import java.util.Scanner;

public class TestAccount {
    public static void main(String[] args) {
        AccountSystem as = new AccountSystem();
        Scanner in  = new Scanner(System.in);
        System.out.println("歡迎進入此係統");
        int choice = 0;
        do{
            System.out.println("1、開戶 2、存款 3、取款 4、轉賬 5、修改密碼 6、註銷 0、退出");
            System.out.println("請選擇");
            choice = in.nextInt();
            switch (choice){
                // 開戶
                case 1:
                    as.regiter();
                    break;
                // 存款
                case 2:
                    as.saveMoney();
                    break;
                // 取款
                case 3:
                    as.takeMoney();
                    break;
                // 轉賬
                case 4:
                    as.transferAccountS();
                    break;
                // 修改密碼
                case 5:
                    as.changePassword();
                    break;
                // 註銷
                case 6:
                    as.writeOff();
                    break;
                case 0: as.closeConnection();return;
                default:
                    System.out.println("暫無此功能");
                    return;
            }
        }while(choice!=0);
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章