资讯动态

Java纯JDBC连接数据库:用main方法快速打印表数据

发布时间:2026/10/22 11:53:22 来源:尧图企业网站定制
1. 为什么一个Main方法就够用了很多人第一次接触数据库编程脑子里冒出来的第一个念头就是我得搭个框架。Spring Boot、MyBatis、Hibernate恨不得把整个生态圈都搬进来。结果光是配置文件就写了两个小时最后连一条SELECT * FROM user都没跑通。我见过太多这样的场景了尤其是刚入门的同学总觉得不搞点企业级的东西就对不起自己写的代码。但实际情况是如果你只是想验证一下数据库连接是否正常、想快速看看某张表里到底存了什么数据、或者想给非技术同事演示一下数据是怎么从库里取出来的一个带main方法的Java类加上一个JDBC驱动包五分钟就能搞定。不需要Maven不需要Gradle甚至不需要IDE——记事本加命令行就能跑。这篇文章要聊的就是这件事用最朴素的方式写一个Java类的main方法通过JDBC连接数据库把表里的内容打印到控制台上。听起来简单但里面有不少细节值得说清楚。比如驱动包怎么选、URL怎么写、ResultSet怎么遍历、中文乱码怎么处理、资源怎么释放才不会导致连接泄漏。这些东西在框架里都被封装好了你根本不用操心但一旦脱离框架每一个都是坑。适合谁看如果你是Java初学者正在学JDBC但不知道怎么下手或者你是一个有经验的开发者临时需要写个小工具从数据库捞点数据又或者你在做代码审查时发现同事写了个裸奔的JDBC代码想看看有没有问题——这篇内容都能给你一些参考。我个人的习惯是不管项目最终用不用框架在前期调研阶段一定会先写一个纯JDBC的main方法来探路。因为框架帮你屏蔽了太多细节一旦出问题你连从哪儿查起都不知道。而裸写JDBC虽然麻烦但每一步都是透明的出了问题一眼就能定位。2. 动手之前先把这几样东西备齐2.1 JDK和数据库的版本匹配问题先说JDK。JDBC是Java标准库的一部分从JDK 1.1开始就有了所以理论上你装任何版本的JDK都能用。但实际开发中我建议至少用JDK 8以上。原因很简单JDK 8引入了try-with-resources语法可以自动关闭Connection、Statement、ResultSet这些资源省去了大量finally块里的手动关闭代码。如果你还在用JDK 7甚至更早的版本那代码写起来会啰嗦很多。数据库这边我用得比较多的是MySQL和PostgreSQL。两者的JDBC用法大同小异主要区别在驱动类名和URL格式上。下面这张表是我整理的常见数据库对应的驱动信息你可以直接对照着用数据库类型驱动类名URL格式模板MySQL 8.xcom.mysql.cj.jdbc.Driverjdbc:mysql://主机:端口/库名?参数MySQL 5.xcom.mysql.jdbc.Driverjdbc:mysql://主机:端口/库名?参数PostgreSQLorg.postgresql.Driverjdbc:postgresql://主机:端口/库名Oracleoracle.jdbc.OracleDriverjdbc:oracle:thin:主机:端口:SIDSQL Servercom.microsoft.sqlserver.jdbc.SQLServerDriverjdbc:sqlserver://主机:端口;databaseName库名注意MySQL 8和MySQL 5的驱动类名是不一样的。MySQL 8用的是com.mysql.cj.jdbc.Driver多了一个cj代表Connector/J。如果你用MySQL 8的数据库但加载了5.x的驱动类会直接报ClassNotFoundException。反过来用5.x的数据库加载8.x的驱动类虽然不一定报错但可能会有兼容性问题。这个坑我在早期项目中踩过当时本地是MySQL 5.7服务器上升级到了8.0代码没改部署上去就挂了。2.2 驱动包的获取与引入方式驱动包就是一个jar文件。MySQL的驱动包叫mysql-connector-java-x.x.x.jar8.0以后改名叫mysql-connector-j-x.x.x.jarPostgreSQL的叫postgresql-x.x.x.jar。你可以从数据库官网或者Maven中央仓库下载。引入方式有两种。一种是在IDE里把jar添加到项目的classpath中这个每个IDE的操作不太一样但基本都是在Project Structure或者Build Path里找到Add External JARs之类的选项。另一种更原始的方式是直接用命令行编译和运行通过-cp参数指定classpathjavac -cp .;mysql-connector-j-8.0.33.jar JdbcDemo.java java -cp .;mysql-connector-j-8.0.33.jar JdbcDemoWindows下classpath分隔符是分号;Linux和Mac下是冒号:。这个细节很容易忽略尤其是你在Windows上写完代码拿到Linux服务器上跑的时候忘了改分隔符就会报ClassNotFoundException。提示如果你用Maven管理项目直接在pom.xml里加依赖就行不需要手动下载jar包。但既然这篇文章讲的是最朴素的方式我们就假设你没有用构建工具。2.3 数据库连接信息的准备你需要知道四个东西主机地址、端口号、数据库名、用户名和密码。本地开发的话主机一般是localhost或127.0.0.1MySQL默认端口是3306PostgreSQL默认是5432。我建议在写代码之前先用数据库自带的客户端工具比如MySQL Workbench或者命令行客户端确认一下能正常连接并且目标表里确实有数据。这一步看起来多余但实际上能帮你排除掉一半的问题。因为如果数据库本身就连不上你写再多Java代码也没用。另外提前确认一下目标表的字段名和类型。比如你有一张user表里面有idint、namevarchar、emailvarchar三个字段那打印的时候就要按这个顺序来取。如果字段名拼错了运行时会报Column xxx not found。3. 从零写一个能跑的JDBC Demo3.1 加载驱动Class.forName还是SPI自动加载最早的JDBC写法里第一步必须是Class.forName(com.mysql.jdbc.Driver)。这行代码的作用是把驱动类加载到JVM里触发它的静态代码块从而向DriverManager注册自己。但从JDBC 4.0JDK 6开始Java引入了SPIService Provider Interface机制。驱动包的META-INF/services/java.sql.Driver文件里会声明驱动类名DriverManager会自动加载它。所以理论上你不需要再写Class.forName了。那到底写不写我的建议是写。原因有两个。第一显式加载驱动能让代码的意图更清晰别人一看就知道你用的是哪个数据库的驱动。第二在某些特殊的类加载器环境下比如OSGi容器或者某些应用服务器SPI自动加载可能会失效显式加载更保险。Class.forName(com.mysql.cj.jdbc.Driver);这行代码会抛出一个ClassNotFoundException所以你得用try-catch包起来或者在方法签名上声明throws。在main方法里我一般直接throws Exception省事。3.2 获取连接URL参数的讲究获取连接的标准写法是Connection conn DriverManager.getConnection(url, username, password);URL的写法有很多讲究。以MySQL 8为例一个完整的URL长这样jdbc:mysql://localhost:3306/testdb?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8allowPublicKeyRetrievaltrue这里面的参数每一个都有用useSSLfalseMySQL 8默认要求SSL连接本地开发没配SSL的话会报错。加上这个参数可以关闭SSL。serverTimezoneAsia/ShanghaiMySQL 8的时区设置变了不指定的话可能会报时区错误或者存进去的时间差8小时。characterEncodingutf8指定字符编码防止中文乱码。allowPublicKeyRetrievaltrueMySQL 8的密码认证插件变了不加这个参数可能会报Public Key Retrieval is not allowed。这些参数在MySQL 5里大部分都不需要但加上也不会有问题除了allowPublicKeyRetrieval在5.x里不识别但会被忽略。所以我一般写一个通用的URL模板换数据库的时候只改主机和库名。PostgreSQL的URL相对简单jdbc:postgresql://localhost:5432/testdb中文乱码问题在PostgreSQL里一般不需要额外处理因为它的默认编码就是UTF-8。3.3 执行查询与遍历结果集拿到Connection之后创建Statement执行查询拿到ResultSetStatement stmt conn.createStatement(); ResultSet rs stmt.executeQuery(SELECT id, name, email FROM user); while (rs.next()) { int id rs.getInt(id); String name rs.getString(name); String email rs.getString(email); System.out.println(id | name | email); }rs.next()方法返回一个布尔值表示是否还有下一行数据。一开始游标指向第一行之前调用next()之后游标下移一行如果这一行有数据就返回true。取值的时候可以用字段名也可以用字段的索引从1开始。用字段名可读性更好但性能稍微差一点点因为每次都要查找字段名对应的索引。对于控制台打印这种场景性能完全不是问题所以用字段名就行。这里有一个细节getInt、getString这些方法如果你取的字段在结果集中不存在会抛SQLException。如果你取的字段值是NULLgetInt会返回0getString会返回null。所以如果你需要区分0和NULL得用rs.wasNull()来判断。3.4 资源释放try-with-resources的正确姿势资源释放是JDBC里最容易出问题的地方。Connection、Statement、ResultSet都是需要显式关闭的。如果不关连接会一直占着时间长了连接池就满了应用就挂了。在JDK 7之前标准的写法是在finally块里逐个关闭而且关闭顺序要和创建顺序相反Connection conn null; Statement stmt null; ResultSet rs null; try { conn DriverManager.getConnection(url, user, password); stmt conn.createStatement(); rs stmt.executeQuery(sql); // 处理结果集 } catch (SQLException e) { e.printStackTrace(); } finally { if (rs ! null) try { rs.close(); } catch (SQLException e) {} if (stmt ! null) try { stmt.close(); } catch (SQLException e) {} if (conn ! null) try { conn.close(); } catch (SQLException e) {} }这种写法又臭又长而且容易漏掉某个资源的关闭。JDK 7之后有了try-with-resources代码可以简化成这样try (Connection conn DriverManager.getConnection(url, user, password); Statement stmt conn.createStatement(); ResultSet rs stmt.executeQuery(sql)) { while (rs.next()) { // 处理结果集 } } catch (SQLException e) { e.printStackTrace(); }只要资源实现了AutoCloseable接口就可以放在try的括号里JVM会自动帮你关闭而且关闭顺序也是自动反过来的。Connection、Statement、ResultSet都实现了这个接口所以可以放心用。注意try-with-resources里资源的关闭顺序是后创建的先关闭也就是rs先关然后stmt最后conn。这个顺序是正确的因为ResultSet依赖于StatementStatement依赖于Connection。4. 跑起来之后才会遇到的真实问题4.1 中文乱码的三种可能原因代码写完了一跑发现控制台打印出来的中文全是问号或者乱码。这个问题太常见了我几乎每次在新环境里跑JDBC都会遇到。原因可能出在三个地方第一种数据库表的字符集不对。如果建表的时候没有指定字符集MySQL默认可能是latin1。这种情况下存进去的中文本身就是乱码取出来当然也是乱码。解决办法是建表时指定CHARACTER SET utf8mb4或者用ALTER TABLE修改。第二种连接URL没有指定编码。就是前面说的characterEncodingutf8参数。如果不加JDBC驱动可能会用操作系统的默认编码来解析数据Windows中文版默认是GBK和数据库的UTF-8对不上就会乱码。第三种控制台本身的编码不对。这个最容易被忽略。Java程序输出的字符编码取决于file.encoding系统属性而控制台的显示编码取决于终端设置。如果两者不一致即使数据本身没问题显示出来也是乱码。可以在运行的时候加-Dfile.encodingUTF-8参数来指定java -Dfile.encodingUTF-8 -cp .;mysql-connector-j-8.0.33.jar JdbcDemo在Windows的cmd里还需要先用chcp 65001把控制台切换到UTF-8编码。不过说实话Windows cmd对UTF-8的支持一直不太好我一般直接用PowerShell或者Git Bash省心很多。4.2 驱动版本不匹配引发的连锁反应前面提过MySQL 8和5的驱动类名不一样但实际影响远不止ClassNotFoundException这么简单。我遇到过一次比较诡异的情况用MySQL 8的驱动连MySQL 5.7的数据库连接能建立简单查询也能跑但一执行带参数的PreparedStatement就报错。查了半天才发现是驱动版本和数据库版本不兼容。所以我的经验是驱动版本尽量和数据库版本保持一致。数据库是MySQL 8.0.x驱动就用8.0.x数据库是5.7驱动就用5.1.x。不要想着用新驱动兼容老数据库虽然大部分情况下没问题但一旦出问题就很难排查。另外如果你用的是Maven注意依赖的scope。JDBC驱动一般用runtimescope就行因为编译的时候只需要java.sql包里的接口不需要具体的驱动类。但如果你在代码里显式写了Class.forName(com.mysql.cj.jdbc.Driver)那就需要compilescope否则编译不过。4.3 连接超时和网络问题本地开发的时候数据库就在本机连接基本都是秒连。但如果你连的是远程数据库就可能会遇到连接超时的问题。默认情况下DriverManager.getConnection没有超时限制如果网络不通程序会一直卡在那里。解决办法是在URL里加连接超时参数jdbc:mysql://远程主机:3306/testdb?connectTimeout5000socketTimeout10000connectTimeout是建立连接的超时时间毫秒socketTimeout是读写数据的超时时间。加上这两个参数之后如果网络有问题程序会在5秒后抛出SQLException而不是无限等待。还有一个常见问题是防火墙。有些云数据库默认只允许特定IP访问如果你的IP不在白名单里连接会被拒绝。这种情况下报的错一般是Communications link failure或者Connection refused。遇到这种错误先检查网络连通性用telnet或者ping再检查防火墙和白名单设置。4.4 大数据量下的内存溢出如果你要打印的表有几十万行数据用Statement.executeQuery一次性把所有结果加载到内存里很可能会OutOfMemoryError。因为MySQL的JDBC驱动默认会把整个结果集读到内存里。解决办法有两个。一是使用流式查询在Statement上设置fetchSizestmt.setFetchSize(Integer.MIN_VALUE);MySQL驱动对Integer.MIN_VALUE有特殊处理会启用流式读取每次只从服务器取一行。但要注意流式读取期间不能在同一连接上执行其他查询否则会报错。二是分页查询用LIMIT和OFFSET分批取SELECT id, name, email FROM user LIMIT 1000 OFFSET 0; SELECT id, name, email FROM user LIMIT 1000 OFFSET 1000;分页查询的好处是不依赖特定驱动的实现通用性更好。缺点是需要执行多次查询而且如果数据在查询过程中发生了变化可能会有重复或遗漏。对于控制台打印这种场景分页查询完全够用了。5. 把代码写得像个样子5.1 配置信息不要硬编码最原始的写法是把URL、用户名、密码直接写在代码里String url jdbc:mysql://localhost:3306/testdb; String user root; String password 123456;这种写法在demo里没问题但如果你把代码提交到代码仓库密码就泄露了。而且换一个环境就要改代码、重新编译很麻烦。更好的做法是把配置信息放到外部文件里比如db.propertiesdb.urljdbc:mysql://localhost:3306/testdb?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8 db.userroot db.password123456 db.drivercom.mysql.cj.jdbc.Driver然后用Properties类加载Properties props new Properties(); try (InputStream in JdbcDemo.class.getClassLoader().getResourceAsStream(db.properties)) { props.load(in); } String url props.getProperty(db.url); String user props.getProperty(db.user); String password props.getProperty(db.password);这样换环境的时候只需要改配置文件不需要动代码。而且可以把db.properties加到.gitignore里避免密码泄露。5.2 把重复代码抽成方法如果每次查询都要写一遍加载驱动、获取连接、创建Statement、遍历结果集的代码那也太累了。可以把这些重复的逻辑抽成方法public static void printTable(String sql) throws Exception { Properties props loadConfig(); String url props.getProperty(db.url); String user props.getProperty(db.user); String password props.getProperty(db.password); try (Connection conn DriverManager.getConnection(url, user, password); Statement stmt conn.createStatement(); ResultSet rs stmt.executeQuery(sql)) { ResultSetMetaData meta rs.getMetaData(); int columnCount meta.getColumnCount(); // 打印表头 for (int i 1; i columnCount; i) { System.out.print(meta.getColumnName(i) \t); } System.out.println(); // 打印数据 while (rs.next()) { for (int i 1; i columnCount; i) { System.out.print(rs.getString(i) \t); } System.out.println(); } } }这里用到了ResultSetMetaData可以动态获取列名和列数不需要提前知道表的结构。这样不管查哪张表都能自动打印出表头和内容。5.3 用PreparedStatement防止SQL注入虽然控制台打印这种场景不太涉及SQL注入但养成用PreparedStatement的习惯是好的。而且PreparedStatement还有预编译的优势执行多次相同结构的SQL时性能更好。String sql SELECT id, name, email FROM user WHERE name LIKE ?; try (PreparedStatement pstmt conn.prepareStatement(sql)) { pstmt.setString(1, %张%); try (ResultSet rs pstmt.executeQuery()) { while (rs.next()) { // 处理结果 } } }注意PreparedStatement的占位符是从1开始编号的不是从0开始。这个和数组索引不一样刚开始用的时候容易搞混。5.4 格式化输出让结果更易读直接System.out.println打印出来的内容列与列之间对不齐看起来很难受。可以用String.format来格式化System.out.printf(%-5s %-20s %-30s%n, ID, NAME, EMAIL); while (rs.next()) { System.out.printf(%-5d %-20s %-30s%n, rs.getInt(id), rs.getString(name), rs.getString(email)); }%-5s表示左对齐占5个字符宽度。%n是平台无关的换行符。这样打印出来的表格整齐多了。如果字段内容太长还可以截断String name rs.getString(name); if (name ! null name.length() 20) { name name.substring(0, 17) ...; }6. 几个容易被忽略的细节6.1 NULL值的处理数据库里的NULL和Java里的null不是一回事。rs.getInt(id)如果字段是NULL返回的是0而不是null。如果你需要区分0和NULL得用rs.wasNull()int id rs.getInt(id); if (rs.wasNull()) { System.out.print(NULL); } else { System.out.print(id); }对于字符串字段rs.getString返回的就是null直接打印会输出null这个字符串。如果你希望输出空字符串可以加个判断String name rs.getString(name); System.out.print(name null ? : name);6.2 日期和时间的格式化rs.getDate返回的是java.sql.Daters.getTimestamp返回的是java.sql.Timestamp。直接打印的话格式不太好看可以用SimpleDateFormat或者DateTimeFormatter来格式化Timestamp ts rs.getTimestamp(create_time); SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd HH:mm:ss); System.out.print(sdf.format(ts));注意java.sql.Date只包含日期部分时分秒会被截断。如果需要完整的时间信息用getTimestamp。6.3 大字段的处理如果表里有TEXT或BLOB这样的大字段直接getString可能会占用大量内存。对于TEXT字段可以用getCharacterStream返回一个Reader然后逐块读取Reader reader rs.getCharacterStream(content); char[] buffer new char[1024]; int len; while ((len reader.read(buffer)) ! -1) { System.out.print(new String(buffer, 0, len)); }对于BLOB字段用getBinaryStream返回InputStream。不过控制台打印二进制数据没什么意义一般只是打印一下长度或者前几个字节。6.4 事务的自动提交JDBC默认是自动提交模式每执行一条SQL就自动提交一次。对于只读查询来说这没什么影响。但如果你在main方法里既查询又更新可能就需要手动控制事务conn.setAutoCommit(false); try { // 执行多条SQL conn.commit(); } catch (Exception e) { conn.rollback(); throw e; } finally { conn.setAutoCommit(true); }不过对于打印数据库表内容这个场景一般不需要考虑事务保持默认的自动提交就行。7. 从Demo到小工具的进化7.1 支持命令行参数如果每次想查不同的表都要改代码、重新编译那也太麻烦了。可以改成从命令行参数接收表名public static void main(String[] args) throws Exception { if (args.length 0) { System.out.println(用法: java JdbcDemo 表名); return; } String tableName args[0]; String sql SELECT * FROM tableName; printTable(sql); }这样运行的时候就可以指定表名了java -cp .;mysql-connector-j-8.0.33.jar JdbcDemo user注意直接拼接表名到SQL里有SQL注入风险但这是本地小工具表名是使用者自己输入的风险可控。如果是在生产环境一定要用白名单校验表名。7.2 支持导出为CSV控制台打印适合快速查看但如果想把数据保存下来CSV格式更实用。可以在打印的同时写入文件try (PrintWriter writer new PrintWriter(new FileWriter(output.csv))) { ResultSetMetaData meta rs.getMetaData(); int columnCount meta.getColumnCount(); // 写表头 for (int i 1; i columnCount; i) { if (i 1) writer.print(,); writer.print(meta.getColumnName(i)); } writer.println(); // 写数据 while (rs.next()) { for (int i 1; i columnCount; i) { if (i 1) writer.print(,); String value rs.getString(i); if (value ! null value.contains(,)) { value \ value \; } writer.print(value null ? : value); } writer.println(); } }CSV里如果字段内容包含逗号需要用双引号包起来。如果包含双引号需要把双引号转义成两个双引号。这些细节处理好了导出的CSV才能被Excel正确打开。7.3 加一个简单的交互界面如果觉得命令行参数还是不够方便可以用Scanner做一个简单的交互Scanner scanner new Scanner(System.in); while (true) { System.out.print(请输入SQL输入exit退出: ); String sql scanner.nextLine(); if (exit.equalsIgnoreCase(sql)) { break; } try { printTable(sql); } catch (Exception e) { System.out.println(执行失败: e.getMessage()); } }这样你就可以在控制台里输入任意SQL实时查看结果。对于调试和探索数据库来说非常方便。8. 一些实战中的经验之谈8.1 不要在循环里创建连接我见过一些初学者写的代码在for循环里每次都DriverManager.getConnection然后查询一条数据就关闭。这样写性能极差因为建立连接是开销很大的操作。正确的做法是在循环外面创建一次连接循环里面复用。如果确实需要频繁获取连接应该用连接池比如HikariCP、Druid。但连接池的配置又是一门学问对于简单的控制台工具来说一个连接就够了。8.2 注意数据库的时区设置MySQL 8的时区问题坑了很多人。如果你的服务器时区是UTC而你在URL里没有指定serverTimezone存进去的时间可能会差8小时。我一般会在URL里明确指定serverTimezoneAsia/Shanghai并且在数据库服务器上也设置好时区。另外Timestamp和Date的转换也要注意。rs.getTimestamp返回的是带时区信息的而rs.getDate只返回日期部分。如果你需要精确的时间用Timestamp。8.3 日志比System.out.println更好虽然这篇文章讲的是控制台打印但在实际项目中用日志框架比如SLF4J Logback比System.out.println好得多。日志可以控制级别、可以输出到文件、可以格式化、可以异步。不过对于一个小demo来说引入日志框架又有点杀鸡用牛刀了。我的建议是demo用System.out.println一旦代码要长期维护就换成日志框架。8.4 异常处理不要只打印堆栈e.printStackTrace()在开发阶段没问题但在生产环境里堆栈信息应该记录到日志里而不是直接输出到控制台。而且异常应该被适当处理而不是简单地打印一下然后继续。比如连接失败的时候应该给用户一个友好的提示而不是抛出一堆看不懂的堆栈信息。try { // JDBC操作 } catch (SQLException e) { System.err.println(数据库操作失败: e.getMessage()); // 如果需要记录日志 }8.5 测试的时候用只读账号如果你只是查询数据建议用一个只有SELECT权限的数据库账号。这样即使代码里不小心写了DELETE或UPDATE数据库也会拒绝执行。这是一个很好的安全习惯尤其是在生产环境上跑临时脚本的时候。9. 完整代码示例与运行说明把前面的内容整合一下一个完整的、可以直接运行的JDBC Demo长这样import java.io.InputStream; import java.sql.*; import java.util.Properties; public class JdbcDemo { public static void main(String[] args) throws Exception { if (args.length 0) { System.out.println(用法: java JdbcDemo 表名); return; } Properties props new Properties(); try (InputStream in JdbcDemo.class.getClassLoader() .getResourceAsStream(db.properties)) { if (in null) { System.err.println(找不到db.properties配置文件); return; } props.load(in); } String driver props.getProperty(db.driver); String url props.getProperty(db.url); String user props.getProperty(db.user); String password props.getProperty(db.password); Class.forName(driver); String tableName args[0]; String sql SELECT * FROM tableName; try (Connection conn DriverManager.getConnection(url, user, password); Statement stmt conn.createStatement(); ResultSet rs stmt.executeQuery(sql)) { ResultSetMetaData meta rs.getMetaData(); int columnCount meta.getColumnCount(); // 打印表头 for (int i 1; i columnCount; i) { System.out.printf(%-20s, meta.getColumnName(i)); } System.out.println(); System.out.println(-.repeat(columnCount * 20)); // 打印数据 int rowCount 0; while (rs.next()) { for (int i 1; i columnCount; i) { String value rs.getString(i); if (value ! null value.length() 18) { value value.substring(0, 15) ...; } System.out.printf(%-20s, value null ? NULL : value); } System.out.println(); rowCount; } System.out.println(-.repeat(columnCount * 20)); System.out.println(共 rowCount 行); } } }对应的db.properties文件db.drivercom.mysql.cj.jdbc.Driver db.urljdbc:mysql://localhost:3306/testdb?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8allowPublicKeyRetrievaltrue db.userroot db.passwordyour_password编译和运行javac -cp .;mysql-connector-j-8.0.33.jar JdbcDemo.java java -cp .;mysql-connector-j-8.0.33.jar JdbcDemo user运行结果大概是这样id name email ------------------------------------------------------------ 1 张三 zhangsantest.com 2 李四 lisitest.com 3 王五 wangwutest.com ------------------------------------------------------------ 共 3 行这个代码虽然简单但涵盖了JDBC的核心流程加载驱动、获取连接、执行查询、遍历结果集、释放资源。而且通过配置文件管理连接信息通过命令行参数指定表名通过ResultSetMetaData动态获取列信息已经具备了一个小工具的基本形态。我在实际使用中会把这段代码保存成一个模板每次需要快速查看数据库的时候改一下配置文件就能用。比打开数据库客户端、输入密码、找到表、右键查询要快得多。尤其是当你在服务器上只能通过命令行操作的时候这个工具就更有用了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