如何改进我的 DAO? - Java EE
我想访问我的申请人数据库,这就是我为其创建 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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我看到的巨大而明显的问题:
EntityManager
。还有,为什么?如果您实际上使用的是 Java EE(正如问题所标记的那样)而不是 J2EE(这是围绕 Java 1.4 构建的一个糟糕的规范),那么 DAO 模式是完全没有必要的。
EntityManager
是新的 DAO。查看Java EE 6 教程 - 持久性<的前几节/a>.
好吧,所以您仍然需要修复单例实现。没有理由只创建该对象的一个实例,因为它不存储任何内部状态。有一个简单的方法修复:
private static ApplicantDAO me = null;
将
getInstance()
实现更改为其他气味:
您几乎总是希望声明
List
而不是ArrayList,因此更改声明,例如
Giant, glaring issues I see:
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.
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:
private static ApplicantDAO me = null;
entirelyChange the
getInstance()
implementation toOther smells:
You'll almost always want to declare
List
s rather thanArrayList
s, so change declarations like为了让您了解更现代的 DAO 是什么样子:
现在有人建议放弃整个 DAO 概念并直接在任何地方使用实体管理器。我并不完全同意这一点。
此 DAO 示例展示了 4 种不同的方法。第一种方法是通过实体的主 ID 进行简单获取。正是这种方式,让人怀疑是否还需要DAO抽象。但请继续阅读。
第二种方法示出了更新方法。在这种情况下,应用程序可能想要对实体执行一些额外的操作,例如设置上次修改日期。 DAO 是执行此操作的一个非常自然的地方。是的,它也可以在数据库中完成,但是 DAO 仍然很方便,因为您可能必须读回实体才能了解所设置的日期。
第三种方法是删除方法。由于 JPA 规范中的一个特殊问题,您只能删除处于附加状态的实体。这意味着需要一些额外的逻辑来检查它是否已附加(包含在持久性上下文中),如果没有附加它(合并它)。
第四种方法显示通过 (JPQL) 查询进行数据检索。查询名称和参数名称都不是类型安全的。 DAO 方便地将其隐藏在类型安全的 Java 方法后面。是的,您可以将这些名称提取为常量,但仍不会强制执行此特定参数和此特定查询之间的关联。
一般来说,DAO 允许进行一定量的重构。在某些时候,我可能想用条件查询替换 JPQL 查询。在所有调用站点更改此设置可能会出现问题。还有一种情况是,实体管理器作为通用 DAO 实在是太强大了。我不想将这些发送到所有客户端站点(对于远程客户端,这甚至是不可能的或非常糟糕的做法)。
最后,从本身不具有事务性的客户端代码中使用实体管理器,意味着该客户端必须担心事务。这给代码增加了很多冗长的内容。使用 DAO,客户端代码变得更加简单:
To give you some idea of what a more modern DAO would look like:
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:
您的示例看起来像是一张完美的“之前”图片,在使用 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.
您可以使用Java Persistence API,并且大多数这些无聊的代码都是不必要的。
You could use Java Persistence API and most of this boring code would be unnecessary.
有史以来最糟糕的代码味道:你再次重新发明轮子。为什么不使用一些开放库,例如 Spring JDBC ? (注意:您也可以阅读代码来从中学习!)
如果您在这里练习,和/或不允许使用外部代码,那么这里有一些增强您的代码的提示:
JdbcTemplate
和RowMapper
类的代码)me
来避免这种情况: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:
JdbcTemplate
andRowMapper
classes)me
at class initialization time: