JDBC核心技术笔记(MySQL8+Java17)

JDBC

java17+MySQL8
jdbc是数据库框架的底层原理:MyBatis(半自动),Hibernate(全自动),Spring Data(注解方式进行操作)

java database connectivity:
是java连接数据库技术的统称。

1.jdbc概念理解

1.使用jdbc提供的方法,可以发送字符串类型的sql语句数据库管理软件(MySQL,Oracle等),并且获得语句的执行结果,进而实现数据库数据的crud。

2.java只提供jdbc的规范(接口)在java.aql和javax.sql包下。具体实现由第三方数据库厂商完成具体的实现驱动代码(jar),实现代码可能不同,但是方法都相同。
jdbc本身就是多态的体现,是面向接口编程的。

3.我们要干的事情是用java的接口去接jdbc的具体实现。

(jar包:java程序达成的一种压缩包,你可以将这些jar包导入你的项目中,然后你可以使用这个java程序中的类和方法以及属性)

2.jdbc核心类和接口

  • DriverManager:(作用)
    • 将第三方jar包注册到程序中
    • 可以根据数据库连接信息获取connection
  • Connection:(作用)
    • 和数据库建立的连接,在连接对象上,可以多次执行数据库的crud动作
    • 可以获取statement和preparedStatement以及callableStatement对象
  • Statement|PreparedStatement|CallableStatement:(作用)
    • 具体发送SQL语句到数据库管理软件的对象
    • 不同发送方式稍有不同!preparedStatement是重点
  • Result:
    • OOP的产物(抽象成数据库的查询结果表)
    • 存储DQL查询结果的对象(查询语句返回结果,其他语句返回int类型)
    • 需要我们进行解析,获取具体的数据库数据

不同Statement的不同:

  1. Statement:执行静态SQL语句(没有动态值语句),没有条件值(或条件只涉及常数)->整个语句可以写成固定的字符串;
  2. PreparedStatement:有动态值(预编译SQL路线);
  3. 执行标准存储过程

(驱动版本选用8±>8.0.25+可以省时区设置;对应java jdbc规范4.2+)

3.jdbc核心API

3.1 导入jar包方式

  1. 项目先创建lib文件夹
  2. 导入驱动依赖jar包
  3. jar包右键,添加为项目依赖Add as Library…

3.2 jdbc基本使用步骤分析(6步)

  1. 注册驱动:把依赖的jar包进行安装
  2. 建立连接connection;
  3. 创建发送sql语句的对象statement;
  4. statement对象发送SQL语句到数据库,并且获取返回结果resultSet;
  5. 解析结果集;
  6. 释放资源:砸桥connection,砸车statement,砸箱子resultSet。

准备工作:

CREATE DATABASE jdbcTestDb;

USE jdbcTestDB;

CREATE TABLE t_user(
 id INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户主键',
 account VARCHAR(20) NOT NULL UNIQUE COMMENT '账号',
 `password` VARCHAR(64) NOT NULL COMMENT '密码',
 nickname VARCHAR(20) NOT NULL COMMENT '昵称');
DESC t_user;
 
INSERT INTO t_user(account,`password`,nickname)
VALUES('root','123456','经理'),('admin','66666','管理员');

SELECT * FROM t_user;

java实现基于statement演示查询:

package com.jdbcLearning.statement;

import com.mysql.cj.jdbc.Driver;

import java.sql.*;
/**
 * @author 马聪
 * @version 1.0
 * introduction:使用statement查询t_user表下的数据
 */
