zoukankan      html  css  js  c++  java
  • Java使用反射封装一个方便操作数据库的类

    刚开始学JavaWeb时,我是调用N个setter方法将从数据库中查询出的数据封装成JavaBean的,极其繁琐。

    后来了解SpringJDBC后,发现它提供的接口非常简单,然后就想自己封装一个简单的用。

    原理很简单,就是使用反射代替手动调用 setter 方法,JavaBean中的属性名要和数据库查询语句中的字段名相同,一一对应。

    数据库配置文件(config.properities)格式为:

            db.url = xxx

            db.dbname = xxx

            db.user = xxx

            db.password = xxx

    代码:

    package Utils;
    
    import java.io.IOException;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Properties;
    
    /**
     * 使用示例:
     *    (三个方法都有可能返回null,返回null则表示数据库操作异常)
     *     1. 查询符号指定条件的记录数
     *           // 必须写成 as count
     *           int count = DBUtils.queryForCount("select count(1) as count from users where age = ?", age);
     *
     *     2. 查询出封装好的对象
     *          查询出的字段要和欲封装成的对象的属性名一一对应,且需要包含setter方法,不需要加构造函数
     *          class User {
     *              private String name;
     *              private int age;
     *              public void setName(String name) { this.name = name; }
     *              public String getName() { return this.name; }
     *              public void setAge(int age) { this.age = age; }
     *              public int getAge() { return this.age; }
     *          }
     *          // 查询出一条记录并封装成对象,传入User.class,如果要查询出Product对象,则传入Product.class
     *          User user = DBUtils.queryForObject("select name, age from users where id = ?", User.class, id);
     *          // 查询出多条记录并封装成对象
     *          List<User> users = DBUtils.queryForList("select name, age from users where id < ?", User.class, id);
     *
     *     3. 增删改
     *         // 删除
     *         int changedCount = DBUtils.update("delete from users where id = ?", id);
     *         // 插入
     *         int changedCount = DBUtils.update("insert into users(name, age) values(?, ?)", name, age);
     *         // 修改
     *         int changedCount = DBUtils.update("update user set age = ? where id = ?", newAge, id);
     *
     *     4. 事务
     *         (多个update操作共同协同工作时使用事务)
     *         DBUtils.startTransaction(); // 开启事务
     *         if (DBUtils.update(xxx) == null) {
     *             DBUtils.rollback();
     *             return false; // 失败,返回
     *         }
     *         if (DBUtils.update(xxx) == null) {
     *             DBUtils.rollback();
     *             return false; // 失败,返回
     *         }
     *         DBUtils.commit(); // 成功,提交事务
     *         return true;
     */
    public class DBUtils {
        /**
         * 线程作用域内,并发安全,可复用
         */
        private final static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
    
        /**
         * 获取数据库链接对象
         * @return 数据库连接对象
         */
        private static Connection getConnection() {
            if (threadLocal.get() == null) {
                Properties properties = new Properties();
                try {
                    properties.load(DBUtils.class.getResourceAsStream("config.properties"));
                    Connection conn = DriverManager.getConnection(
                            properties.getProperty("db.url") + "/" + properties.getProperty("db.dbname"),
                            properties.getProperty("db.user"),
                            properties.getProperty("db.password")
                    );
                    threadLocal.set(conn);
                } catch (SQLException e) {
                    System.out.println("【连接数据库时出现异常:" + e.getMessage() + "】");
                } catch (IOException e) {
                    System.out.println("【打开配置文件 config.properties 时出现异常:" + e.getMessage() + "】");
                }
            }
            return threadLocal.get();
        }
    
    
        /**
         * 关闭数据库连接
         */
        public static void closeConnection() {
            if (threadLocal.get() != null) {
                try {
                    threadLocal.get().close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            threadLocal.remove();
        }
    
    
        /**
         * 查询多条数据并封装成对应的实例
         * @param sql  返回多条记录数的查询语句
         * @param requireType  要封装成的类的Class对象
         * @param params  要绑定到SQL语句上的参数
         * @param <T>  要封装成的类的类型
         * @return  返回封装好的对象列表
         */
        public static <T> List<T> queryForList(String sql, Class<T> requireType, Object... params) {
            List<T> ret = new ArrayList<>();
            Connection conn = getConnection();
            PreparedStatement ps = null;
            if (conn == null)
                return null;
            try {
                ps = conn.prepareStatement(sql);
                for (int i = 0; i < params.length; i++) { // 绑定参数
                    ps.setObject(i + 1, params[i]);
                }
                ResultSet result = ps.executeQuery();
                while (result.next()) {
                    ret.add(requireType.getConstructor().newInstance()); // 创建一个实例
                    Field[] fields = requireType.getDeclaredFields(); // 获取所有属性
                    for (Field field : fields) {
                        // 构造 setter 方法名
                        String setterName = "set" + Character.toUpperCase(field.getName().charAt(0)) + field.getName().substring(1);
                        // 调用对应实例的 setter 方法给它设置属性
                        Method setter = requireType.getMethod(setterName, field.getType());
                        setter.invoke(ret.get(ret.size() - 1), result.getObject(field.getName()));
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 仅需关闭 PreparedStatement,关闭它时 ResultSet 会自动关闭
                try {
                    if (ps != null)
                        ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            return ret;
        }
    
    
        /**
         * 查询出一条数据并封装成对象
         * @param sql  返回一条记录数的查询语句
         * @param requireType  要封装成的类的Class对象
         * @param params  要绑定到SQL语句上的参数
         * @param <T>  要封装成的类的类型
         * @return  返回封装好的对象
         */
        public static <T> T queryForObject(String sql, Class<T> requireType, Object... params) {
            List<T> list = queryForList(sql, requireType, params);
            return list == null ? null : list.get(0);
        }
    
    
        /**
         * 查询符合指定条件的记录数
         * @param sql  查询记录数的SQL语句
         * @param params  要绑定到SQL语句上的参数
         * @return  返回符合条件的记录数
         */
        public static Long queryForCount(String sql, Object... params) {
            class Count {
                private Long count;
                public Count() {}
                public void setCount(Long count) {
                    this.count = count;
                }
                public Long getCount() {
                    return this.count;
                }
            }
            Count count = queryForObject(sql, Count.class, params);
            return count.getCount();
        }
    
    
        /**
         * 执行增删除操作
         * @param sql  DML SQL语句
         * @param params  要绑定到SQL语句上的参数
         * @return  影响的数据库记录数目
         */
        public static Integer update(String sql, Object... params) {
            Connection conn = getConnection();
            PreparedStatement ps = null;
            Integer rowChanged = null;
            try {
                ps = conn.prepareStatement(sql);
                for (int i = 0; i < params.length; i++) { // 绑定参数
                    ps.setObject(i + 1, params[i]);
                }
                rowChanged = ps.executeUpdate();
            } catch (SQLException e) {
                e.printStackTrace();
                return null;
            } finally {
                try {
                    if (ps != null)
                        ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            return rowChanged;
        }
    
    
        /**
         * 开启事务
         */
        public static void startTransaction() {
            try {
                getConnection().setAutoCommit(false);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    
    
        /**
         * 回滚事务
         */
        public static void rollback() {
            try {
                getConnection().rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    getConnection().setAutoCommit(true);
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    
    
        /**
         * 提交事务
         */
        public static void commit() {
            try {
                getConnection().commit();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    getConnection().setAutoCommit(true);
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

      

  • 相关阅读:
    PHP中逻辑运算符and/or与||/&&的一个坑
    PHP usort 使用用户自定义的比较函数对数组中的值进行排序
    php编写TCP服务端和客户端程序
    Redis系列-php怎么通过redis扩展使用redis
    国内镜像源收集
    双通道内存技术简介
    收集些日本的VPS
    建站相关关键词快速普及
    bash 的漏洞,你们中招了吗?
    戴维·卡梅伦(David William Donald Cameron)经典语录
  • 原文地址:https://www.cnblogs.com/yuanyb/p/12003621.html
Copyright © 2011-2022 走看看