java java中的通用DAO
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2848692/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
generic DAO in java
提问by akshay
I am trying to develop generic DAO in java. I have tried the following. Is this a good way to implement generic DAO? I don't want to use hibernate. I am trying to make it as generic as possible so that I don't have to repeat the same code over and over again.
我正在尝试用 Java 开发通用 DAO。我尝试了以下方法。这是实现通用 DAO 的好方法吗?我不想使用休眠。我试图让它尽可能通用,这样我就不必一遍又一遍地重复相同的代码。
public abstract class AbstractDAO<T> {
protected ResultSet findbyId(String tablename, Integer id){
ResultSet rs= null;
try {
// the following lines are not working
pStmt = cn.prepareStatement("SELECT * FROM "+ tablename+ "WHERE id = ?");
pStmt.setInt(1, id);
rs = pStmt.executeQuery();
} catch (SQLException ex) {
System.out.println("ERROR in findbyid " +ex.getMessage() +ex.getCause());
ex.printStackTrace();
}finally{
return rs;
}
}
}
Now I have:
我现在有:
public class UserDAO extends AbstractDAO<User>{
public List<User> findbyid(int id){
Resultset rs =findbyid("USERS",id) // "USERS" is table name in DB
List<Users> users = convertToList(rs);
return users;
}
private List<User> convertToList(ResultSet rs) {
List<User> userList= new ArrayList();
User user= new User();;
try {
while (rs.next()) {
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("username"));
user.setFname(rs.getString("fname"));
user.setLname(rs.getString("lname"));
user.setUsertype(rs.getInt("usertype"));
user.setPasswd(rs.getString("passwd"));
userList.add(user);
}
} catch (SQLException ex) {
Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
}
return userList;
}
}
回答by Espen
If you can live with Spring, I will suggest the following improvements:
如果你能忍受 Spring,我会建议以下改进:
- Let Spring do the exception handling.
- Use JdbcTemplate instead of creating prepared statements yourself.
- 让 Spring 来做异常处理。
- 使用 JdbcTemplate 而不是自己创建准备好的语句。
Independent of using Spring, I will recommend the following:
独立于使用 Spring,我将推荐以下内容:
- Don't send the table name as parameter. That should be done in the initialization phase.
- Use a String on the id parameter, since that's much more generic.
- Consider returning a generic object instead of a collection, since the collection should always contain only one object.
- 不要将表名作为参数发送。这应该在初始化阶段完成。
- 在 id 参数上使用字符串,因为它更通用。
- 考虑返回一个通用对象而不是一个集合,因为集合应该总是只包含一个对象。
An improved AbstractDao with Spring:
使用 Spring 改进的 AbstractDao:
import java.util.Collection;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
public abstract class AbstractDao<T> {
protected final RowMapper<T> rowMapper;
protected final String findByIdSql;
protected final JdbcTemplate jdbcTemplate;
protected AbstractDao(RowMapper<T> rowMapper, String tableName,
JdbcTemplate jdbcTemplate) {
this.rowMapper = rowMapper;
this.findByIdSql = "SELECT * FROM " + tableName + "WHERE id = ?";
this.jdbcTemplate = jdbcTemplate;
}
public Collection<T> findById(final String id) {
Object[] params = {id};
return jdbcTemplate.query(findByIdSql, params, rowMapper);
}
}
As you see, no exception handling or hacking with the primitive SQL classes. This templates closes the ResultSet for you, which I can't see in your code.
如您所见,原始 SQL 类没有异常处理或黑客攻击。此模板为您关闭了 ResultSet,我在您的代码中看不到。
And the UserDao:
和 UserDao:
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
public class UserDao extends AbstractDao<User> {
private final static String TABLE_NAME = "USERS";
public UserDao(JdbcTemplate jdbcTemplate) {
super(new UserRowMapper(), TABLE_NAME, jdbcTemplate);
}
private static class UserRowMapper implements RowMapper<User> {
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setUserName(rs.getString("username"));
user.setFirstName(rs.getString("fname"));
user.setLastName(rs.getString("lname"));
return user;
}
}
}
Updated:
更新:
When you know the id and the id corresponds to a single row in the database, you should consider returning a generic object instead of a collection.
当您知道 id 并且该 id 对应于数据库中的单行时,您应该考虑返回一个通用对象而不是一个集合。
public T findUniqueObjectById(final String id) {
Object[] params = {id};
return jdbcTemplate.queryForObject(findByIdSql, params, rowMapper);
}
This makes your service code more readable, since you don't need to retrieve the user from a list, but only:
这使您的服务代码更具可读性,因为您不需要从列表中检索用户,而只需:
User user = userDao.findUniqueObjectById("22");
回答by Adamski
My advice:
我的建议:
- Don'twrite a generic DAO; Generic classes come back to bite you when you realise they don't quite do what you need in a specific situation and often end up growing in complexity to cover the ever-increasing array of use-cases. Better to code application specific DAOs and then attempt to generify any common behaviour later on.
- Consider using Spring JDBCto write app-specific DAOs but in a much more compact and less error-prone fashion than JDBC. Also, unlike Hibernate, Spring JDBC only acts a thin wrapper around raw JDBC giving you finer grained control and more visibility.
- 不要编写通用的 DAO;当您意识到泛型类在特定情况下不能完全满足您的需求时,它们又会回来咬您,并且通常最终会变得复杂以涵盖不断增加的用例。最好对特定于应用程序的 DAO 进行编码,然后尝试生成任何常见的行为。
- 考虑使用Spring JDBC编写特定于应用程序的 DAO,但比 JDBC 更紧凑且不易出错。此外,与 Hibernate 不同,Spring JDBC 仅充当原始 JDBC 的薄包装器,为您提供更细粒度的控制和更高的可见性。
Example
例子
// Create or inject underlying DataSource.
DataSource ds = ...
// Initialise Spring template, which we'll use for querying.
SimpleJdbcTemplate tmpl = new SimpleJdbcTemplate(ds);
// Create collection of "Role"s: The business object we're interested in.
Set<Role> roles = new HashSet<Role>();
// Query database for roles, use row mapper to extract and create
// business objects and add to collection. If an error occurs Spring
// will translate the checked SQLException into an unchecked Spring
// DataAccessException and also close any open resources (ResultSet, Connection).
roles.addAll(tmpl.query("select * from Role", new ParameterizedRowMapper<Role>() {
public Role mapRow(ResultSet resultSet, int i) throws SQLException {
return new Role(resultSet.getString("RoleName"));
}
}));
回答by Ravindra Gullapalli
It is okay but change the method
没关系,但改变方法
private List<User> convertToList(ResultSet rs) {
List<User> userList= new ArrayList();
User user= new User();;
try {
while (rs.next()) {
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("username"));
user.setFname(rs.getString("fname"));
user.setLname(rs.getString("lname"));
user.setUsertype(rs.getInt("usertype"));
user.setPasswd(rs.getString("passwd"));
userList.add(user);
}
} catch (SQLException ex) {
Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
}
return userList;
}
to
到
private List<User> convertToList(ResultSet rs) {
List<User> userList= new ArrayList<User>();
try {
while (rs.next()) {
User user= new User();
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("username"));
user.setFname(rs.getString("fname"));
user.setLname(rs.getString("lname"));
user.setUsertype(rs.getInt("usertype"));
user.setPasswd(rs.getString("passwd"));
userList.add(user);
}
} catch (SQLException ex) {
Logger.getLogger(UserDAO.class.getName()).log(Level.SEVERE, null, ex);
}
return userList;
}
User object should be created inside while loop.
用户对象应该在 while 循环中创建。
回答by Matthieu BROUILLARD
Do not reinvent the wheel, you can already find good projects doing this, example generic-daoproject on google.
不要重新发明轮子,你已经可以找到这样做的好项目,例如谷歌上的generic-dao项目。
EDIT:answered too quickly probably, the google project is JPA based but nevertheless you can use some of the concepts inside it.
编辑:可能回答得太快了,google 项目是基于 JPA 的,但是您可以使用其中的一些概念。
回答by Robert
You need to add a space before your "WHERE" clause see below:
您需要在“WHERE”子句之前添加一个空格,请参见下文:
pStmt = cn.prepareStatement("SELECT * FROM "+ tablename+ "WHERE id = ?");
to
到
pStmt = cn.prepareStatement("SELECT * FROM "+ tablename+ " WHERE id = ?");
回答by Dmitri
If I've correctly understood the problem statement, you are trying to implement kind of an isolation layer between your services and a plain database exposed through a JDBC interface. The isolation layer would serve as a data mapper of your POJO domain objects to SQL data sets. That is precisely the task of iBATIS library, which I recommend you to ponder over instead of implementing the homebrew GenericDAO class.
如果我正确理解了问题陈述,那么您正在尝试在您的服务和通过 JDBC 接口公开的普通数据库之间实现某种隔离层。隔离层将充当 POJO 域对象到 SQL 数据集的数据映射器。这正是iBATIS 库的任务,我建议您考虑一下,而不是实现自制的 GenericDAO 类。
回答by srikanth N
Even though everyone suggests Spring and its API here, it uses metadata and it's a bad combination of code. So don't use generic DAO's or Spring at all.
尽管每个人都在这里建议使用 Spring 及其 API,但它使用元数据并且代码组合很糟糕。所以根本不要使用通用的 DAO 或 Spring。
Generic code is heavy and does multiply your load on.
通用代码很重,确实会增加您的负担。