public class StatementQuery {
    /**
     * TODO:
     *      DriverManager
     *      Connection
     *      Statement
     *      ResultSet
     * @param args
     */
    public static void main(String[] args) throws SQLException {
//        1. 注册驱动:把依赖的jar包进行安装
        /**
         * TODO:
         *      注册驱动
         *      依赖:驱动版本 8+ com.mysql.cj.jdbc.Driver
         *           驱动版本 5+ com.mysql.jdbc.Driver
         *
         */
        DriverManager.registerDriver(new Driver());
//        2. 建立连接connection;
        /**
         * TODO:
         *      连接要素:
         *          数据库ip 127.0.0.1
         *          db端口号 默认3306
         *          账号 root
         *          密码
         *          连接数据库名称: jdbcTestDb
         */
        /**
         * para1:url
         *      jdbc:数据库厂商名://ip:port/数据库名
         *      jdbc:mysql://127.0.0.1:3306/jdbcTestDb
         *
         */
        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/jdbcTestDb", "root", "gaoceng3905");

//        3. 创建发送sql语句的对象statement;
        Statement statement = connection.createStatement();
//        4. statement对象发送SQL语句到数据库,并且获取返回结果resultSet;
        String sql = "select * from t_user";
        ResultSet resultSet = statement.executeQuery(sql);
//        5. 解析结果集;
        //先看看有没有
        while(resultSet.next()){
            int id = resultSet.getInt("id");
            String account = resultSet.getString("account");
            String password = resultSet.getString("password");
            String nickname = resultSet.getString("nickname");
            System.out.println(id+"--"+account+"--"+password+"--"+nickname);
        }
//        6. 释放资源:砸桥connection,砸车statement,砸箱子resultSet。
        resultSet.close();
        statement.close();
        connection.close();
    }
}

3.3jdbc使用步骤详解

需求,在3.1的数据库基础上模拟登陆
在这里插入图片描述
目的:明确jdbc使用流程和详细讲解内部设计;发现问题,引出PreparedStatement

1.键盘输入时间,收集账号和密码信息
2.注册驱动
3.获取连接
4.创建Statement
5.发送SQL语句,获得查询结果
6.解析查询结果
7.关闭资源

step1:Driver本身静态代码块有调用DriverManager的registerDriver方法所以避免注册两次(所以不采用3.1中的DriverManager.registerDriver(new Driver());),只用Driver加载一下类即可(加载类就会调用)->回顾触发类加载的多种情况:

  1. 调用静态属性、方法;
  2. 子类实例化
  3. 本类实例化
  4. 反射
  5. 接口1.8的default默认实现
  6. 程序入口main

如果直接new Driver有些不优雅,硬编码,改其他dbms的jdbc会不适用
不如反射Class.forName("com.mysql.cj.jdbc.Driver");
后续还可以:字符串->提取到外部配置文件->可以不改动代码的情况下,完成数据库驱动的切换!

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!");
        }
    }
}
package com.jdbcLearning.statement;

import com.mysql.cj.jdbc.Driver;

import java.sql.*;
import java.util.Properties;
import java.util.Scanner;

/**
 * @author 马聪
 * @version 1.0
 * introduction:
 * jdbcLearning3.2

 * TODO:
 *      输入账号以及密码
 *      进行数据库查询t_user
 *      反馈登录成功还是失败
 *      (引出PreparedStatement)

 * TODO:
 *      1.键盘输入时间,收集账号和密码信息
 *      2.注册驱动
 *      3.获取连接
 *      4.创建Statement
 *      5.发送SQL语句,获得查询结果
 *      6.解析查询结果
 *      7.关闭资源
 */
public class StatementUserLoginPart {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        //1.键盘输入时间,收集账号和密码信息
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入账号:");
        String acct = scanner.nextLine();
        System.out.println("请输入密码:");
        String pswd = scanner.nextLine();
        //2.注册驱动。会注册两次,方法本身会注册一次,Driver静态代码块本身也会注册一次
        //DriverManager.registerDriver(new Driver());
        //只触发static
        new Driver();//硬编码,不优雅
        //字符串->提取到外部配置文件->可以不改动代码的情况下,完成数据库驱动的切换!
        Class.forName("com.mysql.cj.jdbc.Driver");
        //3.获取连接

