首页 > 其他分享 >JDBC入门

JDBC入门

时间:2024-12-03 18:59:59浏览次数:10  
标签:语句 JDBC 入门 resultSet connection preparedStatement emp SQL

JDBC入门

JDBC(Java Database Connectivity)是 Java 提供的一种标准 API,用于连接和操作关系型数据库。它是 Java 程序和数据库之间的桥梁,允许开发人员通过 Java 代码与数据库交互,执行查询、更新和其他数据库操作。

一、JDBC的快速入门

  1. 官网下载数据库连接驱动jar包。https://downloads.mysql.com/archives/c-j/
  2. 创建Java项目,在项目下创建lib文件夹,将下载的驱动jar包复制到文件夹里
  3. 选中lib文件夹右键->Add as Library,与项目集成

创建数据库

create database db05;

use db05;

create table t_emp
(
    emp_id     int auto_increment comment '员工编号'
        primary key,
    emp_name   varchar(100)  not null comment '员工姓名',
    emp_salary double(10, 5) not null comment '员工薪资',
    emp_age    int           not null comment '员工年龄'
);

insert into t_emp (emp_name,emp_salary,emp_age)
values  ('andy', 777.77, 32),
        ('大风哥', 666.66, 41),
        ('康师傅',111, 23),
        ('Gavin',123, 26),
        ('小鱼儿', 123, 28);

编写代码

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class JDBCQuick {
    public static void main(String[] args) throws Exception {
        // 1、注册驱动
        // 将数据库厂商提供的驱动类,通过类加载的方式加载到我们的程序当中
        Class.forName("com.mysql.cj.jdbc.Driver");

        // 2、获取连接对象
        String url = "jdbc:mysql://localhost:3306/db05";
        String username = "root";
        String password = "password";
        Connection connection = DriverManager.getConnection(url, username, password);

        // 3、获取执行SQL语句的对象
        Statement statement = connection.createStatement();

        // 4、编写SQL语句并执行,接收返回的结果集
        String sql = "select emp_id, emp_name, emp_salary, emp_age from t_emp";
        ResultSet resultSet = statement.executeQuery(sql);

        // 5、处理结果:遍历resultSet结果集
        // resultSet.next()是判断下一行是否存在数据,并返回布尔类型的值
        while(resultSet.next()) {
            int empId = resultSet.getInt("emp_id");
            String s = resultSet.getString("emp_name");
            double empSalary = resultSet.getDouble("emp_salary");
            int empAge = resultSet.getInt("emp_age");
            System.out.println(empId + "\t" + s + "\t" + empSalary + "\t" + empAge);

        }

        // 6、释放资源(先开后关原则)
        resultSet.close();
        statement.close();
        connection.close();
    }
}

二、代码核心API的理解

1、注册驱动

Class.forName("com.mysql.cj.jdbc.Driver");

  • 在 Java 中,当使用JDBC (Java Database Connectivity)连接数据库时,需要加载数据库特定的驱动程序,以使与数据库进行通信。加载驱动程序的目的是为了注册驱动程序,使得JDBC API能够识别并与特定的数据库进行交互
  • 在指定路径的Driver文件中,核心代码就是DriverManager.registerDriver(new Driver());相当于是底层的创建驱动,因此在java代码中也可以使用这行代码进行创建
  • JDK6开始,不再需要显式地调用Class.forName()来加载JDBC驱动程序,只要在类路径中集成了对应的jar文件,会自动在初始化时注册驱动程序

在这里插入图片描述

2、连接对象Connection

  • Connection接口是JDBC API的重要接口,用于建立与数据库的通信通道,只要Connection对象不为空,则代表一次数据库连接。

  • 在建立连接时,需要指定的数据库URL、用户名、密码参数。

    • URL:jdbc:mysql://localhost:3306/db05
    • jdbc:mysql://IP地址:端口号/数据库名称?参数键值对1&参数键值对2
    • 如果要连接的是本机的数据库,则可以简写为jdbc:mysql:///db05,省略本机的IP地址:端口号
  • Connection接口还负责管理事务,Connection接口提供了commitrollback方法,用于提交事务和回滚事务

  • 可以创建Statement对象,用于执行SQL语句并与数据库进行交互

  • 在使用JDBC技术时,必须要先获取Connection对象,在使用完毕后,要释放资源,避免资源占用浪费及泄漏

