1. 繁琐的样本代码
每次执行一条sql,无论sql简单还复杂,都需要:加载驱动、创建连接、遍历结果集、关闭资源等流程。这会导致核心逻辑淹没在大量的支撑代码当中。
示例:比如即使是查询一个用户名,也要写如下的代码:
ini
public static void main(String[] args) throws ClassNotFoundException {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = DriverManager.getConnection("jdbc:mysql://192.168.1.1:3306/ruoyi?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&allowMultiQueries=true&useSSL=false&allowPublicKeyRetrieval=true&allowMultiQueries=true&useInformationSchema=true", "root", "123456");
preparedStatement = connection.prepareStatement("select user_name from sys_user where user_id=1");
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
System.out.println(resultSet.getString("user_name"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (resultSet != null) {
resultSet.close();
}
if (preparedStatement != null) {
preparedStatement.close();
}
if (connection != null) {
connection.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
2. 资源释放容易泄露
JDBC要求开发者手动关闭ResultSet、PreparedStatement、Connection资源。在复杂的逻辑中(比如多重嵌套的if-else),容易遗漏某个资源的关闭,导致数据库连接池用尽,最终程序崩溃。
3. 硬编码SQL导致代码维护困难
JDBC将sql直接写在java类中,当业务变更导致表结构或查询语句变更时,需要改java代码并重编译整个项目。同时这种字符串拼接的方式,开发体验非常差,非常容易将sql拼写错误。
4. 参数设置及其不灵活
JDBC变量的占位符是?,开发人员必须手动通过索引来设置参数(ps.setLong(0,1))。当sql
参数很多时,数清楚每个占位符对应的变量非常麻烦。
vbscript
// 这种代码极其容易把位置指错
ps.setString(1, user.getName());
ps.setInt(2, user.getAge());
ps.setString(3, user.getEmail());
// ... 想象一下有 30 个参数的情况
5. 结果集映射手动转换
JDBC返回的结果集是ResultSet对象。开发人员需要遍历结果集,并一个一个字段的取数据,组装到POJO对象中。
ini
public class JdbcUtils {
@Data
static class User {
private Long userId;
private String userName;
private String password;
private Integer age;
}
public static void main(String[] args) throws ClassNotFoundException {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = DriverManager.getConnection("jdbc:mysql://192.168.1.1:3306/ruoyi?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&allowMultiQueries=true&useSSL=false&allowPublicKeyRetrieval=true&allowMultiQueries=true&useInformationSchema=true", "root", "123456");
preparedStatement = connection.prepareStatement("select * from sys_user where user_id=?");
preparedStatement.setLong(1, 1);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
User user = new User();
user.setUserId(resultSet.getLong("user_id"));
user.setUserName(resultSet.getString("user_name"));
user.setPassword(resultSet.getString("password"));
user.setAge(resultSet.getInt("age"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (resultSet != null) {
resultSet.close();
}
if (preparedStatement != null) {
preparedStatement.close();
}
if (connection != null) {
connection.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
6. 异常处理太笼统
JDBC抛出的异常基本都是SQLException,无论是语法错误、连接超时、违反唯一键约束,还是数据库挂了,抛出的都是同一个异常。很难通过这个异常定位出更具体的问题。
7. 缺乏事务管理的便捷性
在 JDBC 中处理事务需要手动调用 conn.setAutoCommit(false) 和 conn.commit() / conn.rollback()。当涉及跨多个 Service 调用的复杂事务时,手动传递 Connection 对象会让代码耦合度爆炸。
为了解决这些痛点,业界提供了一些解决方案:
- apache DbUtils/Spring JdbcTemplate:主要解决样板代码和资源关闭问题
- Mybatis:解决了SQL硬编码和结果集映射的问题
- Hibernate、spring data jpa:通过ORM对象映射,让我们彻底摆脱编写简单SQL。