在 Spring JDBC 开发中,我们发现必须在所有DAO模式里的查询,插入,更新和删除操作中创建大量的冗余代码(创建连接,关闭连接,处理异常)。它的效率并不是很高,容易出错和乏味。不过,我们可以使用 JdbcTemplate 和 JdbcDaoSupport 类来简化整个数据库的操作过程。
1. JdbcTemplate
1.1 JdbcTemplate插入操作
1.1.1 单条插入
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void insert(Article article) {
String sql = "INSERT INTO ARTICLE (ID, TITLE, CONTENT) VALUES (?, ?, ?)";
jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update(sql, new Object[]{article.getId(), article.getTitle(), article.getContent()});
}
1.1.2 批量插入
在某些情况下,可能需要将一批记录插入到数据库中。如果你对每条记录调用一个插件的方法,SQL语句将被重复编译,造成系统缓慢进行。解决上述问题,可以使用 JdbcTemplate BATCHUPDATE()方法来执行批量插入操作。用这种方法,该语句只被编译一次,执行多次。
public void insertArticles(final List<Article> articles) {
String sql = "INSERT INTO ARTICLE (ID, TITLE, CONTENT) VALUES (?, ?, ?)";
jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
public void setValues(PreparedStatement ps, int i) throws SQLException {
Article article = articles.get(i);
ps.setLong(1, article.getId());
ps.setString(2, article.getTitle());
ps.setString(3, article.getContent());
}
public int getBatchSize() {
return articles.size();
}
});
}
1.2 JdbcTemplate查询
1.2.1 查询单行数据
有两种方法来查询或从数据库中提取单行记录,并将其转换成一个模型类。
- 自定义RowMapper
- BeanPropertyRowMapper
自定义RowMapper
建议实现 RowMapper 接口来创建自定义的RowMapper
public class ArticleRowMapper implements RowMapper<Article> {
public Article mapRow(ResultSet rs, int rowNum) throws SQLException {
return new Article(rs.getInt("ID"), rs.getString("TITLE"), rs.getString("CONTENT"));
}
}
传递给 queryForObject()方法,返回的结果将调用自定义 mapRow()方法的值匹配到属性。
public Article getArticleById(int id) {
String sql = "SELECT * FROM ARTICLE WHERE ID = ?";
jdbcTemplate = new JdbcTemplate(dataSource);
return jdbcTemplate.queryForObject(sql, new Object[]{id}, new ArticleRowMapper());
}
BeanPropertyRowMapper
public Article getArticleById(int id) {
String sql = "SELECT * FROM ARTICLE WHERE ID = ?";
jdbcTemplate = new JdbcTemplate(dataSource);
return jdbcTemplate.queryForObject(sql, new Object[]{id}, new BeanPropertyRowMapper<Article>(Article.class));
}
使用BeanPropertyRowMapper,需要在实体类Article里有默认的构造函数。负责初始化Article失败。
1.2.2 查询多行
手动映射
由于 RowMapper 不支持 queryForList()方法,需要手动映射它。
public List<Article> getArticles() {
String sql = "SELECT * FROM ARTICLE";
jdbcTemplate = new JdbcTemplate(dataSource);
List<Article> articles = new ArrayList<Article>();
List<Map<String, Object>> rows = jdbcTemplate.queryForList(sql);
for (Map row : rows) {
Article article = new Article((Long)row.get("ID"), (String)row.get("TITLE"), (String)row.get("CONTENT"));
articles.add(article);
}
return articles;
}
BeanPropertyRowMapper
public List<Article> getArticles() {
String sql = "SELECT * FROM ARTICLE";
jdbcTemplate = new JdbcTemplate(dataSource);
return jdbcTemplate.query(sql, new BeanPropertyRowMapper<Article>(Article.class));
}
2. JdbcDaoSupport
通过扩展 JdbcDaoSupport,设置数据源,并且 JdbcTemplate 在类中不再是必需的,只需要正确的数据源注入DAO。就可以使用 getJdbcTemplate()方法得到 JdbcTemplate。
public class JdbcArticleDao extends JdbcDaoSupport implements ArticleDao {
/*private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}*/
public void insert(Article article) {
String sql = "INSERT INTO ARTICLE (ID, TITLE, CONTENT) VALUES (?, ?, ?)";
//jdbcTemplate = new JdbcTemplate(dataSource);
getJdbcTemplate().update(sql, new Object[]{article.getId(), article.getTitle(), article.getContent()});
}
public List<Article> getArticles() {
String sql = "SELECT * FROM ARTICLE";
//bcTemplate = new JdbcTemplate(dataSource);
return getJdbcTemplate().query(sql, new BeanPropertyRowMapper<Article>(Article.class));
}
public Article getArticleById(int id) {
String sql = "SELECT * FROM ARTICLE WHERE ID = ?";
//jdbcTemplate = new JdbcTemplate(dataSource);
return getJdbcTemplate().queryForObject(sql, new Object[]{id}, new BeanPropertyRowMapper<Article>(Article.class));
}
}