MST

星途 面试题库

面试题:Java数据访问层(DAO)中的反模式及优化策略

在Java的DAO层开发中,存在一些反模式,如SQL语句硬编码、不恰当的事务处理等。请详细描述一种DAO层的反模式,分析它可能带来的问题,并提出全面的优化策略,包括但不限于代码结构调整、使用框架特性等。
26.2万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

SQL语句硬编码反模式

描述

在DAO层代码中,将SQL语句直接写死在Java代码中,而不是通过参数化查询或从外部配置文件加载SQL。例如:

public User getUserById(int id) {
    String sql = "SELECT * FROM users WHERE id = " + id;
    // 执行SQL代码
}

可能带来的问题

  1. 维护困难:如果数据库表结构或查询逻辑发生变化,需要修改Java代码中的SQL语句,这可能会影响到多个地方,增加维护成本。例如,若users表名变更,所有硬编码该表名的SQL都需修改。
  2. SQL注入风险:如上述代码,当id值由用户输入提供时,恶意用户可能输入特殊字符构造恶意SQL语句,导致数据泄露或数据被破坏。例如输入1 OR 1 = 1,会返回所有用户数据。
  3. 可读性差:硬编码的SQL语句嵌入Java代码中,使代码逻辑混杂,降低了代码的可读性,不利于团队开发和代码审查。

优化策略

  1. 使用参数化查询:使用JDBC的PreparedStatement代替直接拼接SQL。
public User getUserById(int id) {
    String sql = "SELECT * FROM users WHERE id =?";
    try (PreparedStatement pstmt = connection.prepareStatement(sql)) {
        pstmt.setInt(1, id);
        // 执行查询并处理结果
    } catch (SQLException e) {
        // 异常处理
    }
}
  1. 从外部配置文件加载SQL:将SQL语句放在配置文件(如.properties.xml)中,Java代码从配置文件读取SQL。 例如,在sql.properties文件中:
getUserById=SELECT * FROM users WHERE id =?

在Java代码中读取:

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class UserDAO {
    private static final Properties sqlProps = new Properties();
    static {
        try (InputStream inputStream = UserDAO.class.getClassLoader().getResourceAsStream("sql.properties")) {
            sqlProps.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public User getUserById(int id) {
        String sql = sqlProps.getProperty("getUserById");
        try (PreparedStatement pstmt = connection.prepareStatement(sql)) {
            pstmt.setInt(1, id);
            // 执行查询并处理结果
        } catch (SQLException e) {
            // 异常处理
        }
    }
}
  1. 使用ORM框架:如Hibernate、MyBatis等。以MyBatis为例,通过XML映射文件配置SQL语句。 在UserMapper.xml中:
<mapper namespace="com.example.UserDAO">
    <select id="getUserById" parameterType="int" resultType="User">
        SELECT * FROM users WHERE id = #{id}
    </select>
</mapper>

在Java代码中调用:

public User getUserById(int id) {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    try {
        return sqlSession.selectOne("com.example.UserDAO.getUserById", id);
    } finally {
        sqlSession.close();
    }
}

这样将SQL与Java代码分离,提高了代码的可维护性和安全性,同时利用框架的特性简化了数据库操作。