7、JDBC复习

建立连接

public static Connection getConnection() throws Exception {
        //1、反射去加载jar包中com.mysql.jdbc.Drive这个类中得 DriverManagerDriver(new Driver())
        Class.forName("com.mysql.jdbc.Driver");
        //2、获取连接对象
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3307/summer_camp2023?characterEncoding=utf8", "root", "123456");
        System.out.println(connection);
        return connection;
    }

Driver类是java连接数据库的驱动类,DriverManager是驱动管理类。

java注册数据库驱动的方式是通过反射来创建实例注册的。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.mysql.jdbc;

import java.sql.DriverManager;
import java.sql.SQLException;

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }

    static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

DriverManager.getConnection方法得参数:

  • url : 连接数据库得url地址,协议名:子协议://主机名:端口号/数据库库名?连接参数
    • 协议名:java使用jdbc协议来约束与各个数据库之间得连接
    • 子协议:一般是指连接什么类型得数据库,可以是mysql、Oracle等等
    • 主机名:数据库连接所在的主机地址
    • 端口号:数据库连接端口
    • 数据库名:需要操作的数据库名
    • 连接参数:配置连接属性,例如字符编码、时区等等
  • username:连接数据库所需要的用户名
  • password: 连接数据库所需要的密码

增删改查

我们已经能够获取连接对象了,但是想要对数据库中表进行CRUD,他却不能够为我们直接所用。

我们需要通过Connection 对象来获取一个**statement或者是PrepareStatement**对象。这个对象才是我们能够操作数据表的对象。

  • statement:该对象在操作数据库时,sql语句写死的,也就是说并不能动态的设置参数,有可能导致sql注入,因为他如果想要添加sql参数,只能通过拼接字符串的形式。
  • PrepareStatement:该对象操作数据库时的sql可以被添加参数,比如根据条件查询,那么可以写成select * from table where id = ?,这个?就是一个占位符,用来表示用于填充参数的。使用preparestatement不仅可以让我们不需要去写那么多死的sql,而且还会解决Sql注入问题。PrepareStatement还可以提高执行效率。

增删改

//增删改查
    public static int update(String sql, Connection con,Object ...params) throws Exception {
        PreparedStatement prepareStatement = con.prepareStatement(sql);
        for (int i = 0; i < params.length; i++) {
            prepareStatement.setObject(i+1,params[i]);
        }
        int i = prepareStatement.executeUpdate();
        close(con,prepareStatement);
        return i;
    }

利用PrepareStatement对象操作数据表

@Test
    public void testUpdate(){
        String sql = "delete from t_emps where id = ?";
        try {
            //JDBCUtil.getConnection() 获取数据库连接对象
            int i = JDBCUtil.update(sql, JDBCUtil.getConnection(),"e0006");
            System.out.println(i);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

增删改可以写成一个方法,因为它们只需要返回一个int的类型的数据,表示受影响的行数。

JDBCUtil.getConnection()是通过工具类获取数据库连接,减少代码冗余

查询

多行查询

多行查询是查询中最为复杂的,

//查询多行
public static <T> List<T> queryForList(Class<T> type,String querySql, Connection con,Object ...params) throws Exception {
        PreparedStatement prepareStatement = con.prepareStatement(querySql);
        for (int i = 0; i < params.length; i++) {
            prepareStatement.setObject(i+1,params[i]);
        }
        ResultSet resultSet = prepareStatement.executeQuery();
        //获取结果集的行
        ResultSetMetaData metaData = resultSet.getMetaData();
        //获取列数
        int columnCount = metaData.getColumnCount();
        List<T> results = new ArrayList<>();
        while (resultSet.next()){
            //反射获取实例
            T t = type.newInstance();
            for (int i = 0; i < columnCount; i++) {
                Object value = resultSet.getObject(i+1);
                if (value != null){
                    //根据数据表的列索引获取列名
                    String columnName = metaData.getColumnName(i+1);
                    //反射获取该类型指定的属性名
                    Field field = type.getDeclaredField(columnName);
                    //允许暴力注入,即使是private修饰的属性
                    field.setAccessible(true);
                    //注入属性值
                    field.set(t,value);
                }
            }
            results.add(t);
        }
    	//关闭资源
        close(con,prepareStatement);
        return results;
    }

这里我们使用到了两个比较陌生的知识——反射和ResultSetMetaData

  • 反射:运行时动态获取类信息以及动态调用类中的成分的能力称为Java语言的反射机制。以上代码就是运用了反射的机制,调用者需要传入封装在list集合中的对象类型的Class类。再配合泛型使用,这样我们才知道应该封装什么类型的类到集合中,并且返回相应泛型的集合。
  • ResultSetMetaData:该对象是由结果集ResultSet对象获取的,这个对象是我在这个案例中才得知的,它里面封装了结果集的列数,和根据索引获取列名的方法。

我们为PrepareStatement传入参数的方式是,通过形参获取,但是我们并没有写死,而是用**可变参数…**来获取,这样表示调用者可以传入多个参数,并且还可以选择不传。

可变参数只能够再形参上使用,实际上是把所有的参数都封装成数组

    for (int i = 0; i < params.length; i++) {
        prepareStatement.setObject(i+1,params[i]);
    }

所以我们可以循环来获取这些参数

单行查询

当行查询和多行查询一样,只是返回结果由list变为一个对象,而这个对象就是通过反射获取

public static <T> T queryForObject(Class<T> type ,String sql,Connection con,Object ...params) throws Exception {
        PreparedStatement prepareStatement = con.prepareStatement(sql);
        for (int i = 0; i < params.length; i++) {
            prepareStatement.setObject(i+1,params[i]);
        }
        //获取实例
        T t = null;
        ResultSet resultSet = prepareStatement.executeQuery();
        ResultSetMetaData metaData = resultSet.getMetaData();
        int columnCount = metaData.getColumnCount();
        if (resultSet.next()){
            t = type.newInstance();
            for (int i = 0; i < columnCount; i++) {
                Object value = resultSet.getObject(i+1);
                if (value != null){
                    String columnName = metaData.getColumnName(i+1);
                    Field field = type.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(t,value);
                }
            }
        }
        //关闭资源
        close(con,prepareStatement);
        return t;
    }

单列查询

//查询单列数据
    public static <T> List<T> queryForColumn(Class<T> type,String sql,Connection con,Object ...params) throws Exception {
        List<T> results = new ArrayList<>();
        PreparedStatement prepareStatement = con.prepareStatement(sql);
        for (int i = 0; i < params.length; i++) {
            prepareStatement.setObject(i + 1, params[i]);
        }
        ResultSet resultSet = prepareStatement.executeQuery();
        while (resultSet.next()){
            T t = null;
            t = (T)resultSet.getObject(1);
            results.add(t);
        }
        close(con,prepareStatement);
        return results;
    }

单个查询

public static <T> T queryForOne(Class<T> type,String sql, Connection con,Object ...params) throws Exception {
        PreparedStatement prepareStatement = con.prepareStatement(sql);
        for (int i = 0; i < params.length; i++) {
            prepareStatement.setObject(i+1,params[i]);
        }
        ResultSet resultSet = prepareStatement.executeQuery();
        //获取结果集的行
        ResultSetMetaData metaData = resultSet.getMetaData();
        //获取列数
        int columnCount = metaData.getColumnCount();
        T t = null;
        if (resultSet.next()){
            t = (T) resultSet.getObject(1);
        }
        close(con,prepareStatement);
        return t;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值