2010-05-17 5 views
7

Ich versuche, generische DAO in Java zu entwickeln. Ich habe folgendes versucht. Ist das eine gute Möglichkeit, generisches DAO zu implementieren? Ich möchte den Ruhezustand nicht verwenden. Ich versuche es so allgemein wie möglich zu machen, damit ich nicht immer wieder den gleichen Code wiederholen muss.generische DAO in Java

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

    } 

} 

Jetzt habe ich:

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; 

    } 
} 
+0

Was ist das Problem? – Bozho

+0

PLZ sehe die Zeile sagen // die folgenden Lins in nicht funktioniert; – akshay

+0

Warum möchten Sie nicht Hibernate (oder anderes ORM) verwenden? –

Antwort

0

Sie das Rad nicht neu erfinden, können Sie bereits gute Projekte dies zu tun finden, Beispiel generic-dao Projekt auf Google.

EDIT: beantwortet zu schnell wahrscheinlich, das Google-Projekt PPV basiert, aber dennoch können Sie einige der Konzepte im Inneren nutzen.

+0

Ich möchte wissen, warum meine Zeile im Code nicht funktioniert – akshay

1

Es ist in Ordnung, aber die Methode ändern

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; 

    } 

zu

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; 

    } 

Benutzerobjekt innerhalb while-Schleife erstellt werden soll.

+0

plz siehe die Zeile // die folgenden Lins in nicht funktioniert; – akshay

+0

Dieser Code wird Ressourcen verlieren, wenn eine SQLException ausgelöst wird. Sie müssen sicherstellen, dass das ResultSet, die Anweisung und die Verbindung geschlossen sind. Der einfachste Weg ist die Verwendung eines Frameworks wie Spring JDBC anstelle von Raw JDBC. – Adamski

+0

Was ist der Fehler? –

5

Mein Rat:

  • Sie nicht eine generische DAO schreiben; Generische Klassen kommen zurück, um dich zu beißen, wenn du erkennst, dass sie nicht genau das tun, was du in einer bestimmten Situation benötigst und oft in der Komplexität anwächst, um die ständig wachsende Anzahl von Anwendungsfällen abzudecken. Besser, anwendungsspezifische DAOs zu programmieren und später jedes gängige Verhalten zu generalisieren.
  • Verwenden Sie Spring JDBC, um anwendungsspezifische DAOs zu schreiben, aber viel kompakter und weniger fehleranfällig als JDBC. Im Gegensatz zu Hibernate handelt es sich bei Spring JDBC nur um einen dünnen Wrapper um rohe JDBC, wodurch Sie feinere Kontrolle und mehr Sichtbarkeit erhalten.

Beispiel

// 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")); 
    } 
})); 
+0

Noch eine Abstimmung für Spring JDBC. Es behandelt eine Menge des Boilerplate-Verbindungsmaterials (um Ressourcenlecks zu vermeiden). Darüber hinaus bietet es eine viel bessere Möglichkeit zum Zuordnen von Spalten zu Ihren Objekten. Ein anderer Kommentar, ich würde den Primärschlüssel Spaltenname nicht fest codieren.Sobald Sie das tun, kommt jemand, der eine Tabelle mit einer Spalte mit dem Namen etwas anderes erstellt oder einen mehrspaltigen Primärschlüssel verwendet. – David

6

Wenn Sie mit Frühling leben kann, werde ich die folgenden Verbesserungen vorschlagen:

  • lassen den Frühling die Ausnahmebehandlung zu tun.
  • Verwenden Sie JdbcTemplate, anstatt selbst vorbereitete Anweisungen zu erstellen.

Unabhängig von mit Spring, werde ich folgendes empfehlen:

  • Sie nicht den Tabellennamen als Parameter senden. Dies sollte in der Initialisierungsphase erfolgen.
  • Verwenden Sie eine Zeichenfolge für den ID-Parameter, da dies viel allgemeiner ist.
  • Sie sollten ein generisches Objekt anstelle einer Auflistung zurückgeben, da die Auflistung immer nur ein Objekt enthalten sollte.

Eine verbesserte AbstractDao mit Spring:

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

Wie Sie sehen, keine Ausnahmebehandlung oder Hacking mit den primitiven SQL-Klassen. Diese Vorlage schließt das ResultSet für Sie, das ich in Ihrem Code nicht sehen kann.

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

Aktualisiert:

Wenn Sie die ID kennen und die ID entspricht einer einzelnen Zeile in der Datenbank, sollten Sie ein generisches Objekt anstelle eines betrachten Rückkehr Sammlung.

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

Das macht Ihren Service-Code besser lesbar, da Sie nicht den Benutzer aus einer Liste abrufen müssen, aber nur:

User user = userDao.findUniqueObjectById("22"); 
+0

Ich versuche, Ihren Ansatz zu implementieren und alles scheint in Ordnung zu sein, außer zu entscheiden, wo und wie das userDao-Objekt initialisiert wird. Vor der Implementierung Ihres Ansatzes habe ich userDao mit autowired Annotation in der userService-Klasse verwendet. Aber jetzt in Ihrem Beispiel gibt es keinen leeren Konstruktor und kann dao nicht als autowired Objekt verwenden. Ich dachte, es kann einen leeren Konstruktor der Dao-Klasse geben, der einen anderen Konstruktor mit autowired jdbctemplate aufruft. Ist das nützlich? –

0

Sie benötigen einen Platz, bevor Sie „WHERE“ hinzufügen Klausel siehe unten:

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

zu

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

Obwohl alle Benutzer Spring und seine API hier vorschlagen, verwendet es Metadaten und es ist eine schlechte Kombination von Code. Verwenden Sie also keine generischen DAO oder Spring.

Allgemeiner Code ist schwer und multipliziert Ihre Belastung.

+0

Es klingt, als hätten Sie schlechte Erfahrungen mit generischem Code gemacht. Metadaten sind nicht schlecht, wenn sie richtig gemacht werden - je mehr Informationen Sie in Metadaten aus dem Code verschieben, desto besser sollte Ihr verbleibender Code sein (wenn dies richtig gemacht wird). Generischer Code ist in vielen Fällen der einzige Weg, um zu gehen (DRY übertrumpft die meisten anderen Richtlinien/Gerüche und ist die Wurzel der meisten guten Code- und Kodierungspraktiken). –

0

Wenn ich habe das Problem richtig Aussage verstanden, versuchen Sie Art einer Isolationsschicht zwischen Diensten und einer einfachen Datenbank über eine JDBC-Schnittstelle ausgesetzt zu implementieren. Die Isolationsschicht würde als Datenmapper Ihrer POJO-Domänenobjekte für SQL-Datensätze dienen. Das ist genau die Aufgabe von iBATIS library, die ich Ihnen empfehlen zu überlegen, anstatt die Homebrew-GenericDAO-Klasse zu implementieren.