02.SSM框架集~再談JDBC?

02.SSM框架集~再談JDBC?

本文是上一篇文章的後續,詳情點擊該鏈接~

jar包

提取碼:1asg

JDBC:

       JDBC(Java DataBase Connectivity, Java數據庫連接) ,是一種用於執行SQL語句的Java API,爲多種關係數據庫提供統一訪問,它由一組用Java語言編寫的類和接口組成。有了JDBC,程序員只需用JDBC API寫一個程序,就可訪問所有數據庫。

       SUN公司是規範制定者,制定了規範JDBC(連接數據庫規範)

       DriverManager類

              作用:管理各種不同的JDBC驅動

       Connection接口

       Statement接口和PreparedStatement接口

       ResultSet接口

       數據庫廠商微軟、甲骨文等分別提供實現JDBC接口的驅動jar包 程序員學習JDBC規範來應用這些jar包裏的類。

JDBC訪問數據庫的步驟:

       加載一個Driver驅動

       創建數據庫連接(Connection)

       創建SQL命令發送器Statement

       通過Statement發送SQL命令並得到結果

       處理結果(select語句)

       關閉數據庫資源ResultSet Statement Connection

加載Driver驅動

       使用反射加載驅動,其實就是獲得一個類的字節碼,在獲得類的字節碼的過程中,一定會加載類進入內存,一旦進入內存會執行代碼中的靜態代碼塊,一執行代碼塊,就會自動的向DriverManager中註冊一個驅動

 static {
          try {
              DriverManager.registerDriver(new Driver());
          } catch (SQLException var1) {
              throw new RuntimeException("Can't register driver!");
          }
     }

        mysql8 之前的數據庫驅動名 com.mysql.jdbc.Driver

        mysql8 開始的數據庫驅動 com.mysql.cj.jdbc.Driver

通過DriverManager獲得鏈接

        url                             同一資源定位符

       協議                            jdbc:mysql:

        ip地址                       127.0.0.1/localhost

        url                             同一資源定位符

        端口號                      3306

        具體的資源路徑       mydb

        mysql8之前:             jdbc:mysql://127.0.0.1:3306/mydb

        mysql8開始:             jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai

       useSSL=false            不使用SSL加密機制

       &useUnicode=true     使用unicode字符集

       &characterEncoding=utf8       使用utf8作爲通信字符集

       &serverTimezone=Asia/Shanghai       確定時區爲 Asia/Shanghai

       其中的mydb指的是數據庫名,可以根據需求修改

使用JDBC完成添加操作

