小菜鸟

java菜鸟号正在起航

JDBC 元数据获取详解:探索数据库与结果集的底层信息

在 JDBC 编程中,除了执行 SQL 操作获取业务数据外,有时还需要获取数据库本身的信息(如数据库版本、支持的功能)或结果集的结构(如列名、数据类型)。这些描述数据的数据称为元数据(Metadata)。JDBC 提供了 DatabaseMetaDataResultSetMetaData 两个核心接口,分别用于获取数据库元数据和结果集元数据。本文将详细讲解这两种元数据的获取与应用。

数据库元数据(DatabaseMetaData)

DatabaseMetaData 接口用于描述数据库的整体信息,通过 Connection.getMetaData() 方法获取,可获取数据库产品名称、版本、支持的 SQL 特性、表结构等底层信息。

核心方法与示例

(1)获取数据库基本信息
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;

public class DatabaseMetaDataDemo {
    public static void main(String[] args) {
        try (Connection conn = JDBCUtil.getConnection()) { // 自定义连接工具类
            // 获取数据库元数据对象
            DatabaseMetaData metaData = conn.getMetaData();

            // 1. 数据库产品信息
            String productName = metaData.getDatabaseProductName(); // 如 "MySQL"
            String productVersion = metaData.getDatabaseProductVersion(); // 如 "8.0.30"
            int majorVersion = metaData.getDatabaseMajorVersion(); // 主版本号,如 8
            int minorVersion = metaData.getDatabaseMinorVersion(); // 次版本号,如 0

            // 2. JDBC 驱动信息
            String driverName = metaData.getDriverName(); // 如 "MySQL Connector/J"
            String driverVersion = metaData.getDriverVersion(); // 如 "8.0.30"
            int driverMajor = metaData.getDriverMajorVersion(); // 驱动主版本
            int driverMinor = metaData.getDriverMinorVersion(); // 驱动次版本

            // 3. 连接信息
            String userName = metaData.getUserName(); // 连接数据库的用户名
            String url = metaData.getURL(); // 数据库连接 URL

            // 打印信息
            System.out.println("数据库产品:" + productName + " " + productVersion);
            System.out.println("数据库版本:" + majorVersion + "." + minorVersion);
            System.out.println("JDBC 驱动:" + driverName + " " + driverVersion);
            System.out.println("连接用户:" + userName + ",URL:" + url);

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

输出示例(MySQL)

数据库产品:MySQL 8.0.30
数据库版本:8.0
JDBC 驱动:MySQL Connector/J 8.0.30
连接用户:root@localhost,URL:jdbc:mysql://localhost:3306/test
(2)获取数据库中的表和 schema

DatabaseMetaData 提供了获取数据库中表、视图、列等结构信息的方法,返回 ResultSet 结果集:

阅读全文 »

JDBC 详解:Java 数据库连接的核心操作

JDBC(Java Database Connectivity)是 Java 访问数据库的标准接口,它定义了一套独立于特定数据库管理系统(DBMS)的 API,使 Java 程序能够通过统一的方式操作各种关系型数据库(如 MySQL、Oracle、SQL Server 等)。本文将详细讲解 JDBC 的核心概念、连接步骤及常用操作,帮助你掌握 Java 与数据库交互的基础。

JDBC 核心组件

JDBC 主要通过以下接口和类实现数据库交互:

组件 作用描述
Driver 数据库驱动接口,由各数据库厂商实现(如 MySQL 的 com.mysql.jdbc.Driver)。
DriverManager 驱动管理类,负责注册驱动、创建数据库连接。
Connection 数据库连接接口,代表与数据库的会话,用于创建执行 SQL 的对象。
Statement 执行静态 SQL 语句的接口,存在 SQL 注入风险。
PreparedStatement 预编译 SQL 语句的接口,可防止 SQL 注入,性能更优。
ResultSet 结果集接口,存储查询返回的数据,提供遍历和获取数据的方法。

JDBC 连接数据库的步骤

使用 JDBC 操作数据库的核心步骤可概括为:加载驱动 → 建立连接 → 执行 SQL → 处理结果 → 释放资源

准备工作

  • 引入数据库驱动:根据数据库类型添加对应的驱动 JAR 包(如 MySQL 驱动 mysql-connector-java)。

  • 创建数据库和表:以 MySQL 为例,创建测试表user:

    CREATE TABLE user (
        id INT PRIMARY KEY AUTO_INCREMENT,
        name VARCHAR(50) NOT NULL
    ) ENGINE = InnoDB DEFAULT CHARSET = utf8;

加载驱动与建立连接

(1)核心参数定义
阅读全文 »

加密算法简介

加密算法是保障信息安全的核心技术,根据加密密钥与解密密钥的关系,可分为对称加密算法非对称加密算法两大类。以下介绍几种常见的加密算法:

对称加密算法(Symmetric Encryption)

对称加密算法的特点是加密和解密使用相同的密钥,运算速度快,适合处理大量数据。

AES(Advanced Encryption Standard,高级加密标准)

  • 地位:目前应用最广泛的对称加密算法,是美国联邦政府采用的标准,替代了 DES。
  • 特点:
    • 支持多种密钥长度:128 位、192 位、256 位,密钥长度越长,安全性越高(256 位安全性最高)。
    • 加密效率高,适合加密大文件或实时通信数据(如 HTTPS 的对称加密阶段、文件加密等)。
    • 分组加密:将数据分成固定长度的块(128 位)进行加密,采用迭代加密方式。
  • 应用场景:数据库加密、本地文件加密、SSL/TLS 会话中的数据传输加密等。

DES(Data Encryption Standard,数据加密标准)

  • 地位:早期广泛使用的对称加密算法,后因安全性不足被 AES 替代。
  • 特点:
    • 密钥长度为 56 位(实际存储为 64 位,含 8 位校验位),密钥长度过短,容易被暴力破解。
    • 分组加密:以 64 位为分组对数据加密。
  • 局限性:随着计算能力提升,56 位密钥已无法满足安全需求,目前已基本被淘汰,仅在一些 legacy 系统中存在。
  • 衍生算法:3DES(Triple DES),通过三次 DES 加密提高安全性,但效率较低,逐渐被 AES 取代。
阅读全文 »

HDFS DataNode 工作机制:数据怎么存、状态怎么报、坏了怎么办

DataNode 是 HDFS 里真正存数据的节点。NameNode 管”账本”,DataNode 管”货”。

但它不只是”存”就完了——还要定期向 NameNode 报平安、汇报自己手里有哪些数据块、自己检查数据有没有坏。这套机制保证了 HDFS 在廉价硬件上仍然可靠。

DataNode 的三大职责

职责 具体工作
存数据 把 Block 以文件形式存在本地磁盘上
报状态 定期告诉 NameNode “我活着”、”我手里有这些块”
自检 检查自己存的数据有没有损坏,坏了就上报

启动阶段:注册 + 第一次汇报

sequenceDiagram  
    participant DN[DataNode]  
    participant NN[NameNode]  
    DN->>NN: 发送注册请求(包含节点 ID、存储目录等信息)  
    NN->>DN: 验证注册信息,返回注册成功响应  
    DN->>DN: 扫描本地存储目录,收集所有数据块信息(Block ID、大小、校验和)  
    DN->>NN: 发送完整块报告(Block Report),包含所有块的元数据  
    NN->>DN: 确认块报告,更新集群块映射信息  
    Note over DN,NN: 初始化完成,DataNode 进入常态运行

DataNode 启动时做三件事:

1. 注册

向 NameNode 发送注册请求,包含节点 ID 和存储目录信息。NameNode 验证通过后,DataNode 正式加入集群。

DataNode 的节点 ID 存在本地文件里(dfs.datanode.data.dir/current/VERSION),每次启动用同一个 ID,避免 NameNode 把它当成新节点。

阅读全文 »

HDFS NameNode 工作机制:元数据到底是怎么存的?启动时发生了什么?

NameNode 是 HDFS 的大脑,但它不存数据,只存”账本”——文件在哪个目录、权限是什么、分成了几个块、每个块在哪些 DataNode 上。

这个账本要是丢了,整个集群就废了。所以 NameNode 的元数据管理是 HDFS 最核心的机制之一。

元数据为什么既要存内存,又要存磁盘?

NameNode 的元数据需要满足两个矛盾的要求:

  • 要快:每次文件操作都要查元数据,必须放在内存里
  • 要稳:节点挂了内存数据就没了,必须持久化到磁盘

所以 NameNode 的元数据分三份:

存储位置 内容 作用
内存 完整的目录树、文件属性、块映射 快速响应客户端请求
FsImage(磁盘) 某一时刻的元数据快照 持久化全量备份
Edits(磁盘) 操作日志(增量) 记录 FsImage 之后的所有变更

关键理解:内存元数据 = FsImage + Edits 里所有操作。

FsImage:全量快照,但”块在哪”不存

FsImage 是元数据的全量快照文件,存的是某个时刻的文件系统状态。

但注意:FsImage 不存”每个块在哪个 DataNode 上”。 块的位置信息由 DataNode 启动时通过块报告上报给 NameNode,维护在内存中,不持久化到 FsImage。

怎么查看 FsImage 内容?

FsImage 是二进制文件,用 hdfs oiv 转成可读格式:

# 语法:hdfs oiv -p <格式> -i <FsImage文件> -o <输出文件>  
hdfs oiv -p XML -i /hadoop/hdfs/name/current/fsimage_xxx -o ~/fsimage.xml

转换后能看到目录结构、文件属性、块 ID 和大小,但看不到块在哪个节点。

<inode path="/testHdfs" type="DIRECTORY">  
  <id>16385</id>  
  <permissions>zhanghe:supergroup:rwxr-xr-x</permissions>  
  <modificationTime>1623523456789</modificationTime>  
</inode>  
<inode path="/testHdfs/data.txt" type="FILE">  
  <id>16386</id>  
  <replication>3</replication>  
  <modificationTime>1623523467890</modificationTime>  
  <block>  
    <id>1073741825</id>  
    <genstamp>1001</genstamp>  
    <numBytes>134217728</numBytes>  <!-- 128MB 块 -->  
  </block>  
</inode>

Edits:操作日志,实时追加

Edits 记录每一次元数据变更操作——创建文件、删除目录、修改权限、设置副本数。

写入流程:

  1. 客户端发起元数据修改操作
  2. NameNode 先把操作追加到 Edits 文件(磁盘)
  3. 再更新内存中的元数据
  4. 返回客户端成功

为什么先写 Edits 再更新内存? 如果先更新内存再写 Edits,写磁盘失败时内存已改但磁盘没记,数据不一致。先写磁盘保证了操作被持久化,即使后续内存更新失败也能恢复。

怎么查看 Edits 内容?

# 语法:hdfs oev -p <格式> -i <Edits文件> -o <输出文件>  
hdfs oev -p XML -i /hadoop/hdfs/name/current/edits_xxx -o ~/edits.xml

能看到每次操作的类型、路径、时间戳等。

<RECORD>  
  <OPCODE>OP_CREATE</OPCODE>  <!-- 创建文件操作 -->  
  <DATA>  
    <PATH>/testHdfs/newfile.txt</PATH>  
    <TIMESTAMP>1623523500000</TIMESTAMP>  
    <PERMISSIONS>0644</PERMISSIONS>  
    <REPLICATION>3</REPLICATION>  
  </DATA>  
</RECORD>

Edits 会无限增长,需要定期合并

Edits 不断追加,如果永远不合并,NameNode 启动时就要 replay 几个月甚至几年的操作日志,启动时间会变得不可接受。

解决方案:Secondary NameNode 定期合并 FsImage 和 Edits,生成新的 FsImage,然后 Edits 重置为空。

FsImage(旧快照)+ Edits(增量操作)→ 合并 → 新 FsImage(最新状态)
阅读全文 »
0%