3、Statement

  • Staticment接口用于执行SQL语句并与数据库进行交互。它是JDBC API中的一个重要接口。通过Staticment对象,可以向数据库发送SQL语句并获取执行结果
  • 结果可以是一个或多个结果
    • 增删改:受影响行数单个结果
    • 查询:单行单列、多行多列、单行多列等结果
  • 但是Statement接口在执行SQL语句时,会产生SQL注入攻击问题:
    • 当使用Statement执行动态构建的SQL查询时,往往需要将查询条件与SQL语句拼接在一起,直接将参数SQL语句一并生成,让SQL的查询条件始终为true得到结果

SQL注入的演示:

import javax.lang.model.util.SimpleAnnotationValueVisitor6;
import java.sql.*;
import java.util.Scanner;

public class JDBCInjection {
    public static void main(String[] args) throws Exception {
        //Sql注入问题

        // 1、注册驱动

        // 2、获取连接对象
        Connection connection = DriverManager.getConnection("jdbc:mysql:///db05", "root", "password");

        // 3、获取执行SQL语句的对象
        Statement statement = connection.createStatement();

        System.out.println("请输入员工姓名:");
        Scanner in = new Scanner(System.in);
        // 允许输入空格
        String name = in.nextLine();

        // 4、编写SQL语句,并执行,接收返回的结果
        String sql = "select emp_id,emp_name,emp_salary,emp_age from t_emp where emp_name = '" + name + "'";
        ResultSet resultSet = statement.executeQuery(sql);

        // 5、处理结果,遍历resultSet
        while(resultSet.next()) {
            int empId = resultSet.getInt("emp_id");
            String s = resultSet.getString("emp_name");
            double empSalary = resultSet.getDouble("emp_salary");
            int empAge = resultSet.getInt("emp_age");
            System.out.println(empId + "\t" + s + "\t" + empSalary + "\t" + empAge);
        }

        // 6、释放资源(先开后关)
        resultSet.close();
        statement.close();
        connection.close();

    }
}

当从键盘获取的数据为:

在这里插入图片描述

组合后的语句就是select emp_id,emp_name,emp_salary,emp_age from t_emp where emp_name = 'abc' or '1' = '1',也就是只要有一个条件满足就会执行(自己加一个true条件),就会查询到数据库中的所有结果

4、PreparedStatement

  • 预防sql注入,将传入的值都变成字符,用户输入的单引号也会自动加上转义字符,进行成功预防sql注入

  • PreparedStatementStatement接口的子接口,用于执行预编译的SQL查询,作用如下:

    • 预编译SQL语句:在创建PreparedStatement时,就会预编译SQL语句,也就是SQL语句已经固定
    • 防止SQL注入:PreparedStatement支持参数化查询,将数据作为参数传递到SQL语句中,采用?占位符的方式,将传入的参数用一对单引号包裹起来,无论传递什么都作为值。有效防止传入关键字或值导致SQL注入问题
    • 性能提升:PreparedStatement是预编译SQL语句,同一SQL语句多次执行的情况下,可以复用,不必每次重新编译和解析
import java.sql.*;
import java.util.Scanner;

public class JDBCPrepared {
    public static void main(String[] args) throws Exception {
        //使用PrepareStatement来预防Sql注入问题

        // 1、注册驱动

        // 2、获取连接对象
        Connection connection = DriverManager.getConnection("jdbc:mysql:///db05", "root", "password");

        // 3、获取执行SQL语句的对象
        PreparedStatement preparedStatement = connection.prepareStatement("select emp_id, emp_name, emp_salary, emp_age from t_emp where emp_name = ?");



        System.out.println("请输入员工姓名:");
        Scanner in = new Scanner(System.in);
        // 允许输入空格
        String name = in.nextLine();

        // 4、为?占位符赋值,并执行SQL语句,接收返回的结果
        // 索引是从占位符的1开始的,而不是0
        preparedStatement.setString(1, name);
        ResultSet resultSet = preparedStatement.executeQuery();

        // 5、处理结果,遍历resultSet
        while(resultSet.next()) {
            int empId = resultSet.getInt("emp_id");
            String s = resultSet.getString("emp_name");
            double empSalary = resultSet.getDouble("emp_salary");
            int empAge = resultSet.getInt("emp_age");
            System.out.println(empId + "\t" + s + "\t" + empSalary + "\t" + empAge);
        }

        // 6、释放资源(先开后关)
        resultSet.close();
        preparedStatement.close();
        connection.close();

    }
}