public static void insert(){

        Connection connection = null;
        Statement statement = null;
        try {
            //1:加載一個Driver驅動
            Class.forName("com.mysql.cj.jdbc.Driver");
            //2:創建數據庫連接(Connection)
            String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
            String uid = "root";    //賬號
            String pwd = "root";    //密碼

            connection = DriverManager.getConnection(url,uid,pwd);
            //創建SQL命令發送器
            statement = connection.createStatement();
            // 向數據庫發送語句 數據庫執行完畢後 返回參數
            int n = statement.executeUpdate("insert into student values('689845','黃貴根','656972','信息工程學院',666)");

            if(n > 0){
                System.out.println("數據添加成功!");
            }else{
                System.out.println("數據添加失敗!");
            }

        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }finally{
            //關閉處理
            if(connection != null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

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

       從上述代碼中不難發現,僅僅只是實現添加這麼一個操作,就需要如此多的代碼,細想,如果要寫多個增刪改的操作,難道每次都要寫這麼多行的代碼嘛?

       所以一般到了這個時候,我們就需要一個工具類,來簡化。

編寫DBUtil工具類

public class DBUtil {
    
    //數據庫的連接的靜態方法
    public static Connection getConnection(){
        String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
        String uid = "root";    //賬號
        String pwd = "root";    //密碼
        Connection connection = null;
        Statement statement = null;
        //1:加載一個Driver驅動
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            connection = DriverManager.getConnection(url,uid,pwd);
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
    //關閉處理
    public static void CloseAll(Connection connection, Statement statement, ResultSet resultSet){
        //關閉處理
        if(connection != null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

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

這個時候我們只需要直接調用,就可以省略很多的代碼

public static void insert(){
        Connection connection = null;
        Statement statement = null;
        try {
            connection = DBUtil.getConnection();
            //創建SQL命令發送器
            statement = connection.createStatement();
            // 向數據庫發送語句 數據庫執行完畢後 返回參數
            int n = statement.executeUpdate("insert into student values('689845','黃貴根','656972','信息工程學院',666)");

            if(n > 0){
                System.out.println("數據添加成功!");
            }else{
                System.out.println("數據添加失敗!");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            DBUtil.CloseAll(connection,statement,null);
        }
    }

       這樣子添加看似好像沒問題,而且也已經很簡化了,可是再想想,假如我要換一個表,或者說我不想添加操作了,我要修改或者刪除。怎麼辦?重複寫不麻煩嘛?所以這個時候,我們就需要擴展一下DBUtil工具類了

擴展DBUtil

public static int executeUpdate(String sql,Object [] params) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        int n = 0;//添加失敗
        try {
            //2.建立和數據庫的連接
            conn = getConnection();
            //3.創建一個SQL命令發送器

            pstmt = conn.prepareStatement(sql);
            //4.準備好SQL語句,通過SQL命令發送器發送給數據庫,並得到結果
            for (int i = 0; i <params.length ; i++) {
                pstmt.setObject(i+1, params[i]);
            }
            n = pstmt.executeUpdate();
            //System.out.println(n);

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //6.關閉資源
            CloseAll(conn,pstmt,null);
        }
        return n;
    }

       這個時候我們再添加數據,實際上只需要三行代碼就可以實現了,即使是換了個數據庫表或者其他操作,也無需重複寫代碼

public static void InsertPlus(){
        //三行代碼即可完成
        String sql = "insert into student value(?,?,?,?,?)";
        Object []objects = {"689845","黃貴根","656972","信息工程學院",666.0};
        int n = DBUtil.executeUpdate(sql,objects);

        if(n > 0){
            System.out.println("數據添加成功!");
        }else{
            System.out.println("數據添加失敗!");
        }
    }

刪除行不行呢?試試唄~

		String sql = "delete from student where realname = ?";
        Object []objects = {"黃貴根"};
        int n = DBUtil.executeUpdate(sql,objects);

JDBC常見異常

       Exception in thread "main"java.lang.ClassNotFoundException: com.mysql.jdbc2.Driver

       原因:沒有添加jar包或者com.mysql.jdbc2.Driver路徑錯誤

       Exception in thread "main" java.sql.SQLException: No suitable driver found for jbdc:mysql://127.0.0.1:3306/stumgr

       url錯誤

       Exception in thread "main" java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES)

       原因:用戶名或者密碼錯誤

       Exception in thread "main" com.mysql.jdbc.exceptions .jdbc4.MySQLIntegrityConstraintViolationException:Duplicate entry '90' for key 'PRIMARY'

       原因:主鍵衝突

使用JDBC完成查詢操作

需求:查詢所有信息工程學院的學生
創建學生實體類(get set就不寫在文章裏面了,自行添加。):
public class Student {
    private String son;			//學號
    private String realname;	//姓名
    private String password;	//密碼
    private String classname;	//院系
    private Double score;		//總成績
    }
查詢操作
    public static List<Student> FindAll(){
        Connection connection = DBUtil.getConnection();
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        //創建List集合來接收數據
        List<Student> list = new ArrayList<>();
        try {
            preparedStatement = connection.prepareStatement("select * from student where classname = ?");
            //1表示第一個佔位符,也就是?。 而不是數據庫裏面的第幾個字段
            preparedStatement.setString(1,"信息工程學院");
            //接收結果
            resultSet = preparedStatement.executeQuery();
            while(resultSet.next()){
                //後面對應的是數據庫裏面的字段名
                String son = resultSet.getString("son");
                String realname = resultSet.getString("realname");
                String password = resultSet.getString("password");
                String classname = resultSet.getString("classname");
                Double score = resultSet.getDouble("score");
                //存到實體類
                Student student = new Student(son,realname,password,classname,score);
                //存到集合
                list.add(student);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return list;
    }

測試

public static void main(String[] args) {
        //測試
        List<Student> list = FindAll();
        Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

       這個時候我們發現,每個數據庫裏面的字段,都要定義一個相應的變量來接收,這麼做很不方便。怎麼辦呢?那我們就來擴展一下DBUtil工具類吧。

擴展DBUtil工具類

public static <T> List<T> baseQuery(T t, String sql, Object ... args){
        // 獲取list集合中要裝的對象的字節碼
        Class aClass = t.getClass();
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet set = null;
        List<T> list = null;
        try {
            connection = DBUtil.getConnection();
            statement = connection.prepareStatement(sql);
            // 設置參數的過程
            for (int i = 0; i < args.length; i++) {
                statement.setObject(i + 1, args[i]);
            }
            set = statement.executeQuery();
            // 獲取全部的字段
            Field[] fs = aClass.getDeclaredFields();
            // 先設置屬性可以訪問
            for(Field f:fs){
                f.setAccessible(true);
            }
            list=new ArrayList<>();
            while(set.next()){
                // 創建對象
                T  element = (T)aClass.newInstance();
                // 從結果集的一條數據中取出每個字段的信息,放入element對象上去
                // 遍歷fs 通過屬性名 去結果集中獲取數據
                for(Field f:fs){
                    String name = f.getName();
                    Object value=null;
                    // 判斷實體類屬性的數據類型,選擇對應的get方法
                    if(f.getType()==int.class){
                        value = set.getInt(name);
                    }else if(f.getType()==double.class){
                        value = set.getDouble(name);
                    }else if(f.getType()==boolean.class){
                        value = set.getBoolean(name);
                    }else{
                        value= set.getObject(name);
                    }
                    f.set(element,value);
                }
                list.add(element);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            CloseAll(connection,statement,set);
        }
        return list;
    }

       有了這個工具類之後,我們幾乎只需要一行代碼,就可以兼容多種查詢的操作方法

測試:

public static void FindAllPlus(){
        //查詢所有信息工程學院的學生
        String sql = "select * from student where classname = ?";
        //這個時候幾乎一行代碼就可以完成操作
        List<Student> list = DBUtil.baseQuery(new Student(),sql,"信息工程學院");

        Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

       怎麼樣?是不是簡化好多了~

最終代碼

DBUtil工具類

public class DBUtil {

    //數據庫的連接的靜態方法
    public static Connection getConnection(){
        String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
        String uid = "root";    //賬號
        String pwd = "root";    //密碼
        Connection connection = null;
        Statement statement = null;
        //1:加載一個Driver驅動
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            connection = DriverManager.getConnection(url,uid,pwd);
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
    //關閉處理
    public static void CloseAll(Connection connection, Statement statement, ResultSet resultSet){
        //關閉處理
        if(connection != null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

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

    public static int executeUpdate(String sql,Object [] params) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        int n = 0;//添加失敗
        try {
            //2.建立和數據庫的連接
            conn = getConnection();
            //3.創建一個SQL命令發送器

            pstmt = conn.prepareStatement(sql);
            //4.準備好SQL語句,通過SQL命令發送器發送給數據庫,並得到結果
            for (int i = 0; i <params.length ; i++) {
                pstmt.setObject(i+1, params[i]);
            }
            n = pstmt.executeUpdate();
            //System.out.println(n);

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //6.關閉資源
            CloseAll(conn,pstmt,null);
        }
        return n;
    }

    public static <T> List<T> baseQuery(T t, String sql, Object ... args){
        // 獲取list集合中要裝的對象的字節碼
        Class aClass = t.getClass();
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet set = null;
        List<T> list = null;
        try {
            connection = DBUtil.getConnection();
            statement = connection.prepareStatement(sql);
            // 設置參數的過程
            for (int i = 0; i < args.length; i++) {
                statement.setObject(i + 1, args[i]);
            }
            set = statement.executeQuery();
            // 獲取全部的字段
            Field[] fs = aClass.getDeclaredFields();
            // 先設置屬性可以訪問
            for(Field f:fs){
                f.setAccessible(true);
            }
            list=new ArrayList<>();
            while(set.next()){
                // 創建對象
                T  element = (T)aClass.newInstance();
                // 從結果集的一條數據中取出每個字段的信息,放入element對象上去
                // 遍歷fs 通過屬性名 去結果集中獲取數據
                for(Field f:fs){
                    String name = f.getName();
                    Object value=null;
                    // 判斷實體類屬性的數據類型,選擇對應的get方法
                    if(f.getType()==int.class){
                        value = set.getInt(name);
                    }else if(f.getType()==double.class){
                        value = set.getDouble(name);
                    }else if(f.getType()==boolean.class){
                        value = set.getBoolean(name);
                    }else{
                        value= set.getObject(name);
                    }
                    f.set(element,value);
                }
                list.add(element);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            CloseAll(connection,statement,set);
        }
        return list;
    }
}

使用工具類完成操作

    public static List<Student> FindAllPlus(){
        //查詢所有信息工程學院的學生
        String sql = "select * from student where classname = ?";
        //這個時候幾乎一行代碼就可以完成操作
        List<Student> list = DBUtil.baseQuery(new Student(),sql,"信息工程學院");
        return list;
    }

    public static void InsertPlus(){
        //三行代碼即可完成
        String sql = "insert into student value(?,?,?,?,?)";
        Object []objects = {"689845","黃貴根","656972","信息工程學院",666.0};
        int n = DBUtil.executeUpdate(sql,objects);
    }

       然而即使如此,我們未來將還會有更優質的解決方案可以使用,這就等我們接下來學Mybatis之後就知道了。下期再見~

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