首页 > 数据库 >JDBC中数据库的连接与查询

JDBC中数据库的连接与查询

时间:2024-11-15 09:19:06浏览次数:1  
标签:username JDBC String 数据库 查询 SQL password

让我们仔细看看是怎么访问数据库的

package sql;

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

public class Conn { // 创建类Conn
    Connection con; // 声明Connection对象
    public static String user;
    public static  String password;
    public Connection getConnection() { // 建立返回值为Connection的方法
        try { // 加载数据库驱动类
            Class.forName("com.mysql.cj.jdbc.Driver");
            System.out.println("数据库驱动加载成功");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        user = "root";//数据库登录名
        password = "root";//密码
        try { // 通过访问数据库的URL获取数据库连接对象
            con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=gbk", user, password);
            System.out.println("数据库连接成功");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return con; // 按方法要求返回一个Connection对象
    }
    public static void main(String[] args) { // 主方法,测试连接
        Conn c = new Conn(); // 创建本类对象
        c.getConnection(); // 调用连接数据库的方法
    }
}


具体用法

我们直接看下列的代码

package Main;

import java.sql.*;

public class JDBC {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
//        1.加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
//        2.用户信息和url
        String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=true";
        String username="root";
        String password="root";
//        3.连接成功,数据库对象 Connection
        Connection connection = DriverManager.getConnection(url,username,password);
//        4.执行SQL对象Statement,执行SQL的对象
        Statement statement = connection.createStatement();
//        5.执行SQL的对象去执行SQL,返回结果集
        String sql = "SELECT *FROM studentinfo;";
        ResultSet resultSet = statement.executeQuery(sql);
        while(resultSet.next()){
            System.out.println("SNo="+resultSet.getString("SNo"));
            System.out.println("SName="+resultSet.getString("SName"));
            System.out.println("Birth="+resultSet.getString("Birth"));
            System.out.println("SPNo="+resultSet.getString("SPNo"));
            System.out.println("Major="+resultSet.getString("Major"));
            System.out.println("Grade="+resultSet.getString("Grade"));
            System.out.println("SInstructor="+resultSet.getString("SInstructor"));
            System.out.println("SPwd="+resultSet.getString("SPwd"));
        }
//        6.释放连接
        resultSet.close();
        statement.close();
        connection.close();
    }
}


加载数据库类

Class.forName("com.mysql.cj.jdbc.Driver");是用来加载数据库驱动的。用于我们的 Java 程序与数据库通信。

Class.forName()函数的作用是用于动态加载一个类,其中的参数自然也是数据库的驱动类com.mysql.cj.jdbc.Driver

连接数据库

我们通常使用DriverManager.getConnection(url,username,passwd)方法来连接数据库,这里面需要我们填入三个参数:

  • url:数据库的URL,格式很重要

    • "jdbc:mysql":这是告诉程序使用 JDBC 驱动来连接 MySQL 数据库。

    • "localhost":指向本地计算机的数据库服务器。

    • "3306":MySQL 服务的默认端口号。

    • "test1":这是要访问的数据库名称。

    • ?useUnicode=true&characterEncoding=gbk:这些是查询参数,用于指定数据库的配置。它们表示:

    • useUnicode=true:启用 Unicode 支持,确保可以存储和读取 Unicode 字符。

    • characterEncoding=gbk:设置字符编码为 GBK,通常用于处理中文字符。

  • username:数据库的用户名

  • passwd :数据库的密码

实例化一个SQL对象Statement

这没啥好说的,就是实例化一个对象,以便于我们能调用其中的各种方法

执行SQL语句,查询数据库

查询

要执行数据库的查询我们直接使用executeQuery(String sql)方法,然后里面写入我们的sql语句就行,之后我们就能从返回值得到查询的结果了ResultSet resultSet = statement.executeQuery(sql);

结果

得到了一个ResultSet结果对象之后,想要的得到字符串直接使用getString()方法就行,除此之外还有getLong()getInt()等,就对应了其中的数据类型。

然后就是这些get方法的参数,有两种参数:

  • 列名称:就是你查询出来后,直接输入列表的名称就给你输出了查询的结果,名称的类型自然就是String类型的
  • 列索引:直接从中输入列的索引就会输入第几列的查询结果,但是注意!!!!这里的所以不再是从0开始,而是从1开始,这是非常值得注意的地方,所以的参数类型自然就是int了

释放链接

为了资源不要浪费,使用完了就应该直接释放了