5、ResultSet

  • ResultSetJDBC API中的一个接口,用于表示从数据库中执行查询语句所返回的结果集。它提供了一种用于遍历和访问查询结果的方式
  • 遍历结果:ResultSet可以使用next()方法将游标移动到结果集的下一行,逐行遍历数据库查询到结果,返回值为boolean类型,true代表有下一行结果,false则代表没有
  • 获取单列结果:可以通过getXxx的方法获取单列的数据,该方法为重载方法,支持索引和列名进行获取

三、基于PreparedStatement实现CRUD

CRUD的理解

CRUD 是数据库和软件开发中常用的术语,表示对数据的基本操作,包含四种功能:

  • Create(创建):插入或添加新的数据。
  • Read(读取):查询或读取现有的数据。
  • Update(更新):修改已有的数据。
  • Delete(删除):移除数据。

这些操作是管理和操作数据库中数据的核心,是所有数据库应用程序和接口设计的基础。

1、查询单行单列

 @Test
    public void testQuerySingleRowAndCol() throws Exception {
        // 1.注册驱动
        // 2.获取连接
        Connection connection = DriverManager.getConnection("jdbc:mysql:///db05", "root", "password");
        // 3.预编译SQL语句,得到PreparedStatement对象
        PreparedStatement preparedStatement = connection.prepareStatement("select count(*) as count from t_emp");
        // 4.执行SQL语句,获取结果
        ResultSet resultSet = preparedStatement.executeQuery();
        // 5.处理结果(如果自己明确只有一个结果,那么resultSet最少要做一次next的判断,才能拿到我们要的列的结果)
        while(resultSet.next()) {
            // 对于结果是一行一列的情况,可以直接使用下标获取
            System.out.println(resultSet.getInt(1));	// 输出: 5
            // 也可以使用别名
            System.out.println(resultSet.getInt("count"));	// 输出: 5
        }
        // 6.关闭资源
        resultSet.close();
        preparedStatement.close();
        connection.close();
    }

在这里插入图片描述

注意事项:

  • 使用.next()方法时,查询开始的第一行是在字段名的那一栏,所有即使是单行,仍然需要调用该方法,否则编译错误
  • 如果已知结果就是单行单列,也可以直接使用下标1获取
  • 如果名字较为复杂时,也可以通过给字段名取别名的形式使用别名的字段标签获取

2、查询单行多列

@Test
    public void testQuerySingleRow() throws Exception {
        // 1.获取驱动
        // 2.获取连接
        Connection connection = DriverManager.getConnection("jdbc:mysql:///db05", "root", "password");
        // 3.预编译SQL语句获取PreparedStatement对象
        PreparedStatement preparedStatement = connection.prepareStatement("select emp_id,emp_name,emp_salary,emp_age from t_emp where emp_id = ?");

//        System.out.println("请输入要查找的员工ID:");
//        Scanner in = new Scanner(System.in);
//        int id = in.nextInt();

        // 给占位符?赋值
        preparedStatement.setInt(1, 5);

        // 4.执行,并接收结果
        ResultSet resultSet = preparedStatement.executeQuery();

        // 5.处理结果
        while(resultSet.next()) {
            int empId = resultSet.getInt("emp_id");
            String empName = resultSet.getString("emp_name");
            double empSalary = resultSet.getDouble("emp_Salary");
            int empAge = resultSet.getInt("emp_age");
            System.out.println(empId + "\t" + empName + "\t" + empSalary + "\t" + empAge);
        }

        // 6.资源释放
        resultSet.close();
        preparedStatement.close();
        connection.close();
    }

在这里插入图片描述

注意事项:

  • 使用占位符的时候,一定要给占位符赋值
  • 如果使用注解@Test,测试方法在运行时,无法接收用户的输入,如果想要接收,则可以使用main方法
  • 同样的,即使只有一行结果,仍然需要先调用一次.next()方法

3、查询多行多列

