16.DAO设计思想与搭建骨架_UserDaoImpl

package jdbc.domain.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import jdbc.domain.User;
import jdbc.domain.dao.DataException;
import jdbc.domain.dao.UserDao;
import test.jdbc.JdbcUtil;

public class UserDaoImpl implements UserDao {

public void addUser(User user) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
String sql = "insert into user1(ID, NAME, BIRTHDAY, MONEY) values(?, ?, ?, ?)";
try {
conn = JdbcUtil.getConnection();
ps = conn.prepareStatement(sql);
ps.setInt(1, user.getId());
ps.setString(2, user.getName());
ps.setDate(3, new java.sql.Date(user.getBirthday().getTime()));
ps.setInt(4, user.getMoney());
ps.executeUpdate();
} catch (SQLException e) {
throw new DataException(e.getMessage(), e);
} finally {
JdbcUtil.free(rs, ps, conn);
}
}

public void deleteUser(User user) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
String sql = "delete from user1 where id = ?";
try {
conn = JdbcUtil.getConnection();
ps = conn.prepareStatement(sql);
ps.setInt(1, user.getId());
ps.executeUpdate();
} catch (SQLException e) {
throw new DataException(e.getMessage(), e);
} finally {
JdbcUtil.free(rs, ps, conn);
}
}

public User findUser(String loginName, String password) {
String sql = "select id,name,birthday,money from user1 where name=?";
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
User user = null;
try {
conn = JdbcUtil.getConnection();
ps = conn.prepareStatement(sql);
ps.setString(1, loginName);
rs = ps.executeQuery();
while (rs.next()) {
user = mappingUser(rs);
}
} catch (SQLException e) {
throw new DataException(e.getMessage(), e);
} finally {
JdbcUtil.free(rs, ps, conn);
}
return user;
}

public User getUser(int id) {
String sql = "select id,name,birthday,money from user1 where id=?";
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
User user = null;
try {
conn = JdbcUtil.getConnection();
ps = conn.prepareStatement(sql);
ps.setInt(1, id);
rs = ps.executeQuery();
while (rs.next()) {
user = mappingUser(rs);
}
} catch (SQLException e) {
throw new DataException(e.getMessage(), e);
} finally {
JdbcUtil.free(rs, ps, conn);
}
return user;
}

private User mappingUser(ResultSet rs) throws SQLException {
User user;
user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setBirthday(rs.getDate("birthday"));
user.setMoney(rs.getInt("money"));
return user;
}

