笔记总结:MySQL——JDBC

JDBC

一、JDBC

1.定义

Java Database Connection,Java数据库连接技术

2.JDBC API

java提供的接口,位于java.sql包

  1. Driver

    用于连接数据库的接口,数据库厂商提供的JDBC工具包必须包含该接口的实现

    //根据给定URL地址连接数据库
    //info提供数据库账号密码
    Connection connect(String url, java.util.Properties info) throws SQLException;
    
  2. DriverManager

    数据库厂商提供的JDBC交给DriverManager管理,负责获取数据库连接对象

    String url = "jdbc:mysql://localhost:3306/数据库名称?serverTimezone=Asia/Shanghai";
    public static Connection getConnection(String url, String user, String password) throws SQLException;
    
  3. Connection

    提供与数据库交互的功能接口

    //创建一个SQL语句执行对象
    Statement createStatement() throws SQLException;
    //创建一个预处理SQL执行对象
    PreparedStatement prepareStatement(String sql) throws SQLException;
    //创建一个存储过程SQL执行对象
    CallableStatement prepareCall(String sql) throws SQLException;
    //设置该连接上所有操作是否执行自动提交
    void setAutoCommit(boolean autoCommit) throws SQLException;
    void commit() throws SQLException;
    void rollback() throws SQLException;
    void close() throws SQLException;
    //设置事务隔离级别
    void setTransactionIsolation(int level) throws SQLException;
    
    //不支持事物
    int TRANSACTION_NONE = 0;
    //读取未提交的数据
    int TRANSACTION_READ_UNCOMMITTED = 1;
    //读取已提交的数据
    int TRANSACTION_READ_COMMITTED = 2;
    //可重复读
    int TRANSACTION_REPEATABLE_READ = 4;
    //串行化
    int TRANSACTION_SERIALIZABLE = 8;
    
  4. Statement

    执行SQL语句接口

    //执行查询,得到结果集
    ResultSet executeQuery(String sq) throws SQLException;
    //执行更新,得到受影响的行数
    int executeUpdate(String sql) throws SQLException;
    //关闭SQL语句执行器
    void close() throws SQLException;
    //将SQL语句添加到批处理执行SQL列表中
    void addBatch(String sql) throws SQLException;
    //执行批处理,返回每条SQL语句的执行结果
    int[] executeBatch() throws SQLException;
    
  5. ResultSet

    查询结果集接口

    //光标向下移动一行,默认为第0行,若有数据,则返回true,否则返回false
    boolean next() throws SQLException;
    void close() throws SQLException;
    //获取指定列的字符串值
    //也可以传列的名字
    String getString(int columnIndex) throws SQLException;
    boolean getBoolean(int columnIndex) throws SQLException;
    int getInt(int columnIndex) throws SQLException;
    //对象同时转换为type
    Object getObject(int columnIndex, Class type) throws SQLException;
    //获取结果集元数据:列名称,列数量,列别名等
    ResultSetMetaData getMetaData() throws SQLException;
    //光标向上移动一行
    boolean previous()  throws SQLException;
    
3.JDBC操作步骤
  1. 引入驱动包

    将mysql-connector-java.jar引入工程

  2. 加载驱动

    //MySQL5.0
    Class.forName("com.mysql.jdbc.Driver");
    //MySQL8.0
    Class.forName("com.mysql.cj.jdbc.Driver");
    
  3. 获取连接Connection

  4. 创建SQL语句执行器Statement

  5. 使用执行器执行查询得到结果集ResultSet

  6. 通过结果集获取数据(利用循环)

  7. 释放资源:3个close