        resultSet.close();
        statement.close();
        connection.close();

防止sql注入的改良

发现问题

又细心的人就会发现前面的代码使用Statement拼字符串非常容易引发SQL注入的问题。

什么是SQL注入呢?我们一般查询数据库靠着相对的命令来实现,如果SQL语句是靠要查的字符拼接出来的,一般是没有问题的,但是我们输入一些特定的字符的时候是可能会让sql语句去做其他的事情。总之SQL一般都是因为字符的拼接漏洞实现的。

解决问题

所以我们就得想办法去解决这个问题,有一个方法是转义特定的字符,但这终究是治标不治本的。

前面我们提到,最根本的问题是字符拼接带来的漏洞,如果我们不进行字符拼接,直接传递要查的字符,那问题就引刃而解了

Statement 换成 PreparedStatement可以完全避免SQL注入的问题,因为PreparedStatement始终使用?作为占位符,并且把数据连同SQL本身传给数据库,这样可以保证每次传给数据库的SQL语句是相同的,只是占位符的数据不同,还能高效利用数据库本身对查询的缓存。

//使用prepareStatement查询
try (Connection conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD)) {
    try (PreparedStatement ps = conn.prepareStatement("SELECT id, grade, name, gender FROM students WHERE gender=? AND grade=?")) {
        ps.setObject(1, "M"); // 注意:索引从1开始
        ps.setObject(2, 3);
        try (ResultSet rs = ps.executeQuery()) {
            while (rs.next()) {
                long id = rs.getLong("id");
                long grade = rs.getLong("grade");
                String name = rs.getString("name");
                String gender = rs.getString("gender");
            }
        }
    }
}
//使用Statement查询
try (Connection conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD)) {
    try (Statement stmt = conn.createStatement()) {
        try (ResultSet rs = stmt.executeQuery("SELECT id, grade, name, gender FROM students WHERE gender=1")) {
            while (rs.next()) {
                long id = rs.getLong(1); // 注意:索引从1开始
                long grade = rs.getLong(2);
                String name = rs.getString(3);
                int gender = rs.getInt(4);
            }
        }
    }
}

我们来看看这个例子,上面的是使用的prepareStatement,下面使用的是Statement。虽然两者之间没有太大的区别,但是还有值得我们注意的地方:

  • sql语句插入的函数不同,前者是在prepareStatement就已经插入,而后者是在executeQuery才插入
  • prepareStatement是需要使用setObject方法来指定我们查询的字符的,但是Statement是不用的,至于为什么不行我们后文再说
  • ResultSetnext() 方法用于 移动游标结果集中的下一行,返回的数据类型看代码无疑是一个 boolean

解决完问题带来的思考

我们从代码层面分析完成之后,我想很多人跟我有一样的提问,prepareStatement为什么能够做到防止SQL的注入,这里我们在稍微升入SQL注入一点,在详细剖析SQL注入是怎么完成的。

SQL注入的本质

SQL注入漏洞出现的原因就是用户的输入会直接嵌入到查询语句中,一旦出现精心设计的输入就会改变整个SQL语句的结构

比如现在有这样的语句

String query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";

如果输入了恶意的内容 username = "admin' --"

SELECT * FROM users WHERE username = 'admin' --' AND password = 'password';

后面输入的AND password = 'password';就直接被注释掉了,这样就会只查询前面的username = 'admin'

prepareStatement的防御原理

前面不是说了就是因为用户输入和查询语句不是分离的吗,那思路就很简单了,那将两者分离不就行了

占位符分离

在预编译阶段,SQL 查询的结构被解析并发送到数据库中,这时 占位符?)会被数据库视为参数的占位符,而不是 SQL 语句的一部分。

例如:

String query = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement ps = conn.prepareStatement(query);
ps.setString(1, username);
ps.setString(2, password);

在这里:

  • ? 是占位符,它在查询执行时被替换为实际的参数。
  • ps.setString(1, username)ps.setString(2, password) 将用户输入的值安全地绑定到查询中。
  • 在执行查询时,数据库知道 ? 只是占位符,它不会将用户输入作为 SQL 代码的一部分来解析,而是将其作为数据处理。

即使用户输入恶意的内容,例如:

  • username = "admin' OR 1=1 --"
  • password = "password"

构造的 SQL 查询也不会发生注入,因为数据库会将这些输入当作普通的字符串处理,而不会将其作为 SQL 语句的一部分。执行时的 SQL 查询将是:

SELECT * FROM users WHERE username = 'admin'' OR 1=1 --' AND password = 'password'

这个查询在数据库端仍然会被正确地作为两条字符串值传递,而不会被解析为恶意的 SQL 代码

自动转译用户输入

