• 实现JDBC简单封装


    实现JDBC简单封装

    JDBCUtil类可以较方便地执行常用的DQL、DML、DLL语句。

    package base.jdbc.util;
    
    import java.io.FileInputStream;
    import java.sql.*;
    import java.util.HashMap;
    import java.util.LinkedHashMap;
    import java.util.LinkedList;
    import java.util.Properties;
    
    /**
     * @author QX
     * JDBC简易封装类
     */
    public class JDBCUtil {
        private String[] queryFields = null;  // 所有的字段
        private  Connection connection = null; // 数据库连接对象
        private static String url = null;
        private static String user = null;
        private static String password = null;
    
        /**
         *
         * @param queryFields 设置待查询的字段
         */
        public void setQueryFields(String[] queryFields) {
            this.queryFields = queryFields;
    
        }
    
        static {
            try {
                Properties properties = new Properties();
                properties.load(new FileInputStream("src\db.properties"));
                String driver = properties.getProperty("driver");
                user = properties.getProperty("user");
                password = properties.getProperty("password");
                url = properties.getProperty("url");
                Class.forName(driver);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        JDBCUtil(String[] queryFields) throws SQLException {
            this.queryFields = queryFields;
            this.connection = DriverManager.getConnection(url, user, password);
        }
    
        private PreparedStatement getPreStatement(String sql, Object... params) {
            int cnt = 0;
            for (int i = 0; i < sql.length(); i++) {
                if (sql.charAt(i) == '?') {
                    cnt++;
                }
            }
            if (cnt != params.length || params.length > this.queryFields.length) {
                return null;
            }
    
            PreparedStatement preStatement = null; // 预编译sql执行对象
            try {
                preStatement = this.connection.prepareStatement(sql);
                for (int i = 1; i <= cnt; i++) {
                    preStatement.setObject(i, params[i - 1]);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return preStatement;
        }
    
        /**
         *
         * @param sql 待执行的sql语句
         * @param params ?对应的参数
         * @return  更新数据的总数
         * @throws SQLException SQL执行异常
         */
        public int update(String sql, Object... params) throws SQLException {
            PreparedStatement preStatement = getPreStatement(sql, params);
            assert preStatement != null;
            int ret = preStatement.executeUpdate();
            release(preStatement, null);
            return ret;
        }
    
    
        /**
         *
         * @param sql 待执行的sql语句
         * @param params ?对应的参数
         * @return 查询的结果
         * @throws SQLException SQL执行异常
         */
        public LinkedList<HashMap<String, Object>> query(String sql, Object... params) throws SQLException {
            PreparedStatement preStatement = getPreStatement(sql, params);
            assert preStatement != null;
            ResultSet resultSet = preStatement.executeQuery();
            LinkedList<HashMap<String, Object>> allRecords = new LinkedList<>();
            // LinkedHashMap为有序集合,可以保证记录的顺序,与数据库的显示一致
            while (resultSet.next()) {
                HashMap<String, Object> oneRecordMap = new LinkedHashMap<>();  // 一条记录
                for (String field : this.queryFields) {
                    Object value  = resultSet.getObject(field);
                    oneRecordMap.put(field, value);
                }
                allRecords.add(oneRecordMap);
            }
            release(preStatement, resultSet);
            return allRecords;
        }
    
        /**
         * 开启事务
         */
        public void setAutoCommit(boolean isAuto){
            try{
                if(connection != null && !connection.isClosed()){
                    connection.setAutoCommit(isAuto);
                }
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
    
        /**
         * 提交
         */
        public void commit(){
            try{
                if(connection != null && !connection.isClosed()){
                    connection.commit();
                }
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
    
        /**
         * 回滚
         */
        public void rollback(){
            try{
                if(connection != null && !connection.isClosed()){
                    connection.rollback();
                }
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
    
        /**
         * 释放资源
         */
        private void release(PreparedStatement pre, ResultSet res){
            try{
                if(pre != null){
                    pre.close();
                }
                if(res != null){
                    res.close();
                }
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
    
        /**
         * 关闭连接
         */
        public void close() {
            try {
                if (connection != null && !connection.isClosed()) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    

    这里为什么要用PreparedStatement,而不是Statement,有两个原因:

    • 提高性能

      • 它可以使用占位符?,是预编译的,批处理比Statement效率高
    • 可防止SQL注入攻击

      • 所谓SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。例如登录时执行这样一条sql语句:select * from t_login where username='xx' and password='xx' or 1=1,无论用户名和密码是什么,后面的1=1始终成立,从而获取所有用户的账号密码

    测试类

    package base.jdbc.util;
    
    import org.junit.Test;
    
    import java.util.HashMap;
    import java.util.LinkedList;
    
    public class UtilTest {
        @Test
        public void queryTest() {
            JDBCUtil demo = null;
            try {
                demo = new JDBCUtil(new String[]{"id", "name", "age", "sex", "money", "dpt_id", "phone", "update_time"});
                demo.setAutoCommit(false);
                demo.setQueryFields(new String[]{"id", "name", "age", "sex", "money", "dpt_id"}); // 设置要查询的字段
                String sql = "select * from user where id < ? and sex = ?";
                LinkedList<HashMap<String, Object>> result = demo.query(sql, 7, "男");
                for (var oneRecordMap : result) {
                    System.out.println(oneRecordMap);
                }
                demo.commit();
            } catch (Exception e) {
                demo.rollback(); 
                e.printStackTrace();
            }finally {
                demo.close();
            }
        }
        @Test
        public void updateTest() {
            JDBCUtil demo = null;
            try {
                demo = new JDBCUtil(new String[]{"id", "name", "age", "sex", "money", "dpt_id", "phone", "update_time"});
                demo.setAutoCommit(false);
                String sql = "update user set dpt_id = ?, money = ?";
                System.out.println(demo.update(sql, 2, 50.8));
                demo.commit();  
            } catch (Exception e) {
                demo.rollback();
                e.printStackTrace();
            }finally {
                demo.close();
            }
        }
    }
    

    原数据库表为

    image-20200607101701757查询结果为:

    image-20200607095535649

    更新结果为:

    image-20200607101904961

    money、dpt_id字段已更新。

    该类的缺点是,调用close()后,系统将回收数据库连接对象的资源,频繁地申请连接对象,将消耗资源,执行效率不高,于是便有了数据库连接池,所谓连接池,就是提前申请了多个连接池对象资源,将它们放入某个容器中,当需要时,从容器中拿出供使用,使用完后,调用封装好的close(),并不会将资源归还系统,而是再将它放回容器中(非常类似于多线程池)。使用较广泛数据库连接池的有c3p0druid(阿里开发),druid相对于c3p0使用更简单,效率更高。

  • 相关阅读:
    hdu2060
    hdu1003
    style属性
    变量与常量
    使用BIgDecimal进行浮点数的精确计算
    CSUST 玩游戏 题解(思维+优先队列维护第k大)
    百度之星 迷失 题解(矩阵快速幂+分层图)
    CSUST 简单数学题 题解(质因子分解+并查集)
    CSUST 神秘群岛 题解(LCA)
    CSUST lh的简单图论 题解(图转树LCA问题)
  • 原文地址:https://www.cnblogs.com/main404/p/13056552.html
Copyright © 2020-2023  润新知