Java学习-JDBC(二)

news2024/12/27 13:20:33

核心API

注册驱动
  • Class.forName(“com.mysql.cj.jdbc.Driver”);
  • 在Java中,当使用JDBC连接数据库时,需要加载数据库特定的驱动程序,以便与数据库进行通信,加载驱动程序的目的是为了注册驱动程序,使得JDBC API能够识别并与特定的数据库进行交互
  • 从JDK6开始,不需要显式地调用Class.forName()来加载JDBC驱动程序,只要在路径中集成了对应的jar文件,会自动在初始化时注册驱动程序。
    在这里插入图片描述
Connection
  • Connection接口是JDBC API的重要接口,用于建立与数据库的通信通道,Connection对象不为空,则代表一交数据库连接
  • 在建立连接时,需要指定数据库URL、用户名、密码参数
    • URL:jdbc:mysql://192.168.29.201:3306/jdbc
    • URL:jdbc:mysql://IP地址:端口号/数据库名?参数键值对1&参数键值对2
  • Connection接口还负责管理事务,Connection接口提供了commit和rollback方法,用于事务提交和回滚
  • 在使用JDBC技术时,必须先获取Connection对象,使用完毕后,要释放资源,避免资源占用造成泄露
Statement
  • Statement接口用于执行SQL语句并与数据库进行交互,它是JDBC API一个重要接口,通过Statement对象,可以向数据库发送SQL语句并获取执行结果
  • 结果可以是一个或多个结果
    • 增删改:受影响行数单个结果
    • 查询:单行单列,多行多列,单行多列等结果
  • Statement接口在执行SQL语句时,会产生SQL注入攻击问题
    • 不使用Statement执行动态构建的SQL查询时,往往需要将查询条件与SQL语句拼接在一起,直接将参数和SQL语句一并生成,让SQL的查询条件始终为true得到结果
public class JDBCInjection {
    public static void main(String[] args) throws SQLException {
        String url = "jdbc:mysql://192.168.29.201:3306/jdbc";
        String username = "root";
        String password = "Lotus!1120";
        Connection conn = DriverManager.getConnection(url, username, password);
        //获取执行SQL语句对象
        Statement statement = conn.createStatement();
        System.out.println("Please input your emp_name:");
        Scanner scanner = new Scanner(System.in);
        String name = scanner.nextLine();
        //编写SQL语句并执行,接收返回结果集
        String statement_sql = "select * from jdbc.t_emp where emp_name='" + name +"'";
        System.out.println(statement_sql);
        ResultSet rs = statement.executeQuery(statement_sql);
        //处理结果
        while (rs.next()) {
            int emp_id = rs.getInt("emp_id");
            String emp_name = rs.getString("emp_name");
            double emp_salary = rs.getDouble("emp_salary");
            int emp_age = rs.getInt("emp_age");
            System.out.println(emp_id + "\t" + emp_name + "\t" + emp_salary + "\t" + emp_age);
        }

        //6.释放资源
        rs.close();
        statement.close();
        conn.close();
    }
//执行结果
Please input your emp_name:
abc' or '1'='1
select * from jdbc.t_emp where emp_name='abc' or '1'='1'
1	edison	777.77	23
2	dizzy	888.88	24
3	tye	999.99	25
4	water	333.33	27
PreparedStatement
  • PreparedStatement是Statement接口的子接口,用于执行预编译的SQL查询,作用如下
    • 预编译SQL语句:在创建PreparedStatement时,会预编译SQL语句,也就是SQL语句已经固定
    • 防止SQL注入:PreparedStatement支持参数化查询,将数据作为参数传递到SQL语句中,采用?占位符的方式,将传入的参数用一对单引号包裹起来,无论传递什么都作为值,有效防止关键字或值导致SQL注入问题
    • 性能提升,PreparedStatement是预编译SQL语句,同一SQL语句多次执行的情况下,可以复用,不必每次重新编译和解析
    • 更安全和高效
public class JDBCPreparedStatement {
    public static void main(String[] args) throws SQLException {
        String url = "jdbc:mysql://192.168.29.201:3306/jdbc";
        String username = "root";
        String password = "Lotus!1120";
        Connection conn = DriverManager.getConnection(url, username, password);
        //获取执行SQL语句对象
        String statement_sql = "select * from jdbc.t_emp where emp_name=?";
        PreparedStatement statement = conn.prepareStatement(statement_sql);
        System.out.println("Please input your emp_name:");
        Scanner scanner = new Scanner(System.in);
        String name = scanner.nextLine();
        //为?占位符赋值,执行,接收返回结果集
        statement.setString(1,name);

        ResultSet rs = statement.executeQuery();
        //处理结果
        while (rs.next()) {
            int emp_id = rs.getInt("emp_id");
            String emp_name = rs.getString("emp_name");
            double emp_salary = rs.getDouble("emp_salary");
            int emp_age = rs.getInt("emp_age");
            System.out.println(emp_id + "\t" + emp_name + "\t" + emp_salary + "\t" + emp_age);
        }

        //6.释放资源
        rs.close();
        statement.close();
        conn.close();
    }
}
ResultSet
  • ResultSet是JDBC API中的一个接口,用于表示从数据库中执行查询语句返回的结果集,它提供了一种用于遍历和访问查询结果的方式
  • 遍历结果:ResultSet可以使用next()方法将游标移动到结果集的下一行,逐行遍历数据库查询的结果,返回值为boolean类型,true代表有下一行结果,false代表没有
  • 获取单列结果:可以通过getXXX方法获取单列的数据,该方法为重载方法,支持索引和列名进行获取
//基于junit对PreparedStatement进行测试,测试数据库的增、删、改、查
package com.lotus.base;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.sql.*;


public class JDBCOperation {
    private Connection conn;
    private PreparedStatement statement;
    private ResultSet rs;
    @Before
    public void init() throws SQLException {
        String url = "jdbc:mysql://192.168.29.201:3306/jdbc";
        String username = "root";
        String password = "Lotus!1120";
        conn = DriverManager.getConnection(url, username, password);
    }