4.预处理SQL
  • SQL注入

    实例:用户查询输入条件1=‘1’,此时查询所有信息,使查询结果发生改变

  • PreparedStatement常用方法

    //执行查询,得到一个结果集
    ResultSet executeQuery() throws SQLException;
    //执行更新,得到受影响的行数
    int executeUpdate() throws SQLException;
    //使用给定的整数值设置给定位置的参数
    void setInt(int parameterIndex, int x) throws SQLException;
    //使用给定的长整数值设置给定位置的参数
    void setLong(int parameterIndex, long x) throws SQLException;
    //使用给定的双精度浮点数值设置给定位置的参数
    void setDouble(int parameterIndex, double x) throws SQLException;
    //使用给定的字符串值设置给定位置的参数
    void setString(int parameterIndex, String x) throws SQLException;
    //使用给定的对象设置给定位置的参数
    void setObject(int parameterIndex, Object x) throws SQLException;
    //获取结果集元数据
    ResultSetMetaData getMetaData() throws SQLException;
    
  • 在sql语句中使用?占位符来替代用户输入的内容,在利用set设置占位符内容

    这样,就会把用户输入的内容看作一个整体,用户就不能通过输入类似sql语句的内容进行sql注入

  • 在实际运用中,推荐使用预处理执行器,确保数据库安全

  • 经典实例:

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入商品名称:");
        String goodsName = sc.nextLine();
        String url = "jdbc:mysql://localhost:3306/lesosn?serverTimezone=Asia/Shanghai";
        String username = "root";
        String password = "root";
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            Connection con = DriverManager.getConnection(url,username,password);
            String sql = "SELECT id,name,number,price,agent_id FROM goods WHERE name= ? LIMIT 0,20";
            PreparedStatement ps = con.prepareStatement(sql);
            //设置问号替换的值
            ps.setString(1, goodsName);
            ResultSet rs = ps.executeQuery();
            while(rs.next()){
                long id = rs.getLong("id");
                String name = rs.getString("name");
                int number = rs.getInt("number");
                double price = rs.getDouble("price");
                int agent_id = rs.getInt("agent_id");
                System.out.println(id + "," + name + "," + number + "," + price + "," + agent_id);
            }
            rs.close();
            ps.close();
            con.close();
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    

二、反射

1.Class类
  • Java程序通过编译器编译生成class文件,class文件在JVM上执行

  • 定义一个类来描述所有类的共同特征:

public class Class {
    private String name; //类名
    private Package pk; //包名
    private Constructor[] constructors; //构造方法
    private Field[] fields; //字段
    private Method[] methods; //方法
    private Class<?>[] interfaces; //实现的接口
    private Class<?> superClass; //继承的父类
    //省略getter/setter
}
  • JVM加载类时对类进行解析,将类信息存储进Class对象中。

    在使用的过程中,JVM通过Class对象反推到我们编写的类的内容,这个过程为反射。

  • java提供类:java.lang.Class

  • 获取类对应的Class对象

    Class<类名> clazz = 类名.class;
    Class<类名> clazz = 对象名.getClass();
    Class<类名> clazz = Class对象名.getSuperClass();
    Class clazz = Class.forName("类的全限定名"); //包名.类名
    Class<类名> clazz = 包装类.TYPE;
    
  • Class常用方法

    //获取类中使用public修饰的字段
    public Field[] getFields() throws SecurityException;
    //获取类中定义的所有字段
    public Field[] getDeclaredFields() throws SecurityException;
    //通过给定字段名获取类中定义的字段,不能是私有的
    public Field getField(String name) throws NoSuchFieldException, SecurityException;
    //获取类中使用public修饰的方法
    public Method[] getMethods() throws SecurityException;
    public Method[] getDeclaredMethods() throws SecurityException;
    public Method getDeclaredMethod(String name, Class<?>... parameterTypes) throws NoSuchFieldException, SecurityException;
    public Constructor[]<类名> getConstructors() throws SecurityException;
    public Constructor[]<类名> getDeclaredConstructors() throws SecurityException;
    public Constructor<类名> getConstructor(Class<?>... parameterTypes) throws NoSuchFieldException,SecurityException;
    //获取类的全限定名
    public String getName();
    //获取类名
    public String getSimpleName();
    //获取类所在的包
    public Package getPackage();
    //判断该类是否是基本数据类型
    public native boolean isPrimitive();
    public native boolean isInterface();
    public native boolean isArray();
    //通过类的无参构造创造一个实例,确保无参构造是公开的
    public T newInstance() throws InstantiationException, IllegalAccessException;
    
  • 反射实例:利用Class创建一个学生对象,并为name字段赋值,并反推出name的get和set方法

