JDBC连接数据库和基于反射封装的DBUtils

JDBC操作数据库步骤

JDBC操作数据库通常分为六个通用步骤(例子为mysql数据库的连接):

  1. 加载驱动(JDBC4之后可以省略,需要导入相关数据库的驱动包)
  2. 获取连接
  3. 获取执行sql命令的对象
  4. 执行
  5. 处理结果
  6. 关闭资源

execute方法详解

Statement接口主要用于执行sql语句对象,内部包含一些执行方法:

  • execute():用执行所有的sql语句,对于有结果集的sql会返回true,否则返回false
  • executeUpdate():用于执行DML语句中的更新语句(insert,delete,update),返回结果为影响的数据行数
  • executeQuery():用于执行查询语句(select),返回一个ResultSet(结果集)对象,内部存储的为查询的数据

Statement & PreparedStatement

Statement是由JDBC接口提供的一个用于执行静态SQL语句的接口,但是通过Statement执行SQL语句时,会存在SQL注入的风险,因此JDBC还提供了另一个接口PreparedStatement,用于解决这一问题,使用PreparedStatement对象可以对sql语句预编译,从而防止sql注入。
准备属性文件

DBUtils的封装

以mysql为例。为了不用修改java源代码,可以将连接数据库的常见字符串直接配置到properties文件中:

jdbc.properties

    #mysql connection config
    driverClass=com.mysql.jdbc.Driver
    url=jdbc:mysql://127.0.0.1:3306/mydb
    user=root
    password=123456
    
    #mssqlserver connection config
    #driverClass=com.miscrosoft.jdbc.sqlserver.SQLServerDriver
    #url=jdbc:sqlserver://127.0.0.1:1433;databaseName=test
    #user=sa
    #password=123456
    
    #oracle connection config
    #driverClass=oracle.jdbc.driver.OracleDriver
    #url=jdbc:oracle:thin:@127.0.0.1:1521:orcl
    #user=scott
    #password=tiger

