【java】对jdbc操作结果简单的映射封装

简介: 1. 对jdbc做一个简单的封装,select可以返回一个javabean对象,而不是resultset。主要用了反射。这是我之前写的代码,做了简单的修改。   实现功能:a.对数据库的基本操作 增删改查        b.

1. 对jdbc做一个简单的封装,select可以返回一个javabean对象,而不是resultset。主要用了反射。这是我之前写的代码,做了简单的修改。

  实现功能:a.对数据库的基本操作 增删改查

       b.对查询的单条记录返回一个指定类型的javabean对象,利用java反射,jdbc ResultSet类和ResultSetMetaData类

       c. 对查到的结果集返回一个List, 泛型

  数据源:用到的 数据库连接池是我自己简单实现的一个连接池:【java】简单实现数据库连接池,主要为了后续实现事务的简单实现

  用到的java知识 : 反射,泛型,jdbc

        


import
com.yeyeck.noob.ConnectionPollImpl; import com.yeyeck.noob.IConnectionPool; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.*; import java.util.ArrayList; import java.util.List; public class DBUtil { public static int excuteUpdate(String sql, Object... objects) { IConnectionPool connectionPool = ConnectionPollImpl.getInstance(); Connection connection = connectionPool.getConnection(); PreparedStatement preparedStatement = null; try { preparedStatement = getStateMent(connection, sql, objects); return preparedStatement.executeUpdate(); //执行sql并返回结果 } catch (SQLException e) { e.printStackTrace(); } finally { if (preparedStatement != null) { try { preparedStatement.close(); } catch (SQLException e) { e.printStackTrace(); } } } return 0; } /** * 查询单条记录 * * @param sql 查询语句 * @param clazz 返回对象的class * @param objects 需要的参数,必须跟sql占位符的位置一一对应 * @param <T> 泛型返回 * @return 返回单个对象 */ public static <T> T queryForObject(String sql, Class<T> clazz, Object... objects) { IConnectionPool connectionPool = ConnectionPollImpl.getInstance(); Connection connection = connectionPool.getConnection(); PreparedStatement preparedStatement = null; ResultSet resultSet = null; T object = null; try { preparedStatement = getStateMent(connection, sql, objects); resultSet = getResultSet(preparedStatement); if (resultSet.next()) { object = invokeObject(resultSet, clazz); } } catch (SQLException | IllegalAccessException | InstantiationException | NoSuchFieldException | NoSuchMethodException | InvocationTargetException e) { e.printStackTrace(); } finally { close(preparedStatement, resultSet); //记得关闭 } return object; } /** *查询多条记录 * * @param sql 查询语句 * @param clazz 返回对象的class * @param objects 需要的参数,必须跟sql占位符的位置一一对应 * @param <T> 泛型返回 * * @return list */ public static <T> List<T> queryForList(String sql, Class<T> clazz, Object... objects) { IConnectionPool connectionPool = ConnectionPollImpl.getInstance(); Connection connection = connectionPool.getConnection(); PreparedStatement preparedStatement = null; ResultSet resultSet = null; List<T> list = new ArrayList<>(); try { preparedStatement = getStateMent(connection, sql, objects); resultSet = getResultSet(preparedStatement); while (resultSet.next()) { //调用 invokeObject方法,把一条记录封装成一个对象,添加到list中 list.add(invokeObject(resultSet, clazz)); } } catch (SQLException | IllegalAccessException | InstantiationException | NoSuchFieldException | NoSuchMethodException | InvocationTargetException e) { e.printStackTrace(); } finally { close(preparedStatement, resultSet); } return list.size() > 0 ? list : null; } private static void close(PreparedStatement preparedStatement, ResultSet resultSet) { try { if(resultSet != null) { resultSet.close(); } if (preparedStatement != null) { preparedStatement.close(); } } catch (SQLException e) { e.printStackTrace(); } } /** * 把数据库中的一条记录通过反射包装成相应的Bean * @param resultSet * @param clazz * @param <T> * @return * @throws IllegalAccessException * @throws InstantiationException * @throws SQLException * @throws NoSuchFieldException * @throws NoSuchMethodException * @throws InvocationTargetException */ private static <T> T invokeObject(ResultSet resultSet, Class<T> clazz) throws IllegalAccessException, InstantiationException, SQLException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException { T object = clazz.getDeclaredConstructor().newInstance(); ResultSetMetaData metaData = resultSet.getMetaData(); for (int i = 0, count = metaData.getColumnCount(); i < count; i++) { String columnName = metaData.getColumnName(i + 1); //数据库返回结果的列名 String fieldName = StringUtil.camelName(columnName); //去掉列名中的下划线“_”并转为驼峰命名 Field field = clazz.getDeclaredField(fieldName); //根据字段名获取field String methName = setMethodName(fieldName); //拼set方法名 Class type = field.getType(); //获取字段类型 Method setMethod = clazz.getDeclaredMethod(methName, field.getType()); Object value = resultSet.getObject(i + 1); //获取字段值 setMethod.invoke(object, type.cast(value)); //强转并且赋值 } return object; } private static PreparedStatement getStateMent(Connection connection, String sql, Object... objects) throws SQLException { PreparedStatement preparedStatement = connection.prepareStatement(sql); for (int i = 0, len = objects.length; i < len; i++) { preparedStatement.setObject(i + 1, objects[i]); //给sql每个?占位符填上数据 } return preparedStatement; } private static ResultSet getResultSet(PreparedStatement statement) throws SQLException { if (statement == null) { return null; } else { return statement.executeQuery(); } } private static String setMethodName(String str) { return "set" + StringUtil.firstUpperCase(str); } }

其中用到的StringUtil的几个方法

public class StringUtil {

    /**
     * 转为驼峰命名
     * @param str
     * @return string
     */
    public static String camelName(String str) {
        if (!isEmpty(str)) {
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0, len = str.length(); i < len; i++) {
                if (str.charAt(i) == '_') {
                    while (str.charAt(i + 1) == '_') {
                        i++;
                    }
                    stringBuilder.append(("" + str.charAt(++i)).toUpperCase());
                } else {
                    stringBuilder.append(str.charAt(i));
                }
            }
            return stringBuilder.toString();
        }
        return str;
    }

    /**
     * 判断是否为空串
     *
     * @param str
     * @return
     */
    public static boolean isBlank(String str) {
        if (str != null && str.length() > 0) {
            for (int i = 0, len = str.length(); i < len; i++) {
                if (!Character.isSpaceChar(str.charAt(i))) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 判断是否为空串 ?!!! 我怎么又写了个一样的方法?!!!
     * @param str
     * @return
     */
    public static boolean isEmpty(String str) {
        return str == null || str.length() == 0;
    }


    /**
     * 将第一个字母替换为大写
     * @param str
     * @return
     */
    public static String firstUpperCase(String str) {
        return str.substring(0, 1).toUpperCase() + str.substring(1, str.length());
    }
}

测试

1.测试用到的表

 CREATE TABLE `t_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `age` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 |

初始数据

测试代码

import java.util.List;

public class DBUtilTest {

    public static void main(String[] args) {


        List<User> users1 = DBUtil.queryForList("select * from t_user", User.class);
        System.out.println(users1);

        User user = new User();
        user.setUsername("刘能");
        user.setAge(12);
        String sql1 = "insert into `t_user`(username, age) values (?, ?)";
        System.out.println("insert 语句测试返回结果:" + DBUtil.excuteUpdate(sql1, user.getUsername(), user.getAge()));
        List<User> users2 = DBUtil.queryForList("select * from t_user", User.class);
        System.out.println(users2);

        String sql2 = "delete from t_user where id = ?";
        System.out.println("delete 语句测试返回结果:" + DBUtil.excuteUpdate(sql2, 3));

        String sql3 = "update t_user set age = ? where id = ?";
        System.out.println("update 语句测试返回结果:" + DBUtil.excuteUpdate(sql3, 100, 1));

        String sql4 = "select * from t_user where id = ?";
        User user2 = DBUtil.queryForObject(sql4, User.class, 2);
        System.out.println("select 语句测试返回结果: " + user2 );
        List<User> users3 = DBUtil.queryForList("select * from t_user", User.class);
        System.out.println(users3);


    }

}

测试结果

[User{id=1, username='小明', age=100}, User{id=2, username='小红', age=15}, User{id=4, username='小二', age=12}, User{id=5, username='刘能', age=12}]
insert 语句测试返回结果:1
[User{id=1, username='小明', age=100}, User{id=2, username='小红', age=15}, User{id=4, username='小二', age=12}, User{id=5, username='刘能', age=12}, User{id=6, username='二蛋', age=99}]
delete 语句测试返回结果:1
update 语句测试返回结果:1
select 语句测试返回结果: User{id=2, username='小红', age=15}
[User{id=1, username='小明', age=20}, User{id=2, username='小红', age=15}, User{id=4, username='小二', age=12}, User{id=6, username='二蛋', age=99}]

数据库数据

 

相关文章
|
3月前
|
Java 关系型数据库 数据库连接
JDBC:Java与数据库的“黄金搭档”,为何它如此重要?
JDBC:Java与数据库的“黄金搭档”,为何它如此重要?
43 8
|
3月前
|
Java 数据库连接 API
JDBC:Java数据库连接的“黑科技”大揭秘
JDBC:Java数据库连接的“黑科技”大揭秘
36 7
|
3月前
|
SQL Java 数据库连接
为何JDBC是Java开发者的“心头好”?原因竟然这么简单!
为何JDBC是Java开发者的“心头好”?原因竟然这么简单!
37 3
|
3月前
|
算法 Java 程序员
在Java的编程世界里,多态不仅仅是一种代码层面的技术,它是思想的碰撞,是程序员对现实世界复杂性的抽象映射,是对软件设计哲学的深刻领悟。
在Java的编程世界里,多态不仅仅是一种代码层面的技术,它是思想的碰撞,是程序员对现实世界复杂性的抽象映射,是对软件设计哲学的深刻领悟。
63 9
|
2月前
|
安全 Java 编译器
Java的封装详解
封装和多态是面向对象编程(OOP)的重要概念。封装通过私有属性和公共方法实现数据隐藏和保护,使类的内部细节对外部不可见;多态则通过方法重载和重写实现同一方法在不同对象上的不同表现形式,增强了代码的灵活性和可维护性。两者结合使用,可以使Java程序更加安全、灵活且易于维护。
|
2月前
|
Java
Java的封装详解
封装是Java中实现数据隐藏和保护的核心机制。它通过将对象的状态和行为结合并限制外部直接访问,确保类的内部细节对外不可见,仅能通过公共方法访问和修改对象状态。封装带来了数据隐藏、提高代码可维护性和增强安全性等好处。在Java中,封装主要通过将属性设为私有并提供getter和setter方法来实现。这种方式不仅保护了数据完整性,还允许在修改类内部实现时不影响外部代码,从而提升程序的健壮性和可读性。
|
2月前
|
Java 编译器
封装,继承,多态【Java面向对象知识回顾①】
本文回顾了Java面向对象编程的三大特性:封装、继承和多态。封装通过将数据和方法结合在类中并隐藏实现细节来保护对象状态,继承允许新类扩展现有类的功能,而多态则允许对象在不同情况下表现出不同的行为,这些特性共同提高了代码的复用性、扩展性和灵活性。
封装,继承,多态【Java面向对象知识回顾①】
|
22天前
|
XML Java Maven
在 Cucumber 测试中自动将 Cucumber 数据表映射到 Java 对象
在 Cucumber 测试中自动将 Cucumber 数据表映射到 Java 对象
41 7
|
2月前
|
SQL Java 编译器
Java——类与对象(封装)
封装是面向对象编程中的概念,指将数据(属性)和相关操作(方法)组合成独立单元(类),使外部无法直接访问对象的内部状态,只能通过提供的方法进行交互,从而保护数据安全。例如,手机将各种组件封装起来,只暴露必要的接口供外部使用。实现封装时,使用`private`关键字修饰成员变量,并提供`get`和`set`方法进行访问和修改。此外,介绍了包的概念、导入包的方式及其注意事项,以及`static`关键字的使用,包括静态变量和方法的初始化与代码块的加载顺序。
36 10
Java——类与对象(封装)
|
2月前
|
安全 Java 数据安全/隐私保护
Java 封装怎么理解
封装是Java中的一种重要机制,它将对象的状态(数据)和行为(方法)打包在一起并控制外部访问权限,以保护数据不被随意修改。封装的主要目的包括数据保护、接口设计和增强模块性。通过使用`private`、`protected`及`public`等访问控制修饰符,结合getter和setter方法,可以有效隐藏对象内部实现细节。下面是一个简单的`BankAccount`类示例,展示了如何通过封装保护类的内部状态,确保数据安全和一致性,简化类的使用。理解封装有助于编写高质量代码和设计优秀程序架构。