@Test
    public void testQueryMoreRow() throws Exception {
        Connection connection = DriverManager.getConnection("jdbc:mysql:///db05", "root", "password");
        PreparedStatement preparedStatement = connection.prepareStatement("select emp_id, emp_name, emp_salary, emp_age from t_emp where emp_age > ?");
        preparedStatement.setInt(1, 25);
        ResultSet resultSet = preparedStatement.executeQuery();
        while (resultSet.next()) {
            int empId = resultSet.getInt("emp_id");
            String empName = resultSet.getString("emp_name");
            double empSalary = resultSet.getDouble("emp_Salary");
            int empAge = resultSet.getInt("emp_age");
            System.out.println(empId + "\t" + empName + "\t" + empSalary + "\t" + empAge);
        }
        resultSet.close();
        preparedStatement.close();
        connection.close();
    }

在这里插入图片描述

4、插入数据

@Test
    public void testInsert() throws Exception {
        Connection connection = DriverManager.getConnection("jdbc:mysql:///db05", "root", "password");
        PreparedStatement preparedStatement = connection.prepareStatement("insert into t_emp (emp_name, emp_salary, emp_age) VALUES (?, ?, ?)");
        preparedStatement.setString(1, "小明");
        preparedStatement.setDouble(2, 15000.26);
        preparedStatement.setInt(3, 25);

        int result = preparedStatement.executeUpdate();
        if (result > 0) {
            System.out.println("成功!");
        }else {
            System.out.println("失败!");
        }

        preparedStatement.close();
        connection.close();
    }

注意事项:

  • 添加完数据只用通过调用preparedStatement.executeUpdate()方法判断此作用的影响行即可,大于0,则表示插入成功;反之失败
  • 该方法无需调用.executeQuery()创建ResultSet对象,因此释放内存时也只用释放两个变量

5、修改数据

@Test
    public void testUpdate() throws Exception {
        Connection connection = DriverManager.getConnection("jdbc:mysql:///db05", "root", "password");
        PreparedStatement preparedStatement = connection.prepareStatement("update t_emp set emp_salary = ? where emp_id = ?");
        preparedStatement.setDouble(1, 23000.66);
        preparedStatement.setInt(2, 5);

        int result = preparedStatement.executeUpdate();
        if (result > 0) {
            System.out.println("成功!");
        }else {
            System.out.println("失败!");
        }
        preparedStatement.close();
        connection.close();

    }

注意事项:

  • 修改数据和插入数据一样,都不需要调用.executeQuery()创建ResultSet对象,且调用的判断方法也是.executeQuery()

6、删除数据

@Test
    public void testDelete() throws Exception {
        Connection connection = DriverManager.getConnection("jdbc:mysql:///db05", "root", "password");
        PreparedStatement preparedStatement = connection.prepareStatement("delete from t_emp where emp_name = ?");
        preparedStatement.setString(1, "小明");
        int result = preparedStatement.executeUpdate();
        if (result > 0) {
            System.out.println("成功!");
        }else {
            System.out.println("失败!");
        }
        preparedStatement.close();
        connection.close();
    }

四、可能会出现的问题

1、资源的管理

  • 在使用JDBC相关的资源时,使用完毕后需要及时关闭这些资源以释放数据库服务器资源和避免内存泄漏是很重要的

2、SQL语句问题

  • java.sql.SQLSyntaxErrorExceptionSQL语句错误:
    1. SQL语句有错误,建议先在sql工具中调试好
    2. 连接数据库的URL中,数据库名称编写错误,也会报这个错误

3、SQL语句未设置参数问题

  • java.sql.SQLException: No value specified for parameter 1在使用预编译的SQL语句时,如果有?占位符,要为给每一个占位符赋值,否则就会报该错

4、用户名或密码错误问题

  • 连接数据库时,如果用户名或密码输入错误,也会报SQLException,看清楚后面错误的描述

5、通信异常

  • CommunicationsException在连接数据库的URL中如果IP或端口写错了,就会报这种错误

资源以释放数据库服务器资源和避免内存泄漏是很重要的

2、SQL语句问题

  • java.sql.SQLSyntaxErrorExceptionSQL语句错误:
    1. SQL语句有错误,建议先在sql工具中调试好
    2. 连接数据库的URL中,数据库名称编写错误,也会报这个错误

3、SQL语句未设置参数问题

  • java.sql.SQLException: No value specified for parameter 1在使用预编译的SQL语句时,如果有?占位符,要为给每一个占位符赋值,否则就会报该错