public void updateUser(User user) {
String sql = "update user1 set NAME = ?, BIRTHDAY=? WHERE ID=?";
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JdbcUtil.getConnection();
ps = conn.prepareStatement(sql);
ps.setString(1, user.getName());
ps.setDate(2, new java.sql.Date(user.getBirthday().getTime()));
ps.setInt(3, user.getId());
ps.executeUpdate();
} catch (SQLException e) {
throw new DataException(e.getMessage(), e);
} finally {
JdbcUtil.free(rs, ps, conn);
}
}

}
<think>我们正在处理一个关于Java中NullPointerException异常的问题,具体涉及Properties.load0和JdbcDruidUtil.getConnection以及closeStatement方法。根据用户描述,问题可能出现在加载配置文件或数据库连接操作中。 首先,NullPointerException通常发生在尝试访问或操作一个null对象引用时。我们需要检查相关代码,确保在调用方法之前对象已经被正确初始化。 根据引用[1]中提到的MyBatis配置,我们可以借鉴资源加载的方式。在引用[2]中,MyBatisUtil类通过静态块初始化SqlSessionFactory,这种方式可以确保资源只加载一次且避免空指针。同样,在我们的Properties加载和数据库工具类中,也应该采用类似的初始化机制。 可能的原因和解决方案: 1. Properties加载失败: - 检查配置文件路径是否正确,确保文件存在于类路径中。 - 使用类加载器(ClassLoader)来加载资源,避免使用绝对路径。 - 在加载Properties之前,确保InputStream不为null。 2. JdbcDruidUtil工具类中的连接获取(getConnection)出现空指针: - 检查数据源(DataSource)是否被正确初始化。通常在工具类的静态块中初始化数据源。 - 确保数据库配置参数(如URL、用户名、密码)正确,并且数据源配置无误。 3. closeStatement出现空指针: - 在关闭Statement之前,检查它是否为null。 - 使用try-catch-finally块或try-with-resources确保资源被正确关闭,即使出现异常。 下面我们分别给出代码示例: 1. Properties加载示例(避免NullPointerException): ```java public class ConfigLoader { private static Properties properties; static { properties = new Properties(); try (InputStream input = ConfigLoader.class.getClassLoader().getResourceAsStream("config.properties")) { if (input == null) { throw new RuntimeException("Unable to find config.properties"); } properties.load(input); } catch (IOException e) { throw new RuntimeException("Error loading configuration", e); } } public static String getProperty(String key) { return properties.getProperty(key); } } ``` 2. JdbcDruidUtil工具类示例(确保数据源正确初始化): ```java public class JdbcDruidUtil { private static DataSource dataSource; static { try { // 使用Druid数据源 DruidDataSource druidDataSource = new DruidDataSource(); // 从ConfigLoader获取配置,避免重复加载 druidDataSource.setUrl(ConfigLoader.getProperty("jdbc.url")); druidDataSource.setUsername(ConfigLoader.getProperty("jdbc.username")); druidDataSource.setPassword(ConfigLoader.getProperty("jdbc.password")); // 其他配置(如初始连接数、最大连接数等) // ... dataSource = druidDataSource; } catch (Exception e) { throw new RuntimeException("初始化数据源失败", e); } } public static Connection getConnection() throws SQLException { // 确保dataSource已经初始化 if (dataSource == null) { throw new SQLException("数据源未初始化"); } return dataSource.getConnection(); } // 关闭Connection、Statement、ResultSet的方法,注意处理null public static void close(Connection conn, Statement stmt, ResultSet rs) { 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) { // 日志记录 } } } } ``` 3. 在调用closeStatement时,应该先判断Statement是否为null: ```java public static void closeStatement(Statement stmt) { if (stmt != null) { try { stmt.close(); } catch (SQLException e) { // 日志记录 } } } ``` 总结: - 使用静态块初始化资源(如配置文件和数据库连接池)可以确保在类加载时只执行一次,避免重复初始化。 - 在加载资源时,要检查输入流是否为空,避免后续操作出现空指针。 - 在数据库工具类中,获取连接前检查数据源是否初始化,关闭资源时检查资源对象是否为null。 通过以上步骤,应该可以解决用户遇到的NullPointerException问题。 如果用户的问题是由于其他原因引起的,建议检查堆栈跟踪,定位具体是哪一行代码出现的空指针,然后检查该行代码中所有对象是否被正确初始化。 最后,注意在代码中添加适当的日志记录,以便于排查问题。 §§相关问题§§ 1. 如何避免Java中的NullPointerException? 2. 数据库连接池(如Druid)的配置有哪些注意事项? 3.Java中如何正确关闭数据库资源? 4. 如何优雅地处理配置文件缺失的情况?</think>### Java中NullPointerException的解决方案 针对您遇到的`NullPointerException`异常(涉及`Properties.load0`、`JdbcDruidUtil.getConnection`和`closeStatement`),以下是系统性的解决方案: --- ### 一、问题根本原因 1. **Properties加载失败** - 配置文件路径错误或文件不存在 - 输入流未正确关闭导致资源泄漏 - 未处理`getResourceAsStream()`返回`null`的情况 2. **数据库连接获取失败** - 数据源未正确初始化(如未加载JDBC驱动) - 数据库配置参数错误(URL/用户名/密码) - 连接池未正确配置(Druid特有) 3. **Statement关闭异常** - 尝试关闭未初始化的`Statement`对象 - 资源关闭顺序错误(应先关ResultSet,再关Statement) --- ### 二、解决方案 #### 1. 修复Properties加载(参考引用[2]) ```java // 正确加载配置文件示例 public class ConfigLoader { private static Properties props; static { props = new Properties(); try (InputStream input = ConfigLoader.class.getClassLoader() .getResourceAsStream("application.properties")) { // [!code focus] if (input == null) { // 关键检查点 throw new RuntimeException("配置文件未找到"); } props.load(input); // 触发load0调用 } catch (IOException e) { throw new RuntimeException("配置加载失败", e); } } public static String getProperty(String key) { return props.getProperty(key); } } ``` > **关键点**: > - 使用`try-with-resources`确保流自动关闭[^2] > - 显式检查`input == null`避免NPE > - 静态初始化保证线程安全 #### 2. 修复JdbcDruidUtil(参考引用[3]) ```java public class JdbcDruidUtil { private static DataSource dataSource; // Druid数据源 static { try { // 1. 从配置加载参数 String url = ConfigLoader.getProperty("jdbc.url"); String user = ConfigLoader.getProperty("jdbc.user"); String password = ConfigLoader.getProperty("jdbc.password"); // 2. 初始化Druid连接池 DruidDataSource ds = new DruidDataSource(); // [!code focus] ds.setUrl(url); ds.setUsername(user); ds.setPassword(password); ds.setInitialSize(5); // 初始连接数 ds.setMaxActive(20); // 最大连接数 dataSource = ds; } catch (Exception e) { throw new ExceptionInInitializerError("Druid初始化失败"); } } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); // 此时dataSource必不为null } } ``` #### 3. 安全关闭资源 ```java public static void closeStatement(Statement stmt) { if (stmt != null) { // 必须判空 try { stmt.close(); } catch (SQLException e) { // 日志记录而非抛出异常 Logger.error("关闭Statement失败: " + e.getMessage()); } } } // 完整关闭模板 public static void closeResources(ResultSet rs, Statement stmt, Connection conn) { try { if (rs != null) rs.close(); } catch (SQLException e) { /* 处理异常 */ } try { if (stmt != null) stmt.close(); // [!code focus] } catch (SQLException e) { /* 处理异常 */ } try { if (conn != null) conn.close(); // 归还连接至连接池 } catch (SQLException e) { /* 处理异常 */ } } ``` --- ### 三、预防措施 1. **防御性编程** - 所有对象使用前显式判空:`if (obj != null)` - 使用`Optional`处理可能为null的返回值 2. **资源管理** - 遵循`try-with-resources`规范(实现`AutoCloseable`接口) - 关闭顺序:`ResultSet → Statement → Connection` 3. **连接池配置** ```java // Druid建议配置 ds.setValidationQuery("SELECT 1"); // 连接检测语句 ds.setTestWhileIdle(true); // 定期检查空闲连接 ds.setTimeBetweenEvictionRunsMillis(60000); // 60秒检测周期 ``` --- ### 四、调试建议 1. 在`Properties.load0`报错处检查: ```java System.out.println("加载路径: " + ConfigLoader.class.getResource("/application.properties")); ``` 2. 在Druid初始化后添加验证: ```java System.out.println("活跃连接数: " + ((DruidDataSource)dataSource).getActiveCount()); ``` > 通过以上步骤,可彻底解决配置加载和数据库连接相关的`NullPointerException`问题。若仍出现异常,请检查数据库驱动版本和防火墙设置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值