UserService是一个典型的Java服务类,负责处理用户相关的业务逻辑和数据操作。这个版本的核心改进是将原本基于内存的数据查询改为通过JDBC连接数据库进行操作,实现了数据的持久化存储。下面我们来详细拆解这个类的设计思路和实现细节。
从代码中可以看到,UserService主要依赖以下几个关键组件:
DBUtil:数据库连接工具类,负责获取和释放数据库连接User及其子类(Citizen、Repairman、Admin):用户实体类,代表系统中的不同角色Connection、PreparedStatement、ResultSet):用于执行SQL语句和处理结果这种设计遵循了经典的三层架构模式,将数据访问逻辑集中在Service层,与业务逻辑解耦。
提示:在实际项目中,建议进一步将数据访问层(DAO)单独抽离,使Service层专注于业务逻辑,这样更符合单一职责原则。
从SQL语句可以推断出数据库表ks_user的基本结构:
user_id:用户唯一标识,整型user_name:用户名,字符串类型phone:联系电话,字符串类型password:密码(存储的应该是加密后的值)user_role:用户角色,整型(1-普通用户,2-维修工,3-管理员)todo_count:待办事项计数(仅维修工使用)这种设计采用了单表继承的模式,将不同角色的用户存储在同一个表中,通过user_role字段区分。优点是查询简单,缺点是如果不同角色属性差异很大时,会有很多空字段。
java复制public User getUserByUserNameAndRole(String userName, int role) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
String sql = "SELECT * FROM ks_user WHERE user_name = ? AND user_role = ?";
User user = null;
try {
conn = DBUtil.getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, userName);
pstmt.setInt(2, role);
rs = pstmt.executeQuery();
if (rs.next()) {
int userId = rs.getInt("user_id");
String phone = rs.getString("phone");
String password = rs.getString("password");
int todoCount = rs.getInt("todo_count");
if (role == 1) {
user = new entity.Citizen(userId, userName, phone, password, role);
} else if (role == 2) {
user = new Repairman(userId, userName, phone, password, role, todoCount);
} else if (role == 3) {
user = new entity.Admin(userId, userName, phone, password, role);
}
}
} catch (SQLException e) {
e.printStackTrace();
System.out.println("查询用户失败!");
} finally {
DBUtil.close(conn,pstmt,rs);
}
return user;
}
这个方法有几个值得注意的实现细节:
使用PreparedStatement防止SQL注入:通过参数化查询,有效避免了SQL注入风险。
资源管理:严格遵守JDBC资源管理规范,在finally块中关闭连接、语句和结果集。
对象创建策略:根据角色类型创建不同的用户子类对象,体现了多态思想。
异常处理:捕获SQLException并打印堆栈,但仅输出简单错误信息,实际项目中应考虑更完善的错误处理机制。
java复制public boolean updateUserInfo(User user, String newPhone, String newPwd) {
if (user == null) {
return false;
}
Connection conn = null;
PreparedStatement pstmt = null;
String sql = "UPDATE ks_user SET user_phone = ?, user_password = ? WHERE user_id = ?";
try {
conn = DBUtil.getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, newPhone);
pstmt.setString(2, newPwd);
pstmt.setInt(3, user.getUserId());
int affectedRows = pstmt.executeUpdate();
return affectedRows > 0;
} catch (SQLException e) {
e.printStackTrace();
return false;
} finally {
DBUtil.close(conn,pstmt);
}
}
这个方法的关键点:
参数校验:首先检查user参数是否为null,避免空指针异常。
更新操作:使用UPDATE语句修改用户信息,通过affectedRows判断是否更新成功。
事务处理:当前实现缺少显式的事务控制,如果这是一个关键操作,应考虑添加事务管理。
java复制public User getRepairmanWithMinTodo() {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
String sql = "SELECT * FROM ks_user WHERE user_role = 2 ORDER BY todo_count ASC LIMIT 1";
User repairman = null;
try {
conn = DBUtil.getConnection();
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
if (rs.next()) {
int userId = rs.getInt("user_id");
String userName = rs.getString("user_name");
String phone = rs.getString("phone");
String password = rs.getString("password");
int todoCount = rs.getInt("todo_count");
repairman = new Repairman(userId, userName, phone, password, 2, todoCount);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(conn, pstmt, rs);
}
return repairman;
}
这个方法实现了简单的负载均衡策略:
排序查询:通过ORDER BY todo_count ASC获取待办最少的维修工。
限制结果:使用LIMIT 1只返回一个结果,提高效率。
角色过滤:WHERE条件确保只查询维修工(user_role = 2)。
硬编码问题:角色类型(1,2,3)直接硬编码在代码中,不利于维护。
缺乏事务管理:更新操作没有事务控制,可能导致数据不一致。
密码安全:密码以明文形式存储和传输,存在安全隐患。
性能考虑:频繁创建和关闭数据库连接可能影响性能。
java复制public enum UserRole {
CITIZEN(1), REPAIRMAN(2), ADMIN(3);
private final int code;
UserRole(int code) {
this.code = code;
}
public int getCode() {
return code;
}
}
引入连接池:使用HikariCP等连接池管理数据库连接。
密码加密:使用BCrypt等安全算法加密存储密码。
添加事务注解:使用Spring的@Transactional管理事务。
日志记录:使用SLF4J等日志框架替代System.out.println。
问题现象:获取数据库连接失败,抛出SQLException。
排查步骤:
解决方案:
java复制// 示例:使用HikariCP连接池配置
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/ks_db");
config.setUsername("username");
config.setPassword("password");
config.setMaximumPoolSize(10);
HikariDataSource ds = new HikariDataSource(config);
问题现象:用户查询响应缓慢。
优化建议:
索引创建SQL:
sql复制CREATE INDEX idx_user_name_role ON ks_user(user_name, user_role);
问题现象:ResultSet到对象的转换代码重复且容易出错。
改进方案:使用JdbcTemplate或MyBatis等持久层框架简化操作。
使用JdbcTemplate示例:
java复制public User getUserByUserNameAndRole(String userName, UserRole role) {
String sql = "SELECT * FROM ks_user WHERE user_name = ? AND user_role = ?";
return jdbcTemplate.queryForObject(sql, new Object[]{userName, role.getCode()},
(rs, rowNum) -> {
// 对象映射逻辑
if (role == UserRole.CITIZEN) {
return new Citizen(...);
}
// 其他角色处理
});
}
对于用户数量较多的系统,应实现分页查询功能:
java复制public List<User> getUsersByPage(int pageNum, int pageSize) {
String sql = "SELECT * FROM ks_user LIMIT ? OFFSET ?";
int offset = (pageNum - 1) * pageSize;
// 执行查询并返回结果列表
}
添加用户状态字段,支持禁用/启用用户:
sql复制ALTER TABLE ks_user ADD COLUMN status TINYINT DEFAULT 1 COMMENT '1-启用,0-禁用';
记录用户重要操作的日志:
java复制public boolean updateUserInfo(User user, String newPhone, String newPwd) {
boolean success = // 更新逻辑
if (success) {
auditLogService.log(user.getUserId(), "UPDATE_PROFILE",
"修改联系方式或密码");
}
return success;
}
在实际项目中,UserService作为核心服务类,其稳定性和安全性至关重要。建议在后续迭代中逐步实现上述改进方案,同时编写完善的单元测试和集成测试,确保代码质量。对于新项目,可以考虑使用Spring Data JPA或MyBatis-Plus等现代化持久层框架,能够显著减少样板代码,提高开发效率。