封装DBUtils

    import java.io.*;
    import java.sql*;
    import java.util.*;
    
    /**
     * 自己封装的数据库工具类,包含一些操作数据库的简便方法
     * 1. 获取连接
     * 2. 关闭资源
     * 3. 封装通用增删改操作
     * @author mrchai
     */
    public class DBUtils {
    
        public static String driverClass;
        public static String url;
        public static String user;
        public static String password;
    
    
        static{
            try {
                Properties prop = new Properties();
                //加载属性文件
                prop.load(new FileInputStream("src/jdbc.properties"));
                //获取属性信息(连接数据库的相关字符串)
                driverClass = prop.getProperty("driverClass");
                url = prop.getProperty("url");
                user = prop.getProperty("user");
                password = prop.getProperty("password");
    
                //加载驱动
                Class.forName(driverClass);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    
        /**
    	 * 获取连接
    	 * @return
    	 */
        public static Connection getConn(){
            try {
                return DriverManager.getConnection(url, user, password);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        /**
    	 * 关闭资源
    	 * @param rs
    	 * @param stat
    	 * @param conn
    	 */
        public static void close(ResultSet rs,Statement stat,Connection conn){
            try {
                if(rs != null){
                    rs.close();
                }
                if(stat != null){
                    stat.close();
                }
                if(conn != null){
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    
        /**
    	 * 封装通用的增、删、改操作(针对任何数据库表的更新操作(DML语句)都能通过该方法实现)
    	 * @param sql
    	 * @return
    	 */
        public static int exeUpdate(String sql,Object... params){
            Connection conn = null;
            PreparedStatement ps = null;
            try {
                //获取连接
                conn = getConn();
                //编译sql语句获取预处理对象
                ps = conn.prepareStatement(sql);
                if(Objects.nonNull(params)){				
                    for(int i = 0;i<params.length;i++){
                        ps.setObject(i + 1, params[i]); 
                    }
                }
                //执行更新
                int i = ps.executeUpdate();
                return i;
            } catch (SQLException e) {
                e.printStackTrace();
            }finally{
                close(null, ps, conn); 
            }
            return 0;
        }
    }

反射

反射是java中类的一种自省机制,通过反射可以在运行时获取类中的成分,并且使用,从而提高了java的动态性;java中任何一个类都有一个对应的java.lang.Class对象,这个对象包含了类中的所有成分(属性,构造器,方法,注解等),获取类的Class对象有三种方式:

  1. Class.forName(“类路径”) Class clz = class.forName(“com.softeem.entity.Emp”)
  2. 类名称.class Class clz = Emp.class
  3. 对象引用.getClass() Class clz = emp.getClass()

基于反射实现对象拷贝

public class ObjectCopy {

    public static <T> T clone(Object source,Class<T> t){
        T target = null;
        try {
            //获取源对象的Class对象
            Class clz = source.getClass();
            //创建新对象(无数据)
            target = t.newInstance();

            //获取源对象中的所有属性列表
            Field[] fields = clz.getDeclaredFields();
            for (Field f : fields) {
                //获取属性名
                String fname = f.getName();//ename
                //获取源对象的所有get方法,并执行,将其返回值通过调用目标对象的set方法,设置给目标对象 ename  setEname
                //获取当前属性的setter/getter方法名
                String setMethodName = "set"+fname.substring(0,1).toUpperCase()+fname.substring(1);//setEname
                String getMethodName = "get"+fname.substring(0,1).toUpperCase()+fname.substring(1);//setEname

                //获取方法对象
                Method setMethod = clz.getMethod(setMethodName, f.getType());
                Method getMethod = clz.getMethod(getMethodName);

                //调用源对象的getter获取返回值 getName() getDno()
                Object returnValue = getMethod.invoke(source);
                //调用目标对象的setter方法设置值
                setMethod.invoke(target, returnValue);
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        //返回产生的新对象
        return target;
    }

    public static void main(String[] args) {
        Account a = new Account(1, "测试1", new BigDecimal(3500));
        Emp e = new Emp(1, "测试2", new BigDecimal("4500"), new Date(), 10);

        Account obj = clone(a,Account.class);
        System.out.println(obj);

        Emp obj2 = clone(e,Emp.class);
        System.out.println(obj2);
    }
}

基于反射封装DBUtils

/**
	 * 封装通用的查询集合操作,对于任何形式的查询,都能返回一个对象集合
	 * @param t  需要返回的数据类型(泛型)
	 * @param sql 目标查询语句
	 * @param params 执行查询所需的参数
	 * @return 返回包含指定对象的集合
	 */
public static <T> List<T> queryList(Class<T> t,String sql,Object... params){
    //声明空集合
    List<T> data = new ArrayList<>();
    //获取查询结果信息
    List<Map<String,Object>> list = getDataPair(sql, params);
    if(list.isEmpty()){
        return data;
    }
    //遍历集合
    for (Map<String, Object> map : list) {
        T obj = parseMapToBean(map,t);
        data.add(obj);
    }
    return data;
}

/**
	 * 封装通用查询对象操作,对于任何形式的查询,都能返回一个确定的对象
	 * @param t  需要返回的数据类型(泛型)
	 * @param sql 目标查询语句
	 * @param params 执行查询所需的参数
	 * @return 返回指定对象
	 */
public static <T> T queryOne(Class<T> t,String sql,Object... params){
    List<Map<String,Object>> list = getDataPair(sql, params);
    if(!list.isEmpty()){
        Map<String,Object> map = list.get(0);
        T obj = parseMapToBean(map,t);
        return obj;
    }
    return null;
}

/**
	 * 将一个Map集合对象转换为一个JavaBean并返回
	 * @param map
	 * @param t
	 * @return
	 */
private static <T> T parseMapToBean(Map<String, Object> map, Class<T> t) {
    T obj = null;
    try {
        //创建一个空实例
        obj = t.newInstance();
        //获取map集合的键集(所有列名称,即要返回对象的属性名)
        Set<String> keys = map.keySet();
        for (String cname : keys) {
            //获取属性对象
            Field f = t.getDeclaredField(cname);
            //获取set方法的名称
            String setMethodName = "set"+cname.substring(0,1).toUpperCase()+cname.substring(1);
            //获取set方法对象
            Method method = t.getMethod(setMethodName, f.getType());
            //执行方法
            method.invoke(obj, map.get(cname));
        }
    } catch (InstantiationException | IllegalAccessException e) {
        e.printStackTrace();
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
    return obj;
}

/**
	 * 解析指定查询语句,并将获取的数据(列名,列值)以集合的形式返回
	 * @param sql
	 * @param params
	 * @return
	 */
private static List<Map<String,Object>> getDataPair(String sql,Object... params){
    Connection conn = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
    //声明集合存储获取的表数据(列名,列值)
    List<Map<String,Object>> list = new ArrayList<>();
    try {
        conn = getConn();
        ps = conn.prepareStatement(sql);
        if(Objects.nonNull(params)){
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i + 1, params[i]);
            }
        }
        rs = ps.executeQuery();
        //获取结果集元数据
        ResultSetMetaData rsmd = rs.getMetaData();
        //获取列总数,获取列名称,获取标签名,获取列值,将相关数据存储到map集合
        //获取查询的总列数
        int count = rsmd.getColumnCount();
        //对结果集遍历
        while(rs.next()){
            //对结果集每遍历一次,获取一条数据(即一个map对象)
            Map<String,Object> map = new HashMap<>();
            //遍历每一列
            for (int i = 1; i <= count; i++) {
                //获取列名称
                String columnName = rsmd.getColumnName(i); 
                //获取标签名(列别名)
                //String columnLabel = rsmd.getColumnLabel(i);
                //获取列值
                Object value = rs.getObject(i);
                //当列值不为null时才将数据存入map集合
                if(Objects.nonNull(value)){						
                    //将数据存入map
                    map.put(columnName, value);
                }
            }
            //将map集合存入List
            list.add(map);
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally{
        //回收资源
        DBUtils.close(rs, ps, conn);
    }
    return list;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值