如何改进我的 DAO? - Java EE

发布于 2024-11-15 13:59:10 字数 4463 浏览 4 评论 0原文

我想访问我的申请人数据库,这就是我为其创建 DAO 类的原因。

我认为我有很多代码味道,因为我不断重复一些代码。那么我该怎么做才能使我的代码更简单以减少代码异味呢?我违反了什么规则?我该如何改进我的代码?谢谢。

我的代码如下:

public class ApplicantDAO {

private static ApplicantDAO me = null;

private ApplicantDAO(){};

public static synchronized ApplicantDAO getInstance() {
    if(me == null) {
        me = new ApplicantDAO();
    }
    return me;
}

public Applicant getApplicant(int applicantNumber) throws SQLException {
    Applicant applicant = null;

    Connection conn = null; 
    Statement statement= null;
    String query = null;
    ResultSet rs = null;

    try {
        conn = ConnectionManager.getConnection();
        statement = conn.createStatement();
        query = "SELECT * FROM applicant WHERE applicant_no = '" + applicantNumber +"'";    //check applicant_number
        rs = statement.executeQuery(query);

        while(rs.next()){
            applicant = new Applicant();

            applicant.setApplicantNumber(rs.getInt("applicant_no"));
            applicant.setApplicationDate(rs.getString("applicant_date")); 
            applicant.setfName(rs.getString("first_name"));
            applicant.setlName(rs.getString("last_name"));
            applicant.setmName(rs.getString("middle_name"));
            applicant.setAge(rs.getInt("age"));
            applicant.setGender(rs.getString("gender"));
            applicant.setEmail(rs.getString("email_address"));
            applicant.setContactNumber(rs.getString("contact_no"));
            applicant.setCity(rs.getString("city"));
            applicant.setSchool(rs.getString("school"));
            applicant.setCourse(rs.getString("course"));
            applicant.setYearGraduated(rs.getInt("year_graduated"));
            applicant.setYearWorkExp(rs.getInt("year_work_exp"));
            applicant.setSourceChannel(rs.getString("source_channel"));
            applicant.setStatus_id(rs.getInt("status_id"));

        }

    } catch (SQLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }finally {
        if (rs != null) try { rs.close(); } catch (SQLException logOrIgnore) {}
        if (statement != null) try { statement.close(); } catch (SQLException logOrIgnore) {}
        if (conn!= null) try { conn.close(); } catch (SQLException logOrIgnore) {}
    }


    return applicant;
}

public ArrayList<Applicant> getApplicants() throws SQLException{
    ArrayList<Applicant> applicantList = null;
    Applicant applicant = null;

    Connection conn = null; 
    Statement statement= null;
    String query = null;
    ResultSet rs = null;

    try {
        conn = ConnectionManager.getConnection();
        statement = conn.createStatement();
        query = "select * from applicant";
        rs = statement.executeQuery(query);

        while(rs.next()){
            if(applicantList == null){
                applicantList = new ArrayList<Applicant>();
            }
            applicant = new Applicant();

            applicant.setApplicantNumber(rs.getInt("applicant_no"));
            applicant.setApplicationDate(rs.getString("applicant_date")); 
            applicant.setfName(rs.getString("first_name"));
            applicant.setlName(rs.getString("last_name"));
            applicant.setmName(rs.getString("middle_name"));
            applicant.setAge(rs.getInt("age"));
            applicant.setGender(rs.getString("gender"));
            applicant.setEmail(rs.getString("email_address"));
            applicant.setContactNumber(rs.getString("contact_no"));
            applicant.setCity(rs.getString("city"));
            applicant.setSchool(rs.getString("school"));
            applicant.setCourse(rs.getString("course"));
            applicant.setYearGraduated(rs.getInt("year_graduated"));
            applicant.setYearWorkExp(rs.getInt("year_work_exp"));
            applicant.setSourceChannel(rs.getString("source_channel"));
            applicant.setStatus_id(rs.getInt("status_id"));

            applicantList.add(applicant);
        }

    } catch (SQLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }finally{
         if (rs != null) try { rs.close(); } catch (SQLException logOrIgnore) {}
         if (statement != null) try { statement.close(); } catch (SQLException logOrIgnore) {}
         if (conn!= null) try { conn.close(); } catch (SQLException logOrIgnore) {}
    }
    return applicantList;
}

I want to access my applicant database that's why I created a DAO class for it.

I think I have lots of code smells because I keep on repeating some code. So what can I do to make my code simpler in order to achieve less code smells? What rules am I violating? How can i improve my code? Thank you.

My code is as follows:

public class ApplicantDAO {

private static ApplicantDAO me = null;

private ApplicantDAO(){};

public static synchronized ApplicantDAO getInstance() {
    if(me == null) {
        me = new ApplicantDAO();
    }
    return me;
}

public Applicant getApplicant(int applicantNumber) throws SQLException {
    Applicant applicant = null;

    Connection conn = null; 
    Statement statement= null;
    String query = null;
    ResultSet rs = null;

    try {
        conn = ConnectionManager.getConnection();
        statement = conn.createStatement();
        query = "SELECT * FROM applicant WHERE applicant_no = '" + applicantNumber +"'";    //check applicant_number
        rs = statement.executeQuery(query);

        while(rs.next()){
            applicant = new Applicant();

            applicant.setApplicantNumber(rs.getInt("applicant_no"));
            applicant.setApplicationDate(rs.getString("applicant_date")); 
            applicant.setfName(rs.getString("first_name"));
            applicant.setlName(rs.getString("last_name"));
            applicant.setmName(rs.getString("middle_name"));
            applicant.setAge(rs.getInt("age"));
            applicant.setGender(rs.getString("gender"));
            applicant.setEmail(rs.getString("email_address"));
            applicant.setContactNumber(rs.getString("contact_no"));
            applicant.setCity(rs.getString("city"));
            applicant.setSchool(rs.getString("school"));
            applicant.setCourse(rs.getString("course"));
            applicant.setYearGraduated(rs.getInt("year_graduated"));
            applicant.setYearWorkExp(rs.getInt("year_work_exp"));
            applicant.setSourceChannel(rs.getString("source_channel"));
            applicant.setStatus_id(rs.getInt("status_id"));

        }

    } catch (SQLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }finally {
        if (rs != null) try { rs.close(); } catch (SQLException logOrIgnore) {}
        if (statement != null) try { statement.close(); } catch (SQLException logOrIgnore) {}
        if (conn!= null) try { conn.close(); } catch (SQLException logOrIgnore) {}
    }


    return applicant;
}

public ArrayList<Applicant> getApplicants() throws SQLException{
    ArrayList<Applicant> applicantList = null;
    Applicant applicant = null;

    Connection conn = null; 
    Statement statement= null;
    String query = null;
    ResultSet rs = null;

    try {
        conn = ConnectionManager.getConnection();
        statement = conn.createStatement();
        query = "select * from applicant";
        rs = statement.executeQuery(query);

        while(rs.next()){
            if(applicantList == null){
                applicantList = new ArrayList<Applicant>();
            }
            applicant = new Applicant();

            applicant.setApplicantNumber(rs.getInt("applicant_no"));
            applicant.setApplicationDate(rs.getString("applicant_date")); 
            applicant.setfName(rs.getString("first_name"));
            applicant.setlName(rs.getString("last_name"));
            applicant.setmName(rs.getString("middle_name"));
            applicant.setAge(rs.getInt("age"));
            applicant.setGender(rs.getString("gender"));
            applicant.setEmail(rs.getString("email_address"));
            applicant.setContactNumber(rs.getString("contact_no"));
            applicant.setCity(rs.getString("city"));
            applicant.setSchool(rs.getString("school"));
            applicant.setCourse(rs.getString("course"));
            applicant.setYearGraduated(rs.getInt("year_graduated"));
            applicant.setYearWorkExp(rs.getInt("year_work_exp"));
            applicant.setSourceChannel(rs.getString("source_channel"));
            applicant.setStatus_id(rs.getInt("status_id"));

            applicantList.add(applicant);
        }

    } catch (SQLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }finally{
         if (rs != null) try { rs.close(); } catch (SQLException logOrIgnore) {}
         if (statement != null) try { statement.close(); } catch (SQLException logOrIgnore) {}
         if (conn!= null) try { conn.close(); } catch (SQLException logOrIgnore) {}
    }
    return applicantList;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

傲世九天 2024-11-22 13:59:10

我看到的巨大而明显的问题:

  1. DAO 是一个单例。为什么?
  2. 您没有使用 EntityManager。还有,为什么?

如果您实际上使用的是 Java EE(正如问题所标记的那样)而不是 J2EE(这是围绕 Java 1.4 构建的一个糟糕的规范),那么 DAO 模式是完全没有必要的。 EntityManager 是新的 DAO。

查看Java EE 6 教程 - 持久性<的前几节/a>.


我们需要使用 J2ee..:(

好吧,所以您仍然需要修复单例实现。没有理由只创建该对象的一个​​实例,因为它不存储任何内部状态。有一个简单的方法修复:

  • 完全删除 private static ApplicantDAO me = null;
  • getInstance() 实现更改为

    public static ApplicantDAO getInstance() {
        返回新的ApplicantDAO();
    }
    

其他气味:

  • 您几乎总是希望声明 List 而不是 ArrayList,因此更改声明,例如

    public ArrayList<申请人>; getApplicants() 抛出 SQLException
    // 到
    公开列表<申请人> getApplicants() 抛出 SQLException
    
    // 和
    
    ArrayList<申请人>申请人列表=空;
    // 到
    列表<申请人>申请人列表=空;
    

Giant, glaring issues I see:

  1. The DAO is a singleton. Why?
  2. You're not using EntityManager. Also, why?

If you're actually using Java EE (as the question is tagged) rather than J2EE (which is a miserable spec built around Java 1.4) then the DAO pattern is completely unnecessary. EntityManager is the new DAO.

Have a look at the first few sections of The Java EE 6 Tutorial - Persistence.


we are required to use J2ee.. :(

Ok, so you still need to fix the singleton implementation. There is simply no reason to only create one instance of this object, given that it does not store any internal state whatsoever. There's an easy fix:

  • Remove private static ApplicantDAO me = null; entirely
  • Change the getInstance() implementation to

    public static ApplicantDAO getInstance() {
        return new ApplicantDAO();
    }
    

Other smells:

  • You'll almost always want to declare Lists rather than ArrayLists, so change declarations like

    public ArrayList<Applicant> getApplicants() throws SQLException
    // to
    public List<Applicant> getApplicants() throws SQLException
    
    // and
    
    ArrayList<Applicant> applicantList = null;
    // to
    List<Applicant> applicantList = null;
    
空心空情空意 2024-11-22 13:59:10

为了让您了解更现代的 DAO 是什么样子:

@Stateless
public class JPAApplicantDAO implements ApplicantDAO {

    @PersistenceContext(unitName = "myPU")
    private EntityManager entityManager;

    @Override
    public Applicant getByID(Long applicantID) {
        return entityManager.find(Applicant.class, applicantID);
    }

    @Override
    public void update(Applicant applicant) {
        applicant.setLastModifiedDate(new Date());
        entityManager.merge(applicant);
    }

    @Override
    public void delete(Applicant applicant) {
        Applicant deletedApplicant = applicant;
        if (!entityManager.contains(applicant)) {
            deletedApplicant = entityManager.merge(applicant);
        }

        entityManager.remove(deletedApplicant);
    }

    @Override
    public List<Applicant> getBySomethingID(Long somethingID) {
        return entityManager.createNamedQuery("Applicant.getBySomethingID", Applicant.class)
                            .setParameter("somethingID", somethingID)
                            .getResultList();
    }
}

现在有人建议放弃整个 DAO 概念并直接在任何地方使用实体管理器。我并不完全同意这一点。

此 DAO 示例展示了 4 种不同的方法。第一种方法是通过实体的主 ID 进行简单获取。正是这种方式,让人怀疑是否还需要DAO抽象。但请继续阅读。

第二种方法示出了更新方法。在这种情况下,应用程序可能想要对实体执行一些额外的操作,例如设置上次修改日期。 DAO 是执行此操作的一个非常自然的地方。是的,它也可以在数据库中完成,但是 DAO 仍然很方便,因为您可能必须读回实体才能了解所设置的日期。

第三种方法是删除方法。由于 JPA 规范中的一个特殊问题,您只能删除处于附加状态的实体。这意味着需要一些额外的逻辑来检查它是否已附加(包含在持久性上下文中),如果没有附加它(合并它)。

第四种方法显示通过 (JPQL) 查询进行数据检索。查询名称和参数名称都不是类型安全的。 DAO 方便地将其隐藏在类型安全的 Java 方法后面。是的,您可以将这些名称提取为常量,但仍不会强制执行此特定参数和此特定查询之间的关联。

一般来说,DAO 允许进行一定量的重构。在某些时候,我可能想用条件查询替换 JPQL 查询。在所有调用站点更改此设置可能会出现问题。还有一种情况是,实体管理器作为通用 DAO 实在是太强大了。我不想将这些发送到所有客户端站点(对于远程客户端,这甚至是不可能的或非常糟糕的做法)。

最后,从本身不具有事务性的客户端代码中使用实体管理器,意味着该客户端必须担心事务。这给代码增加了很多冗长的内容。使用 DAO,客户端代码变得更加简单:

@Named
@RequestScoped
public class SomeBean {

    @EJB
    private ApplicantDAO applicantDAO;

    public void someMethod() {
        applicantDAO.delete(applicant);
    }
}

To give you some idea of what a more modern DAO would look like:

@Stateless
public class JPAApplicantDAO implements ApplicantDAO {

    @PersistenceContext(unitName = "myPU")
    private EntityManager entityManager;

    @Override
    public Applicant getByID(Long applicantID) {
        return entityManager.find(Applicant.class, applicantID);
    }

    @Override
    public void update(Applicant applicant) {
        applicant.setLastModifiedDate(new Date());
        entityManager.merge(applicant);
    }

    @Override
    public void delete(Applicant applicant) {
        Applicant deletedApplicant = applicant;
        if (!entityManager.contains(applicant)) {
            deletedApplicant = entityManager.merge(applicant);
        }

        entityManager.remove(deletedApplicant);
    }

    @Override
    public List<Applicant> getBySomethingID(Long somethingID) {
        return entityManager.createNamedQuery("Applicant.getBySomethingID", Applicant.class)
                            .setParameter("somethingID", somethingID)
                            .getResultList();
    }
}

Now it has been suggested to forgo the entire DAO concept and directly use the entity manager everywhere. I don't entirely agree with that.

This DAO example shows 4 different methods. The first method is a simple get via the main ID of an entity. It's this kind of method that makes people wonder whether the DAO abstraction is still needed. But read on.

The second method shows an update method. In this case the application might want to do something extra to the entity, such as setting a last modified date. The DAO is quite a natural place to do this. Yes, it could be done in the DB as well, but then the DAO would still be handy since you might have to read the entity back in order to learn about the date being set.

The third method is a delete method. Due to a peculiar issue in the JPA spec, you can only delete an entity that's in the attached state. This means some extra logic to check whether it's attached (contained in the persistence context) and if not attach it (merge it).

The fourth method shows data retrieval via a (JPQL) query. Both the name of the query and the name of the parameter are not type-safe. The DAO conveniently hides this behind a type-safe Java method. Yes, you can extract those names to a constant, but the association between this particular parameter and this particular query would still not be enforced.

In general, the DAO allows a certain amount of refactoring to take place. At some point I might want to replace the JPQL query with a criteria query. Changing this at all call-sites might be problematic. Then there's the case that an entity manager as a general DAO is simply to powerful. I don't want to send these to all client sites (in case of remote clients this is even impossible or very bad practice).

Finally, using an entity manager from client code that is itself not transactional, means this client has to worry about transactions. This adds a lot of verbosity to the code. With a DAO, the client code becomes much simpler:

@Named
@RequestScoped
public class SomeBean {

    @EJB
    private ApplicantDAO applicantDAO;

    public void someMethod() {
        applicantDAO.delete(applicant);
    }
}
扭转时空 2024-11-22 13:59:10

您的示例看起来像是一张完美的“之前”图片,在使用 Hibernate 将对象映射到关系数据库并使用 Spring 依赖注入功能支持连接和事务管理之后,显示了漂亮的“之后”图片。

Your example looks like a perfect "before" picture to show a great looking "after" picture after using Hibernate for mapping objects to the relational database and Spring dependency injection features to support connection and transaction management.

变身佩奇 2024-11-22 13:59:10

您可以使用Java Persistence API,并且大多数这些无聊的代码都是不必要的。

You could use Java Persistence API and most of this boring code would be unnecessary.

我恋#小黄人 2024-11-22 13:59:10

有史以来最糟糕的代码味道:你再次重新发明轮子。为什么不使用一些开放库,例如 Spring JDBC ? (注意:您也可以阅读代码来从中学习!)

如果您在这里练习,和/或不允许使用外部代码,那么这里有一些增强您的代码的提示:

  • 所有未包含的代码关于定义语句(及其参数)或处理结果集,可以分解为可重用方法以减少代码重复。这可能会导致您使用回调式参数或用于语句创建的可变参数,以及用于申请人重构的适配器式组件(尝试查看 Spring 的 JdbcTemplateRowMapper 类的代码)
  • 你的签名太精确了:当你可以返回一个List时,为什么要返回一个ArrayList?
  • 为什么你的 getInstance() 方法是同步的?您可以通过在类初始化时初始化 me 来避免这种情况:

    private static ApplicantDAO me = new ApplicantDAO();
    公共静态 ApplicantDAO getInstance() { 返回我; }
    

  • 您的日志策略似乎未定义:我认为这是故意的,但请记住,这在现实应用程序中非常重要。

Worst code smell ever: you're reinventing the wheel - again. Why not using some open library, such as Spring JDBC ? (nota: you may read the code to learn from it too!)

If you're practising here, and/or are not allowed to use external code, then here are a few hints to enhance your code:

  • all the code which is not about defining a statement (with its arguments) or processing a resultSet, may be factorized in reusable methods to reduce code duplication. This may lead you to callback-style arguments or varargs for statement creation, and adapter-style components for Applicants reconstitution (try looking into Spring's code for its JdbcTemplate and RowMapper classes)
  • your signatures are too precise: why return an ArrayList when you may return a List?
  • why is your getInstance() method synchronized? You may avoid this by initializing me at class initialization time:

    private static ApplicantDAO me = new ApplicantDAO();
    public static ApplicantDAO getInstance() { return me; }
    

  • your log policy is not defined it seems: I assume it's on purpose here, but keep in mind that this is quite important in real-life apps.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文