public static void main(String[] args){
    Class<Student> clazz = Student.class;
    Constructor<? extends Student> c = clazz.getDeclaredConstructor();
    //Student类中的无参构造是私有的
    c.setAccessible(ture);
    Student s = clazz.newInstance();
    Field nameField = clazz.getDeclaredField("name");
    nameField.setAccessible(true);
    //给指定对象的字段赋值
    nameField.set(s, "李四");
    
    //反推方法getName
    String fieldName = nameField.getName();
    String methodName = "get" + fieldName.subString(0,1).toUpperCase() + fieldName.subString(1);
    Method m = clazz.getDeclaredMethod(methodName);
    m.setAccessible(true);
    String name = (String) m.invoke(s);
    System.out.println(name);
    
    //反推方法setName
    methodName = "set" + fieldName.subString(0,1).toUpperCase() + fieldName.subString(1);
    m = clazz.getDeclaredMethod(methodName, nameField.getType());
    m.setAccessible(true);
    m.invoke(s, "李刚");
}
//省略抛出异常
2.反射与数据库

如果查询结果的字段与对象的属性名保持一致,就可以利用反射完成万能查询。

万能查询实例:

public class JdbcUtil {

    private static final String url = "jdbc:mysql://localhost:3306/lesosn?serverTimezone=Asia/Shanghai";
    private static final String username = "root";
    private static final String password = "root";

    static{
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            System.out.println("驱动加载异常");
        }
    }

    //test
    public static void main(String[] args) {
        String sql = "SELECT id,name,region_id AS regionId FROM agent WHERE name LIKE ?";
        Object[] params = {"%魅%"};
        List<Agent> agentList = query(sql, Agent.class, params);
        agentList.forEach(System.out::println);
    }


    public static <T> List<T> query(String sql, Class<T> clazz, Object...params){
        List<T> list = new ArrayList<>();
        Connection connection = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            connection = DriverManager.getConnection(url, username, password);
            ps = createPreparedStatement(connection, sql, params);
            rs = ps.executeQuery();
            while(rs.next()){
                T t = createInstance(clazz, rs);
                list.add(t);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(rs, ps, connection);
        }
        return list;
    }

    public static int update(String sql, Object...params){
        int result = 0;
        Connection connection = null;
        PreparedStatement ps = null;
        try {
            connection = DriverManager.getConnection(url, username, password);
            ps = createPreparedStatement(connection, sql, params);
            result = ps.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(ps,connection);
        }
        return result;
    }

    //利用反射,构造对象
    private static <T> T createInstance(Class<T> clazz, ResultSet rs)
            throws NoSuchMethodException, InvocationTargetException, InstantiationException,IllegalAccessException {
        Constructor<? extends T> c = clazz.getConstructor();
        c.setAccessible(true);
        T t = c.newInstance();
        Field[] fields = clazz.getDeclaredFields();
        for(Field field : fields){
            String fieldName = field.getName();
            String methodName = "set" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
            Method m = clazz.getDeclaredMethod(methodName, field.getType());
            //会产生找不到这个字段的问题
            try{
                Object value = rs.getObject(fieldName, field.getType());
                m.invoke(t, value);
            }catch (Exception e){
                continue;
            }
        }
        return t;
    }

    private static PreparedStatement createPreparedStatement(Connection connection, String sql, Object...params) throws SQLException {
        PreparedStatement ps = connection.prepareStatement(sql);
        if(params != null && params.length > 0){
            for(int i = 0; i < params.length; ++i){
                ps.setObject(i + 1, params[i]);
            }
        }
        return ps;
    }

    private static void close(AutoCloseable...closeable){
        if(closeable != null && closeable.length > 0){
            for(AutoCloseable ac : closeable){
                if(ac != null){
                    try {
                        ac.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值