7

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;
        }

    }

}

今私が持っています:

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;

    }
}
4

7 に答える 7

6

Springと一緒に暮らせる場合は、次の改善を提案します。

  • Springに例外処理を任せます。
  • プリペアドステートメントを自分で作成する代わりに、JdbcTemplateを使用します。

Springの使用とは別に、次のことをお勧めします。

  • テーブル名をパラメータとして送信しないでください。これは、初期化フェーズで実行する必要があります。
  • idパラメータには文字列を使用します。これは、はるかに一般的だからです。
  • コレクションには常に1つのオブジェクトのみが含まれる必要があるため、コレクションではなくジェネリックオブジェクトを返すことを検討してください。

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);
    }
}

ご覧のとおり、プリミティブSQLクラスを使用した例外処理やハッキングはありません。このテンプレートは、コードに表示されないResultSetを閉じます。

そして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;
        }
    }
}

更新しました:

idがわかっていて、idがデータベース内の単一の行に対応している場合は、コレクションではなくジェネリックオブジェクトを返すことを検討する必要があります。

public T findUniqueObjectById(final String id) {
    Object[] params = {id};
    return jdbcTemplate.queryForObject(findByIdSql, params, rowMapper);
}

これにより、リストからユーザーを取得する必要がないため、サービスコードが読みやすくなりますが、次の場合に限ります。

User user = userDao.findUniqueObjectById("22");
于 2010-05-17T12:51:13.870 に答える
5

私のアドバイス:

  • 一般的な DAO を記述しないでください。ジェネリック クラスは、特定の状況で必要なことを十分に実行できず、ますます増加する一連のユース ケースをカバーするために複雑さを増してしまうことが多いことに気付くと、再び噛み付きます。アプリケーション固有の DAO をコーディングしてから、後で一般的な動作を生成することを試みることをお勧めします。
  • Spring JDBCを使用してアプリ固有の DAO を作成することを検討してください。ただし、JDBC よりもはるかにコンパクトでエラーが発生しにくい方法です。また、Hibernate とは異なり、Spring JDBC は未加工の JDBC の薄いラッパーとしてのみ機能し、よりきめ細かな制御と可視性を提供します。

// 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"));
  }
}));
于 2010-05-17T11:57:53.650 に答える
1

いいけど方法変えて

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; 

    } 

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; 

    } 

ユーザー オブジェクトは while ループ内で作成する必要があります。

于 2010-05-17T11:54:15.803 に答える
0

私が問題の説明を正しく理解していれば、サービスと JDBC インターフェイスを介して公開されるプレーンなデータベースとの間に一種の分離レイヤーを実装しようとしています。分離レイヤーは、POJO ドメイン オブジェクトから SQL データ セットへのデータ マッパーとして機能します。それがまさにiBATIS ライブラリのタスクであり、自作の GenericDAO クラスを実装する代わりに熟考することをお勧めします。

于 2011-08-21T15:49:37.863 に答える
0

車輪を再発明しないでください。Google のgeneric-daoプロジェクトなど、これを行う優れたプロジェクトを既に見つけることができます。

編集:おそらく答えが早すぎます.GoogleプロジェクトはJPAベースですが、それでもその中のいくつかの概念を使用できます.

于 2010-05-17T11:47:49.780 に答える
0

「WHERE」句の前にスペースを追加する必要があります。以下を参照してください。

pStmt = cn.prepareStatement("SELECT * FROM "+ tablename+ "WHERE id = ?");

 pStmt = cn.prepareStatement("SELECT * FROM "+ tablename+ " WHERE id = ?");
于 2010-05-17T15:17:14.747 に答える
-1

ここでは誰もが Spring とその API を提案していますが、これはメタデータを使用しており、コードの組み合わせが不適切です。したがって、一般的な DAO や Spring はまったく使用しないでください。

汎用コードは重く、負荷が倍増します。

于 2011-04-07T13:38:15.570 に答える