4、用户名或密码错误问题

  • 连接数据库时,如果用户名或密码输入错误,也会报SQLException,看清楚后面错误的描述

5、通信异常

  • CommunicationsException在连接数据库的URL中如果IP或端口写错了,就会报这种错误

标签:语句,JDBC,入门,resultSet,connection,preparedStatement,emp,SQL
From: https://blog.csdn.net/2302_81034736/article/details/144221407

相关文章

  • JDBC连接数据库实现增删改查
    这里为了方便展览,我直接写到了一个类里面,其中也涉及了一些前端交互要注意其中的sql语句的对象,可以根据自己的数据库内容名称进行修改这个是原本的表importjavax.servlet.;importjavax.servlet.http.;importjavax.servlet.annotation.;importjava.io.IOException;import......
  • JDBC链接数据库
    1.首先我们需要下载mysql的官网jar包https://dev.mysql.com/downloads/connector/j/这个版本比较新然后打开idea创建一个项目下面是链接代码,记得看注释packagecom.stu.jdbc;//我的包的名字叫com.stu.jdbc,报错可以删除importjava.sql.*;publicclassJDBC{//这个类的名......
  • HarmonyOS Next 入门实战 - 导航框架:HMRouter
    基础知识目前官方推荐的最佳解决方案,是官方对于Navigation导航组件的封装,使用更简单便捷。如果熟悉Navigation的话,使用起来很快上手。首先先集成HMRouter模块使用命令行安装依赖:ohpminstall@hadss/hmrouter或在模块的oh-package.json5文件中添加依赖{"dependencies"......
  • 《Vue零基础入门教程》第十八课:计算属性 VS 侦听器
      往期内容《Vue零基础入门教程》第十课:属性绑定指令《Vue零基础入门教程》第十一课:事件绑定指令《Vue零基础入门教程》第十二课:双向绑定指令《Vue零基础入门教程》第十三课:条件渲染《Vue零基础入门教程》第十四课:列表渲染《Vue零基础入门教程》第十五课:样式绑定《Vue......
  • web入门-web91
    源码:show_source(__FILE__);include('flag.php');$a=$_GET['cmd'];if(preg_match('/^php$/im',$a)){if(preg_match('/^php$/i',$a)){echo'hacker';}else{echo$flag;}}else......
  • 动态规划、背包问题入门
    目录1、动态规划定义2、数塔问题题目描述:代码实现:3、最长有序子序列问题描述:代码实现:动态规划基本思想特点4、背包问题①01背包问题空间复杂度优化②完全背包③多重背包二进制优化④二维费用背包1、动态规划定义动态规划是一种用于解决优化问题的算法策略,它的......
  • web入门-361
    这是一个ssit漏洞注入基础题ssit介绍:SSTI就是服务器端模板注入(Server-SideTemplateInjection)当前使用的一些框架,比如python的flask,php的tp,java的spring等一般都采用成熟的的MVC的模式,用户的输入先进入Controller控制器,然后根据请求类型和请求的指令发送给对......
  • 网络安全必看—全网最全的命令执行绕过总结分享,黑客技术零基础入门到精通教程
    1基础知识$包裹的内容会被bash进行解析如下1.$""2.$''3.$()4.\`$id\`$包裹的内容增添包裹,有可能会持续深入解析如下,我们在test目录新建了一个whoami,当我们用(l......
  • 从实战的角度分析渗透测试究竟需要学习了解的知识点,黑客技术零基础入门到精通教程建议
    前言最近有很多人询问,自己明明OWASPTop10都学的差不多了,各种靶场也复现的差不多了,Burpsuite、goby、awvs、dirsearch等等工具也是用的丝滑,但为什么就是感觉挖不到洞呢基础知识已经准备的差不多了,现在可能缺乏的是挖洞时间的思路,针对特定场景下的渗透套路,这个一般可以学......
  • pyad(Python Active Directory)入门教程
    今年换了工作,需要比较频繁的操作AD域控,但是之前同事写的PS脚本比较不灵活(主要是我也不太会PS),然后就想能不能使用Python来编写一些自动化程序操作域控,便找到了pyad这个库。pyad是一个第三方Python库,用于管理MicrosoftActiveDirectory,可以将AD对象表示为Python对象(ADUser、ADGrou......