    /**
     * 单行单列测试
     * @throws SQLException
     */
    @Test
    public void testQuerySingleRowAndColumn() throws SQLException {
        String statement_sql = "select count(*) as count from jdbc.t_emp";
        statement = conn.prepareStatement(statement_sql);

        rs = statement.executeQuery();
        //处理结果,如确认只有一行数据,需要做一次rs.next()的判断,才能拿到列的结果
        while (rs.next()) {
            System.out.println(rs.getInt(1));  //基于索引获取
            System.out.println(rs.getInt("count")); //基于列名获取
        }
    }
    /**
     * 获取单行多列数据
     * @throws SQLException
     */
    @Test
    public void testQuerySingleRowAndMultiCol() throws SQLException {
        String statement_sql = "select * from jdbc.t_emp where emp_id=?";
        statement = conn.prepareStatement(statement_sql);
        statement.setInt(1,2);

        rs = statement.executeQuery();
        //处理结果,如确认只有一行数据,需要做一次rs.next()的判断,才能拿到列的结果
        while (rs.next()) {
            int emp_id = rs.getInt("emp_id");
            String emp_name = rs.getString("emp_name");
            double emp_salary = rs.getDouble("emp_salary");
            int emp_age = rs.getInt("emp_age");
            System.out.println(emp_id + "\t" + emp_name + "\t" + emp_salary + "\t" + emp_age);
        }
    }
    /**
     * 获取多行多列数据
     * @throws SQLException
     */
    @Test
    public void testQueryMultiRowAndMultiCol() throws SQLException {
        String statement_sql = "select * from jdbc.t_emp where emp_age>?";
        statement = conn.prepareStatement(statement_sql);
        statement.setInt(1,23);
        rs = statement.executeQuery();
        //处理结果,如确认只有一行数据,需要做一次rs.next()的判断,才能拿到列的结果
        while (rs.next()) {
            int emp_id = rs.getInt("emp_id");
            String emp_name = rs.getString("emp_name");
            double emp_salary = rs.getDouble("emp_salary");
            int emp_age = rs.getInt("emp_age");
            System.out.println(emp_id + "\t" + emp_name + "\t" + emp_salary + "\t" + emp_age);
        }
    }
    /**
     * 新增数据
     * @throws SQLException
     */
    @Test
    public void testInsert() throws SQLException {
        String statement_sql = "insert into t_emp(emp_name,emp_salary,emp_age) values (?,?,?)";
        statement = conn.prepareStatement(statement_sql);
        statement.setString(1,"rose");
        statement.setDouble(2,111.11);
        statement.setInt(3,33);
        int result = statement.executeUpdate();
        //根据受影响行数判断是否成功
        if (result > 0) {
            System.out.println("Success");
        } else {
            System.out.println("Failure");
        }
    }
    /**
     * 更新数据
     * @throws SQLException
     */
    @Test
    public void testUpdate() throws SQLException {
        String statement_sql = "update t_emp set emp_salary = ? where emp_id = ?";
        statement = conn.prepareStatement(statement_sql);
        statement.setDouble(1,000.11);
        statement.setInt(2,2);
        int result = statement.executeUpdate();
        //根据受影响行数判断是否成功
        if (result > 0) {
            System.out.println("Success");
        } else {
            System.out.println("Failure");
        }
    }
    /**
     * 删除数据
     * @throws SQLException
     */
    @Test
    public void testDelete() throws SQLException {
        String statement_sql = "delete from t_emp where emp_id = ?";
        statement = conn.prepareStatement(statement_sql);
        statement.setDouble(1,5);
        int result = statement.executeUpdate();
        //根据受影响行数判断是否成功
        if (result > 0) {
            System.out.println("Success");
        } else {
            System.out.println("Failure");
        }
    }
    @After
    public void destory() throws SQLException {
        //6.释放资源
        if (rs != null) {
            rs.close();
        }
        if (statement != null) {
            statement.close();
        }
        if (conn != null) {
            conn.close();
        }

    }
}
常见问题
资源管理
  • 在使用JDBC相关资源时,如Connection,PreparedStatement,ResultSet,使用完毕后,要及时关闭这些资源以释放数据库服务器资源和避免内存泄漏
SQL语句问题
  • java.sql.SQLSyntaxErrorException:SQL语句错误异常,一般有几种情况
    • SQL语句错误,检查SQL语句!建议SQL语句在SQL工具中测试后再复制到Java程序中
    • 连接数据库的URL中,数据库名称编写错误,也会报该异常
SQL语句未设置参数问题
  • java.sql.SQLException:No value specified for parameter 1
    • 在使用预编译SQL语句时,如果有?占位符,要为每一个占位符赋值,否则报该错
用户名或密码错误
  • java.sql.SQLException: Access denied for user ‘root1’@‘192.168.29.1’ (using password: YES)
    • 连接数据库时,用户名或密码输入错误
通信异常
  • com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
    • 在连接数据库的URL中,如果IP或端口写错了,会报上述异常

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1806387.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Element-UI入门

目录 1.什么是Element-UI 2.作用 3.版本历史 4.优缺点 4.1.优点 4.2.缺点 5.应用场景 6.代码示例 7.未来展望 8.总结 1.什么是Element-UI Element-UI 是由饿了么前端团队开发的一套基于 Vue.js 的桌面端组件库。提供了一整套 UI 组件,使开发者能够快速构…

统信UOS1070上配置文件管理器默认属性01

原文链接:统信UOS 1070上配置文件管理器默认属性01 Hello,大家好啊!今天给大家带来一篇关于在统信UOS 1070上配置文件管理器默认属性的文章。文件管理器是我们日常操作系统使用中非常重要的工具,了解如何配置其默认属性可以极大地…

使用贝塞尔曲线实现一个iOS时间轴

UI效果 实现的思路 就是通过贝塞尔曲线画出时间轴的圆环的路径,然后 使用CAShaper来渲染UI,再通过 animation.beginTime [cilrclLayer convertTime:CACurrentMediaTime() fromLayer:nil] circleTimeOffset 来设置每个圆环的动画开始时间, …

手写kNN算法的实现-用余弦相似度来度量距离

设a为预测点,b为其中一个样本点,在向量空间里,它们的形成的夹角为θ,那么θ越小(cosθ的值越接近1),就说明a点越接近b点。所以我们可以通过考察余弦相似度来预测a点的类型。 from collections i…

【学术小白成长之路】03三方演化博弈(基于复制动态方程)均衡点与稳定性分析

从本专栏开始,笔者正式研究演化博弈分析,其中涉及到双方演化博弈分析,三方演化博弈分析,复杂网络博弈分析等等。 先阅读了大量相关的博弈分析的文献,总结了现有的研究常用的研究流程,针对每个流程进行拆解。…

HTML-CSS练习例子

HTML CSS 练习 https://icodethis.com 作为前端练习生。不敲代码只看,入门是很慢的,所以直接实战是学习前端最快的途径之一。 这个网站练习HTML CSS的,可以打开了解一下,可以每天打卡,例子简单,循序渐进&…

《TCP/IP网络编程》(第十三章)多种I/O函数(2)

使用readv和writev函数可以提高数据通信的效率,它们的功能可以概括为**“对数据进行整合传输及发送”**。 即使用writev函数可以将分散在多个缓冲中的数据一并发送,使用readv函数可以由多个缓冲分别接受,所以适当使用他们可以减少I/O函数的调…

Pytorch 实现目标检测一(Pytorch 23)

一 目标检测和边界框 在图像分类任务中,我们假设图像中只有一个主要物体对象,我们只关注如何识别其类别。然而,很多时候图像里有多个我们感兴趣的目标,我们不仅想知 道它们的类别,还想得到它们在图像中的具体位置。在…

ESP8266+STM32+阿里云保姆级教程(AT指令+MQTT)

前言:在开发过程中,几乎踩便了所有大坑小坑总结出的文章,我是把坑踩满了,帮助更过小白快速上手,如有错误之处,还麻烦各位大佬帮忙指正、 目录 一、ESP-01s介绍 1、ESP-01s管脚功能: 模组启动模…

vscode 突然无法启动 WSL terminal 了怎么办?

参考:https://github.com/microsoft/vscode/issues/107485 根据参考网页,似乎在 windows 更新之后,重启,就有可能出现标题所说的 vscode 无法启动 WSL terminal 的情况。 首先使用 cmd 进入 wsl 终端,把 ~/.vscode-se…

EON安装ASE Interface

EON安装 我的eon路径于/eon/。 则环境为 export PYTHONPATH/eon/:$PYTHONPATH export PATH/eon/bin:$PATHsource: https://theory.cm.utexas.edu/eon/installation.html ASE 测试系统ubuntu。如果你python2和python3总是纠缠不清,可以sudo apt install python-…

vscode中执行python语句dir(torch)不返回结果

输入半天,发现在IDLE运行后的shell界面输入语句就会返回一大串。但是在vscode中老是不返回值。 结果恍然发现这没加print()。 无语惨了。 家人们,这是python,而不是matlab。思维还没转换过来,笑死

扩散模型Stable Diffusion

扩散模型构成 Text Encoder(CLIPText) Clip Text为文本编码器。以77 token为输入,输出为77 token 嵌入向量,每个向量有768维度。 Diffusion(UNetScheduler) 在潜在空间中逐步处理扩散信息。以文本嵌入向量和由噪声组成的起始多维数组为输入&#xff0c…

二叉树—leetcode

前言 本篇博客我们来仔细说一下二叉树二叉树的一些OJ题目 请看完上一篇:数据结构-二叉树-CSDN博客 💓 个人主页:普通young man-CSDN博客 ⏩ 文章专栏:LeetCode_普通young man的博客-CSDN博客 若有问题 评论区见📝 &…

Zynq7000 系列FPGA模块化仪器

• 基于 XilinxXC7Z020 / 010 / 007S • 灵活的模块组合 • 易于嵌入的紧凑型外观结构 • 高性能的 ARM Cortex 处理器 • 成熟的 FPGA 可编程逻辑 ,基于 IP 核的软件库 FPGA 控制器 Zynq7000 系列模块是基于 Xilinx XC7Z020/010/007S 全可编程片上系统 (SoC) 的…

LLM的基础模型8:深入注意力机制

大模型技术论文不断,每个月总会新增上千篇。本专栏精选论文重点解读,主题还是围绕着行业实践和工程量产。若在某个环节出现卡点,可以回到大模型必备腔调或者LLM背后的基础模型新阅读。而最新科技(Mamba,xLSTM,KAN)则提…

[ue5]建模场景学习笔记(5)——必修内容可交互的地形,交互沙(3)

1.需求分析: 我们现在已经能够让这片地形出现在任意地方,只要角色走在这片地形上,就能够产生痕迹,但这片区域总是需要人工指定,又无法把这片区域无限扩大(显存爆炸),因此尝试使角色无…

【BUG】已解决:Could not find a version that satisfies the requirement tensorflow

已解决:Could not find a version that satisfies the requirement tensorflow 欢迎来到我的主页,我是博主英杰,211科班出身,就职于医疗科技公司,热衷分享知识,同时是武汉城市开发者社区主理人 擅长.net、C…

Java抽象队列同步器AQS

AQS介绍 AQS是一个抽象类,主要用来构建锁和同步器。 public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable { }AQS为构建锁和同步器提供了一些通用功能的实现,因此,使用…

基于STM32开发的智能语音助理系统

⬇帮大家整理了单片机的资料 包括stm32的项目合集【源码开发文档】 点击下方蓝字即可领取,感谢支持!⬇ 点击领取更多嵌入式详细资料 问题讨论,stm32的资料领取可以私信! 目录 引言环境准备智能语音助理系统基础代码实现&#xff…