JDBC代码完善

拓展

在ResultSetMetaData中存在getColumnCount()方法用来得到MySQL中的总列数,在后续中可以用getObject()有参方法直接获取到列的值,参数为列数,列数从1开始。在用Object类型存储数据时,有时还会做非空判断。演示代码如下:

            //5.statement执行sql语句,返回结果集
            ResultSet rs = preState.executeQuery();
            //通过结果集rs得到结果集元数据
            ResultSetMetaData md = rs.getMetaData();
            //获取结果集的总列数
            int columnCount = md.getColumnCount();
            //6.解析结果集rs
            while (rs.next()) {
                //根据每一行数据,封装成一个实体对象
                T t=c.newInstance();
                //1.取出某一行的每个数据,封装到对象t的属性中
                for (int i = 1; i <=columnCount ; i++) {
                    //通过列的序号获取每一列的值
                    Object value = rs.getObject(i);
                    if(value!=null){
                        //通过列的序号获取每一列的列名
                        String columnName = md.getColumnName(i);
                        //因为列名和实体类t中的属性名一致,为每一个属性构造一个反射中的set方法
                        Field f = c.getDeclaredField(columnName);
                        //赋予私有属性的赋值权限
                        f.setAccessible(true);
                        //使用反射,把value给到对象t的属性中
                        f.set(t,value);//理解为:把value赋值给对象t的columnName属性,相当于set方法
                    }
                }

反射,其实就是无参构造方法然后用set方法给到对象t的属性中,具体代码演示如下:

    public static <T> T selectRow(String sql,Class<T> c) {
        try {
            //连接MySQL代码以下省略。
            ResultSet rs = statement.executeQuery(sql);
            //通过结果集rs得到结果集元数据
            ResultSetMetaData md = rs.getMetaData();
            //获取结果集的总列数
            int columnCount = md.getColumnCount();
            //6.解析结果集rs
            // 根据每一行数据,封装成一个实体对象
            T t=null;
            if (rs.next()) {
                t=c.newInstance();
                 //1.取出某一行的每个数据,封装到对象t的属性中
                for (int i = 1; i <=columnCount ; i++) {
                    //通过列的序号获取每一列的值
                    Object value = rs.getObject(i);
                    if(value!=null){
                        //通过列的序号获取每一列的列名
                        String columnName = md.getColumnName(i);
                        //因为列名和实体类t中的属性名一致,为每一个属性构造一个反射中的set方法
                        Field f = c.getDeclaredField(columnName);
                        //赋予私有属性的赋值权限
                        f.setAccessible(true);
                        //使用反射,把value给到对象t的属性中
                        f.set(t,value);//理解为:把value赋值给对象t的columnName属性,相当于set方法
                    }
                }
                return t;
            }
            //7.关闭资源
            statement.close();
            con.close();

        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

在Java中的sql语句直接进行true和flase判断会出现逻辑错误。未完全密封的代码如下:

    @Test
    public void testLogin(){
        String username="cc' or '1'='1";//逻辑会出现错误
        String password="cc' or '1'='1";
        User user=selectRow("select * from t_users where username='"+username+"' and password='"+password+"'",User.class);
        System.out.println(user!=null?"登陆成功":"登录失败");
    }

在本代码中,原先存在的账户aa,密码为aa可以正常登录,但是用户名和密码都输入cc' or '1'='1也可以正确登入

更改后的密封代码如下:

//4.需要创建statement
            PreparedStatement preState = con.prepareStatement(sql)
//后续statement调用照常

其中

Statement 父类
PreparedStatement 子类
1.提前传入sql,执行的时候不传入sql
2.支持传入sql中的参数
3.解决sql的注入逻辑漏洞
4.提高代码执行效率

在用哪个prepareStatement方法调整语句逻辑性后,语句只可以正常登录,不会产生逻辑错误。代码如下:

    //测试登录
    @Test
    public void testLogin(){
        String username="aa";
        String password="aa";
        User user=selectRow("select * from t_users where username=? and password=?",User.class,username,password);
        System.out.println(user!=null?"登陆成功":"登录失败");
    }
Object...params 可变性参数组 :在调用函数时,可以传入任意个任意类型的参数,常用于方法中的有参构造方法,用来解决参数数量和类型不确定的情况。
@Test 在导入junit包后可以自由声明方法是否为测试方法,可以看为将方法直接作为主方法正常运行并在控制台输出结果。演示图如下:

 代码完善

在MySQL与Java的使用中,这些代码是常用的,需要熟练掌握,代码如下:

//查询多行多列
    public static <T> List<T> list(String sql,Class<T> c,Object...params) {
        //创建一个集合,包含所有对象
        List<T> tList = new ArrayList<>();
        try {
            //1.注册驱动-反射去加载jar包中com.hp.jdbc.Driver这个类中的DriverManager.registerDriver(new Driver())
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取连接对象 characterEncoding=utf8用于解决插入数据中文乱码的问题
            Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/summer-camp2023?characterEncoding=utf8",
                    "root", "root");
            //3.定义sql

            //4.需要创建statement
            PreparedStatement preState = con.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                preState.setObject(i+1,params[i]);
            }
            //5.statement执行sql语句,返回结果集
            ResultSet rs = preState.executeQuery();
            //通过结果集rs得到结果集元数据
            ResultSetMetaData md = rs.getMetaData();
            //获取结果集的总列数
            int columnCount = md.getColumnCount();
            //6.解析结果集rs
            while (rs.next()) {
                //根据每一行数据,封装成一个实体对象
                T t=c.newInstance();
                //1.取出某一行的每个数据,封装到对象t的属性中
                for (int i = 1; i <=columnCount ; i++) {
                    //通过列的序号获取每一列的值
                    Object value = rs.getObject(i);
                    if(value!=null){
                        //通过列的序号获取每一列的列名
                        String columnName = md.getColumnName(i);
                        //因为列名和实体类t中的属性名一致,为每一个属性构造一个反射中的set方法
                        Field f = c.getDeclaredField(columnName);
                        //赋予私有属性的赋值权限
                        f.setAccessible(true);
                        //使用反射,把value给到对象t的属性中
                        f.set(t,value);//理解为:把value赋值给对象t的columnName属性,相当于set方法
                    }
                }
                //把对象存入集合中
                tList.add(t);
            }
            //7.关闭资源
            preState.close();
            con.close();
        }catch (Exception e){
            e.printStackTrace();
        }
        return tList;
    }
//查询一行
public static <T> T selectRow(String sql,Class<T> c,Object...params) {
        try {
            //1.注册驱动-反射去加载jar包中com.hp.jdbc.Driver这个类中的DriverManager.registerDriver(new Driver())
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取连接对象 characterEncoding=utf8用于解决插入数据中文乱码的问题
            Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/summer-camp2023?characterEncoding=utf8",
                    "root", "root");
            //3.定义sql

            //4.需要创建statement
            PreparedStatement preState = con.prepareStatement(sql);
            //在执行前,给sql传递参数
            for (int i = 0; i <params.length ; i++) {
                preState.setObject(i+1,params[i]);
            }
            //5.statement执行sql语句,返回结果集
            ResultSet rs = preState.executeQuery();
            //通过结果集rs得到结果集元数据
            ResultSetMetaData md = rs.getMetaData();
            //获取结果集的总列数
            int columnCount = md.getColumnCount();
            //6.解析结果集rs
            // 根据每一行数据,封装成一个实体对象
            T t=null;
            if (rs.next()) {
                t=c.newInstance();
                //1.取出某一行的每个数据,封装到对象t的属性中
                for (int i = 1; i <=columnCount ; i++) {
                    //通过列的序号获取每一列的值
                    Object value = rs.getObject(i);
                    if(value!=null){
                        //通过列的序号获取每一列的列名
                        String columnName = md.getColumnName(i);
                        //因为列名和实体类t中的属性名一致,为每一个属性构造一个反射中的set方法
                        Field f = c.getDeclaredField(columnName);
                        //赋予私有属性的赋值权限
                        f.setAccessible(true);
                        //使用反射,把value给到对象t的属性中
                        f.set(t,value);//理解为:把value赋值给对象t的columnName属性,相当于set方法
                    }
                }
                return t;
            }
            //7.关闭资源
            preState.close();
            con.close();

        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
    //查询一列
    public static <T> List<T> selectColumn(String sql,Class<T> c,Object...params) {
        //创建一个集合,包含所有对象
        List<T> tList = new ArrayList<>();
        try {
            //1.注册驱动-反射去加载jar包中com.hp.jdbc.Driver这个类中的DriverManager.registerDriver(new Driver())
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取连接对象 characterEncoding=utf8用于解决插入数据中文乱码的问题
            Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/summer-camp2023?characterEncoding=utf8",
                    "root", "root");
            //3.定义sql

            //4.需要创建statement
            PreparedStatement preState = con.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                preState.setObject(i+1,params[i]);
            }
            //5.statement执行sql语句,返回结果集
            ResultSet rs = preState.executeQuery();
            //通过结果集rs得到结果集元数据
            ResultSetMetaData md = rs.getMetaData();
            //获取结果集的总列数
            int columnCount = md.getColumnCount();
            //6.解析结果集rs
            while (rs.next()) {
                //通过列的序号获取每一列的值
                T t = (T) rs.getObject(1);

                //把对象存入集合中
                tList.add(t);
            }
            //7.关闭资源
            preState.close();
            con.close();
        }catch (Exception e){
            e.printStackTrace();
        }
        return tList;
    }
    //查询单个
    public static <T> T selectOne(String sql,Class<T> c,Object...params) {
        try {
            //1.注册驱动-反射去加载jar包中com.hp.jdbc.Driver这个类中的DriverManager.registerDriver(new Driver())
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取连接对象 characterEncoding=utf8用于解决插入数据中文乱码的问题
            Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/summer-camp2023?characterEncoding=utf8",
                    "root", "root");
            //3.定义sql

            //4.需要创建statement
            PreparedStatement preState = con.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                preState.setObject(i+1,params[i]);
            }
            //5.statement执行sql语句,返回结果集
            ResultSet rs = preState.executeQuery(sql);
            //通过结果集rs得到结果集元数据
            ResultSetMetaData md = rs.getMetaData();
            //获取结果集的总列数
            int columnCount = md.getColumnCount();
            //6.解析结果集rs
            T t = null;
            if (rs.next()) {
                t = (T) rs.getObject(1);
            }

            //7.关闭资源
            preState.close();
            con.close();

            return t;//返回t
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
    public static int update(String sql,Object...params) {
        try {
            //1.注册驱动-反射去加载jar包中com.hp.jdbc.Driver这个类中的DriverManager.registerDriver(new Driver())
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取连接对象 characterEncoding=utf8用于解决插入数据中文乱码的问题
            Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/summer-camp2023?characterEncoding=utf8",
                    "root", "root");
            //3.定义sql

            //4.需要创建statement
            PreparedStatement preState = con.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                preState.setObject(i+1,params[i]);
            }
            //5.statement执行sql语句,返回结果集
            int i = preState.executeUpdate(sql);

            //7.关闭资源
            preState.close();
            con.close();

            return i;//返回t
        }catch (Exception e){
            e.printStackTrace();
        }
        return 0;
    }

总结

Jdbc深入之后相对困难,对于初学者的代码严密性较高。但是大部分对于MySQL语句中的大致流程是不变的。

1.注册驱动
2.获取连接对象
3.定义sql
4.创建需要的statement
5.statement执行sql语句,返回结果集
6.解析结果集
7.关闭资源

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值