问题
Learning java. When I make a jdbc call with a query in java, how can I store that record. I have seen them being stored in hash collections by more advanced coders but I am not sure how to use the java collections framework to store records and iterate through them. Does anyone have a simple code example they can share and explain for storing records of resultset like a hashmap?
Thank you in advance. sorry for the noob question.
回答1:
If you are using a framework, then you have to play by the rules of that framework for ORM. If you're rolling your own classes and making JDBC calls on your own, then you can provide a simple "framework" of your own as follows:
- Every table in the database is a class
- Every column in the table is a class's instance field
- You can write a generic query method that returns your data as lists of objects
- Use a factory to generate the objects that you wish to create for the queries you use
Here is a simple example of this paradigm:
I have a database Clients, so I will write a class to represent the data model. This class is written using JavaFX properties so that the elements can be represented in a GUI.
public class Client extends DB {
private IntegerProperty id = new SimpleIntegerProperty();
private StringProperty lastName = new SimpleStringProperty();
private StringProperty firstName = new SimpleStringProperty();
public final int getID() {return this.id.get(); }
void setID(int id) { this.id.set(id); }
public final IntegerProperty idProperty() { return this.id; }
public final String getLastName() { return this.lastName.get(); }
public final void setLastName(String ln) { this.lastName.set(ln); }
public final StringProperty lastNameProperty() { return this.lastName; }
public final String getFirstName() { return this.firstName.get(); }
public final void setFirstName(String fn) { this.firstName.set(fn); }
public final StringProperty firstNameProperty() { return this.firstName; }
Client(ResultSet jrs) {
try {
this.id.set(jrs.getInt(DB.CLI_FIELD_ID));
this.lastName.set(jrs.getString(DB.CLI_FIELD_LAST));
this.firstName.set(jrs.getString(DB.CLI_FIELD_FIRST));
} catch (SQLException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
System.exit(1);
}
}
static class ClientFactory implements Callback<ResultSet,Client> {
@Override
public Client call(ResultSet jrs) {
return new Client(jrs);
}
}
This class contains three things:
The JavaFX bean definitions for the instance fields of the class so that they may be used with the GUI controls provided by the JavaFX framework.
A constructor which initializes an instance of the Client class with the data contained in the currently indicated row of a ResultSet that is passed as a parameter to the constructor.
A nested static class that provides the factory used to create new Client objects. It is very simple. All the factory does is invoke the constructor for Client by passing a ResultSet row to it. Notice that this class implements the Callback interface to indicate that this factory expects to receive one parameter of the type Resultset and that it will return one result of type Client. I chose to use the Callback interface for this purpose, but the programmer could use his own similar interface for the factory.
To make this homegrown framework work, a home-grown query method can be used similar to the following. This method allows the programmer to query with a single parameter of type long, but it could be easily abstracted to allow a query to be built using a supplied list of parameters:
static <E> ObservableList<E> doGenericQuery(long param,
String sql, Callback<ResultSet,E> factory) {
Connection con = null;
ObservableList<E> queryList = FXCollections.<E>observableArrayList();
try {
con = MyDataBase.getConnection(); // provide your own connection here
PreparedStatement ps = con.PreparedStatement(sql);
ps.setLong(1, param);
ResultSet jrs = ps.executeQuery();
while (jrs.next()) {
queryList.<E>add(factory.<ResultSet,E>call(jrs));
}
} catch (SQLException e) {
Logger.getLogger(DB.class.getName()).log(Level.SEVERE, null, e);
} finally {
if (jrs != null) try { jrs.close(); } catch (SQLException e) { }
}
return queryList;
}
This generic method queries your database and transforms the ResultSet into a List of objects that is based on one of your data model table classes (here an ObservableList because, again, JavaFX). The key line is the generic method call:
queryList.<E>add(factory.<ResultSet,E>call(jrs));
Which uses the factory for one of your data model classes (Class E) to build an object for that class E using the row of data currently indicated in your ResultSet.
Building a database app this way has advantages and disadvantages: it may be more performant than relying upon an ORM framework, but it also requires you to do all the database to object mapping footwork. It frees you from dependency upon a framework, but you'll have to write more code, particularly boilerplate.
If your application is simple, or your database is not too complex you may wish to homegrow your own "framework" in a similar way.
回答2:
Your question is tagged as a spring question; so I'm going to give you a spring answer. Here are the pieces involved:
- Your java object
- A RowMapper class
- A ResultSetExtractor class
- Your query
- A JdbcTemplate
Storing result set data in a hashmap and all the associated code to reliably get at that data can get messy. Use spring's paradigm of a data extractor to hide the messy details of matching your java objects to a database and you can then proceed to write java as your normally would, as if your application wasn't hooked up to a database at all.
A JdbcTemplate is a class given to you by Spring which you configure that allows you to execute queries on a database. Using spring, you don't have to write the jdbctemplate, its provided for you but you do need to write the other parts, and it would look something like this:
My java object
public class Shoe {
int size;
String color;
String id;
}
ShoeExtractor
public class ShoeExtractor implements ResultSetExtractor {
public Object extractData(ResultSet rs) throws SQLException, DataAccessException {
Shoe s = new Shoe();
// setting object's values to result set's values
s.setSize(rs.getInt(1));
s.setColor(rs.getString(2));
s.setId(rs.getString(3));
return s;
}
RowMapper
public class ShoeRowMapper implements RowMapper {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
ShoeExtractor shoeExtractor = new ShoeExtractor ();
return shoeExtractor.extractData(rs);
}
}
In your "main"
@Resource
private JdbcTemplate jdbcTemplate;
StringBuffer statement = new StringBuffer();
statement.append("select size, color, id from shoes");
List<Shoe> shoes = jdbcTemplate.query(statement.toString(), new ShoeRowMapper ()):
回答3:
In java, it is idiomatic to create a class for each result or for subsets of each result. For example
patientResultSet => patientEntityObject
It is not idiomatic to store it in a Collection. Reason being, it's difficult to inspect it to figure out how to get the field you want.
回答4:
usually you have to map the resultset data into some sort of class by your own. This is called Object Relational Mapping (ORM, I assume your are ussing an structured db) . You can do it yourself as shown in a previou answer or by an existing api/product such as jpa/hibernate
来源:https://stackoverflow.com/questions/16571358/what-data-structure-to-use-with-a-java-jdbc-resultset-what-is-the-defacto-stand