        /*
         * getConnection(1,2,3)方法是一个重载方法
         * 允许开发者,用不同形式传入数据库的核心参数
         * 核心属性:
         *  1.数据库所在主机的ip或主机名:localhost|127.0.0.1
         *  2.数据库软件所在主机的端口号:3306
         *  3.连接的具体库:jdbcTestDb
         *  4.连接的账号:root
         *  5.连接的密码:
         *  6.可选的信息 没有

         *  三个参数:
         *  String url 其他 jdbc:mysql://127.0.0.1:3306/jdbcTestDb?key=value&key=value
         *  如果dbms安装到本机,可以省略为jdbc:mysql:///jdbcTestDb,省略了本机地址和默认3306端口号
         *  String user账号
         *  String pswd密码
         * 注意:此处key=value&key=value并不需要写
         *
         * 两个参数:
         * String url 同三个参数
         * Properties info账号密码 key=value成对字符串 user:xxx;password:xxx
         *
         * 一个参数
         * String url 将账号密码放在可选信息?key=value&key=value处
         *
         * url=账号&password=密码
         * 8.0.25+版本驱动可以不填时区作为可选信息;
         * 8+版本可以不用写useUnicode=true&characterEncoding=utf8&useSSL=true
         * serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=true
         */
        Properties info = new Properties();
        info.put("user","root");
        info.put("password","gaoceng3905");
        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/jdbcTestDb", info);

        //Connection connection1 = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/jdbcTestDb?user=root&password=gaoceng3905");

        //4.创建Statement
        Statement statement = connection.createStatement();//小汽车
        //5.发送SQL语句,获得查询结果
        String sql = "SELECT * FROM t_user WHERE account = '"+acct+"' AND password = '"+pswd+"';";
        /*
         * sql分类:DDL,DML(增删改),DQL,DCL,TPL
         * 参数sql:非DQL
         * 如果为DML->返回修改行数
         * 如果非DML->返回0
         * int row = statement.executeUpdate(sql);
         *
         */
        ResultSet resultSet = statement.executeQuery(sql);
        //6.解析查询结果
        /*
         *取数据:逐行cursor开始指向第一行之前
         * next方法向后移动cursor,有数据,返回true,反之false
         * 
         * 获取列数据
         * resultSet.get类型(String columnLabel | int columnIndex)
         * columnLabel:列名或者列的别名
         * int columnIndex:从左到右从1开始
         */

//        while(resultSet.next()){
//            int id = resultSet.getInt(1);
//            String account = resultSet.getString("account");
//            String password = resultSet.getString(3);
//            String nickname = resultSet.getString(4);
//            System.out.println(id+"--"+account+"--"+password+"--"+nickname);
//        }
        if(resultSet.next()){
            System.out.println("登录成功");
        }else{
            System.out.println("登录失败");
        }
        //7.关闭资源
        resultSet.close();
        statement.close();
        connection.close();
    }
}

3.4statement的问题以及preparedStatement基本使用

statement的问题:
会在字符串拼接的时候有SQL注入攻击的危险,使得结果出现问题。比如输入' or '1'='1;字符串拼接比较麻烦;只能拼接字符串类型,其他类型无法处理(不懂为啥sql语句会有其他类型)

statement只适合静态查询语句,不适合动态查询
原本:1.创建Statement;2.拼接sql;3.发送sql
preparedStatement

1.先编写sql语句结果,不包含动态值部分的语句,动态值部分使用占位符?代替 注意?只能代替动态值
2.创建PreparedStatement,并传入动态值
3.动态值 占位符 赋值?单独赋值即可
4.发送sql语句即可,并返回结果

获取结果集时,不需要传sql语句,因为已经知道语句以及动态值,只需要点击发送即可。

package com.jdbcLearning.preparedStatement.api;

import com.mysql.cj.jdbc.Driver;

import java.sql.*;
import java.util.Scanner;

/**
 * @author 马聪
 * @version 1.0
 * introduction:
 * 使用预编译的Statement完成用户登录
 *
 * TODO:
 * 防止注入攻击
 * 演示ps的使用流程
 */
public class PSUserLogin {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1.键盘输入时间,收集账号和密码信息
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入账号:");
        String acct = scanner.nextLine();
        System.out.println("请输入密码:");
        String pswd = scanner.nextLine();
        //2.注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //3.获取连接
        Connection connection = DriverManager.getConnection("jdbc:mysql:///jdbcTestDb?user=root&password=gaoceng3905");
        //4.创建Statement:

        //原本:1.创建Statement;2.拼接sql;3.发送sql
        //preparedStatement
        //(1).先编写sql语句结果,不包含动态值部分的语句,动态值部分使用占位符?代替 注意?只能代替动态值
        //(2).创建PreparedStatement
        //(3).动态值 占位符 赋值?单独赋值即可
        //(4).发送sql语句即可,并返回结果

        String sql = "select * from t_user where account = ? and password = ?";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //参数1:index占位符的位置,从左向右数从1开始
        //参数2:占位符的值,Object类型可以设置任何类型的值
        preparedStatement.setObject(1,acct);
        preparedStatement.setObject(2,pswd);

        //5.获取结果集
        //不需要传sql语句,因为已经知道语句以及动态值,只需要点击发送即可
        ResultSet resultSet = preparedStatement.executeQuery();

        //6.结果集解析
        if(resultSet.next()){
            System.out.println("登录成功");
        }else{
            System.out.println("登录失败");
        }
        //关闭资源
        resultSet.close();
        preparedStatement.close();
        connection.close();
    }
}

3.5查询进阶(转List<Map>

查询自动化进阶->getMetaData(获取列相关信息的方法得到metaData对象)

    List<Map> list = new ArrayList<>();
        while(resultSet.next()){
            Map<String,Object> map = new HashMap<>();
            //纯手动取值
//            map.put("id",resultSet.getObject("id"));
//            map.put("account",resultSet.getObject("account"));
//            map.put("password",resultSet.getObject("password"));
//            map.put("nickname",resultSet.getObject("nickname"));
            //自动遍历列
            //TODO:metadata装的是当前的列信息
            ResultSetMetaData metaData = resultSet.getMetaData();
            int columnCount = metaData.getColumnCount();
            for (int i = 1; i < columnCount; i++) {
                //name是实际名,label是别名,美别名才是实际名
                map.put(metaData.getColumnLabel(i),resultSet.getObject(i));
            }

            list.add(map);
        }

insert示例

    @Test
    public void testInsert() throws ClassNotFoundException, SQLException {
        /*
         *t_user插入一条数据
         *  account test
         *  password test
         *  nickname 二狗子
         */
        //1.注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //2.connection
        Connection connection = DriverManager.getConnection("jdbc:mysql:///jdbcTestDb","root","gaoceng3905");
        //3.ps(编写sql,动态值赋值,发送)
        String sql = "insert into t_user(account,password,nickname) values(?,?,?);";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setObject(1,"test");
        preparedStatement.setObject(2,"test");
        preparedStatement.setObject(3,"二狗子");
        //4.resultset
        int rows = preparedStatement.executeUpdate();
        //5.insert不用解析,输出结果
        if(rows >0){
            System.out.println("插入成功");
        }else{
            System.out.println("插入失败");
        }
        //6.关闭资源
        preparedStatement.close();
        connection.close();
    }

insert示例(delete和update实现同理)

    @Test
    public void testInsert() throws ClassNotFoundException, SQLException {
        /*
         *t_user插入一条数据
         *  account test
         *  password test
         *  nickname 二狗子
         */
        //1.注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //2.connection
        Connection connection = DriverManager.getConnection("jdbc:mysql:///jdbcTestDb","root","gaoceng3905");
        //3.ps(编写sql,动态值赋值,发送)
        String sql = "insert into t_user(account,password,nickname) values(?,?,?);";
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        preparedStatement.setObject(1,"test");
        preparedStatement.setObject(2,"test");
        preparedStatement.setObject(3,"二狗子");
        //4.resultset
        int rows = preparedStatement.executeUpdate();
        //5.insert不用解析,输出结果
        if(rows >0){
            System.out.println("插入成功");
        }else{
            System.out.println("插入失败");
        }
        //6.关闭资源
        preparedStatement.close();
        connection.close();
    }
  • 23
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值