写JDBC连接数据库,这事儿说简单也简单,说复杂能把你绕进去一整天。我刚学那会儿,对着Class.forName那一行代码发了半小时呆,心里嘀咕:这玩意儿到底是在干嘛?后来踩的坑多了,才慢慢摸清楚,JDBC其实就是Java和数据库之间的一座桥,你过桥得先知道桥在哪、怎么上桥、桥那头是什么路况。今天就把我从入门到实战踩过的坑、总结的经验,全给你抖落出来。

先唠唠最基础的那三步。第一步,你得把数据库的驱动jar包搞到手,MySQL就找mysql-connector-java,PostgreSQL就找postgresql,别搞混了。第二步,Class.forName("com.mysql.cj.jdbc.Driver")这行代码,很多人以为是在“加载驱动”,其实它是在注册驱动,让JDBC知道该用哪个厂商的实现。第三步,DriverManager.getConnection(url, user, password)拿到Connection对象。这三步走完,你才算真正摸到了数据库的门把手。我当时就卡在第二步,死活想不通为啥要写这行,后来才知道,老版本的JDBC必须显式注册,新版本虽然可以省,但写上总没错,兼容性更好。
URL的写法是个坑中坑。MySQL的经典格式是jdbc:mysql://localhost:3306/数据库名?useSSL=false&serverTimezone=Asia/Shanghai,这里面的参数一个都不能少。useSSL不关,控制台会刷一堆警告,看得你心烦;serverTimezone不设,时间字段查出来全是乱的。PostgreSQL的格式是jdbc:postgresql://localhost:5432/数据库名,相对简单些。还有Oracle,那URL长得跟密码似的,jdbc:oracle:thin:@localhost:1521:orcl,我第一次见的时候还以为自己抄错了。记住一个原则:URL里的参数就是告诉驱动“我这边什么情况”,宁可多写,别漏写。
拿到Connection之后,好戏才刚开始。Statement、PreparedStatement、CallableStatement这三兄弟,你得搞清楚谁是谁。Statement就是个愣头青,直接拼接SQL往里扔,容易SQL注入,而且每次执行都要编译,性能拉胯。PreparedStatement就聪明多了,先预编译SQL,再用占位符传参,既安全又高效,实战中90%的场景都用它。CallableStatement是给存储过程用的,平时用得少,但遇到复杂业务也得会。我见过不少新手上来就Statement.executeQuery("SELECT FROM user WHERE id = " + id),这要是被黑客盯上,你的数据库跟裸奔没区别。
连接池这东西,等你项目一上线就知道多重要。每次请求都new一个Connection,用完再close,高并发下数据库分分钟被打爆。我当年做过一个活动页,流量一上来,MySQL直接报Too many connections,吓得我冷汗直冒。后来换上HikariCP,配置一下最大连接数和超时时间,世界瞬间清净了。连接池的原理说白了就是“复用”,提前创建一批连接放池子里,谁用谁取,用完还回去,省去了反复建立TCP连接的开销。Druid也不错,自带监控页面,能看到每条SQL的执行时间,排查慢查询神器。
事务处理是实战里绕不开的坎。默认情况下,Connection是自动提交的,每条SQL执行完就commit了。但你做转账操作,扣钱和加钱必须是一个整体,要么都成功,要么都失败。这时候就得connection.setAutoCommit(false),手动控制事务,统一commit,出错就rollback回滚。这里有个细节容易翻车:事务的隔离级别。MySQL默认是可重复读,如果你在一个事务里查了两次数据,第二次可能查到的是快照,不是最新数据。新手最容易犯的错是,事务代码写完了,却忘了在finally里调rollback或commit,结果连接还回去的时候,事务状态是乱的,下个请求拿到这个连接就出幺蛾子。
说几个我实战中踩过的坑,你遇到了能少走弯路。第一个,驱动类加载失败,报ClassNotFoundException,99%是jar包没放对位置。Maven项目就检查pom.xml,普通项目就检查build path,别光顾着写代码。第二个,连接超时,报Connection timed out,先ping一下数据库服务器,再看防火墙,才怀疑代码。第三个,中文乱码,八成是URL里少了characterEncoding=utf8,或者数据库表本身是latin1编码。第四个,ResultSet用完了不关,Statement也不关,导致连接泄漏,这个问题排查起来特别头疼,因为报错往往在很久之后才出现,而且随机性很强。我的习惯是,能用try-with-resources就绝不用手动close,代码简洁还不会忘。
关于性能优化,你得学会看执行计划。用PreparedStatement的时候,SQL里尽量别写SELECT ,把需要的列名写清楚,减少网络传输量。批量插入别一条条executeUpdate,用addBatch和executeBatch,速度能快好几倍,我当时导十万条数据,用批量操作从三分钟降到了十秒。还有,索引不是越多越好,频繁更新的字段加索引反而拖慢写入速度。面试时候总爱问“怎么优化慢查询”,其实答案就藏在这几个细节里:SQL写法、索引设计、连接池配置,这三样做好,大部分性能问题都能解决。
再啰嗦一句,JDBC学的是“底层逻辑”,但实战中你大概率会用MyBatis、Hibernate这类框架,它们封装了JDBC,让你少写很多样板代码。但框架出了问题,你还得回到JDBC层面去排查。比如MyBatis报的“无效的列类型”,其实就是PreparedStatement设置参数时类型不匹配。所以别觉得学JDBC过时了,它就像练武人的马步,扎不稳,后面全白搭。你现在把Connection、Statement、ResultSet这几个核心对象玩明白了,将来用任何框架都能一眼看穿它的本质。JDBC这条路,入门不难,难的是在实战里把细节抠到位,慢慢来,该踩的坑一个都跑不了,但踩完你就真会了。


