I am studying how to execute query on a database using JDBC in Spring Framework.
I am following this tutorial: http://www.tutorialspoint.com/spring/spring_jdbc_example.h
Here is the typical pattern I use with BeanPropertyRowMapper. It saves a lot of coding. Your query needs to alias each column to match the property name in the class. In this case species_name as species
and the other column names happen to match already.
public class Animal {
String species;
String phylum;
String family;
...getters and setters omitted
}
@Repository
public class AnimalRepository {
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@Autowired
public void setDataSource(DataSource dataSource) {
this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}
public List<Animal> getAnimalsByPhylum(String phylum) {
String sql = " SELECT species_name as species, phylum, family FROM animals"
+" WHERE phylum = :phylum";
Map<String, Object> namedParameters = new HashMap<String, Object>();
namedParameters.put("phylum", phylum);
SqlParameterSource params = new MapSqlParameterSource(namedParameters);
List<Animal> records = namedParameterJdbcTemplate.query(sql,
params, BeanPropertyRowMapper.newInstance(Animal.class));
return records;
}
}
An alternative is to use a RowMapper (this example just uses an anonymous class) when you need more customization per row:
List<Animal> records = namedParameterJdbcTemplate.query(sql,
params, new RowMapper<Animal>(){
public Animal mapRow(ResultSet rs, int i) throws SQLException {
Animal animal = new Animal();
animal.setSpecies(rs.getString("species_name"));
if (some condition) {
animal.setPhylum(rs.getString("phylum"));
} else {
animal.setPhylum(rs.getString("phylum")+someThing());
}
animal.setFamily(rs.getString("family"));
return animal;
}
});
When you pass an instance of your RowMapper
to the JdbcTemplate
method
List <Student> students = jdbcTemplateObject.query(SQL, new StudentMapper());
The JdbcTemplate
depending on which method you called, will internally use the mapper with the result set it gets from the JDBC Connection to create an object of your requested type. For example, since you called JdbcTemplate#query(String, RowMapper)
, the method will use your String SQL to query the database and will loop through each "row" in the ResultSet
kind of like this:
ResultSet rs = ... // execute query
List<Student> students = ...// some list
int rowNum = 0;
while(rs.next()) {
Student student = rowMapper.mapRow(rs, rowNum);
students.add(student);
rowNum++;
}
return students;
So, Spring
's JdbcTemplate
method will use the RowMapper
you provide and call its mapRow
method to create the expected return object.
You might like to look at Martin Fowler's Data Mapper in conjunction with Table Data Gateway for an idea of how these things are distributed and provide low coupling.
So, who call this mapRow method? is it called automatically by the Spring Framework? (because in this example is never called manually...)
This is automatically called by spring framework. All You need is to specify
- Connection parameters,
- SQL statement
- Declare parameters and provide parameter values
- Do the work for each iteration.
Using RowMapper in Spring
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
public class RowsMap implements RowMapper<EmpPojo>{
@Override
public EmpPojo mapRow(ResultSet rs, int counts) throws SQLException {
EmpPojo em=new EmpPojo();
em.setEid(rs.getInt(1));
em.setEname(rs.getString(2));
em.setEsal(rs.getDouble(3));
return em;
}
}
Finally in Main class
List<EmpPojo> lm=jt.query("select * from emps", new RowsMap());
for(EmpPojo e:lm)
{
System.out.println(e.getEid()+" "+e.getEname()+" "+e.getEsal());
}