PreparedStatement 会自动转义参数中的特殊字符,如单引号(')等,使其在数据库中正确地作为字符串处理。这进一步防止了 SQL 注入攻击。

例如,如果用户输入的用户名是:

  • admin' --

PreparedStatement 会自动将这个字符串转义为:

  • 'admin'' --'

这样,即使用户输入恶意的内容,数据库也会将其作为普通字符串处理,而不会被当作 SQL 语句的一部分执行。

标签:username,JDBC,String,数据库,查询,SQL,password
From: https://www.cnblogs.com/ENchantedN/p/18547337

相关文章

  • 数据库表设计中的关系实现:多对多、一对多、一对一
    数据库表设计中的关系实现:多对多、一对多、一对一在数据库设计中,表之间的关系是构建高效、可维护数据模型的关键。理解并正确实现这些关系,对于确保数据的完整性和查询的效率至关重要。本文将详细探讨多对多、一对多和一对一关系的实现方式,并提供严谨的指导。1.多对多关系多对......
  • xshell上实现:MongoDB文档查询
    实验内容概述    本实验旨在了解MongoDB文档数据库的基本操作,包括创建集合、插入文档数据和执行文档查询操作。实验环境:Linux(Centos7)xshell7Mongodb实验目的理解MongoDB文档数据库的基本概念和特性。掌握在MongoDB中创建集合和插入文档数据的方法。学习使用Mongo......
  • MongoDB创建只读用户并授权指定集合的查询权限
    MongoDB创建只读用户并授权指定集合的查询权限创建测试数据usetestdbdb.test_t.insertOne({id:1,name:'zhangsan'});db.test_t.insertOne({id:2,name:'lisi'});db.test_t1.insertOne({id:1,name:'zhangsan'});db.test_t1.insertOne({id:2,name:'lisi'}......
  • Yashandb数据库YCM安装
    YashandbYCM安装到官网下载YCM软件:https://download.yashandb.com/download开机自启前提管理平台开机自启需要确保对rc.local有可执行权限,可执行以下命令:#chmod+x/etc/rc.local将软件包上传至yasmanager用户/home/yasmanager路径下:[root@yashanyasmanager]#ta......
  • MySQL数据库:SQL语言入门 【3】(学习笔记)
    5,TCL—— 事务控制语言(TransactionControlLanguage)     用于数据库的事务管理。(1)事务的概念+作用     事务(Transaction)指的是一个操作序列,该操作序列中的多个操作要么都做,要么都不做,是一个不可分割的工作单位,是数据库环境中的逻辑工作单位,由DBMS(数......
  • MySQL数据库:SQL语言入门 【2】(学习笔记)
    目录 2,DML—— 数据操作语言(DataManipulationLanguage)(1)insert  增加 数据(2)delete 删除 数据    truncate 删除表和数据,再创建一个新表(3)update 修改 数据3,DDL——数据定义语言(DataDefinitionLanguage)(1)create 创建数据库对象(2)drop 删除......
  • MySQL数据库:SQL语言入门 【1】(学习笔记)
    SQL(StructuredQueryLanguage)是结构化查询语言的简称,它是一种数据库查询和程序设计语言,同时也是目前使用最广泛的关系型数据库操作语言。(95%适用于所有关系型数据库)【 SQL是关系型数据库通用的操作语言】在数据库管理系统中,使用SQL语言来实现数据的存取、查询、更新等功能......
  • windows C#-查询表达式基础(一)
    查询是什么及其作用是什么?查询是一组指令,描述要从给定数据源(或源)检索的数据以及返回的数据应具有的形状和组织。查询与它生成的结果不同。通常情况下,源数据按逻辑方式组织为相同类型的元素的序列。例如,SQL数据库表包含行的序列。在XML文件中,存在XML元素的“序列”(......
  • DBeaver如何设置自动刷新数据库表的数据,彻底解放双手!
    前言大家好,我是小徐啊。DBeaver是一款常用的数据库连接工具,它的优点是免费使用,而且支持的数据库类型超级多,甚至可以直接安装数据库对应的驱动jar包来连接数据库。比如达梦数据库,之前版本是可以通过jar包方式设置驱动来连接达梦数据库的。好了,言归正传,今天小徐要介绍一个DBeaver......
  • 性能测试之JDBC连接、分布式负载
    一、JmeterJDBC连接Jmeter支持连接数据库,对SQL语句进行性能测试,JDBCConnetctionConfiguration用来配置连接信息。1、把JDBC驱动的jar包引入测试计划Jmeter要连接mysql数据库,首先得下载mysqljdbc驱动包,这里使用的是mysql-connector-java-5.1.7-bin.jar选择测试计划——......