文章目录
- DAO模式
- JDBC API
- 基于 Spring JdbcTemplate的数据访问层实现
- 将SQLException转译到DataAccessException
- SpringBoot使用JdbcTemplate的配置
- JdbcTemplate的常用方法
- 完整案例
DAO模式
- 为了统一和简化软件系统的数据访问操作,在常规的Java软件系统分层中,都会定义DAO数据访问层,使用该模式,既可以分离业务逻辑与数据访问,又可以屏蔽各种数据底层操作的差异。

DAO模式示例
public interface UserDAO {
List<User> findAll();
User findById(Long id);
Long addUser(User user);
void updateUser(User user);
void deleteById(Long id);
List<User> findByName(String name);
}
public class UserService {
private UserDAO userDAO;
public List<User> listUsers() {
return userDAO.findAll();
}
public User saveUser(User user) {
if (user.getId() != null && user.getId() != 0) {
userDAO.updateUser(user);
} else {
userDAO.addUser(user);
}
return user;
}
public void deleteUser(Long id) {
userDAO.deleteById(id);
}
public User findUser(Long id) {
return userDAO.findById(id);
}
public List<User> searchUser(String name) {
return userDAO.findByName(name);
}
}
JDBC API
- 在Spring JdbcTemplate诞生之前,开发人员需要使用JDBC API实现数据访问层:
public class UserDAOImpl implements UserDAO {
@Override
public User findById(Long id) throws SQLException {
Connection conn = null;
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/user_info", "root", "root");
String sql = "select id,name,email from user where id=" + id;
Statement st = conn.createStatement();
ResultSet resultSet = st.executeQuery(sql);
User user = new User();
if (resultSet != null) {
user.setId(resultSet.getArray("id"));
user.setName(resultSet.getArray("name"));
user.setEmail(resultSet.getArray("email"));
}
} catch (SQLException ex) {
throw new SQLException(ex);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException ex) {
throw new SQLException(ex);
}
}
}
}
...
}
- 由于JDBC API主要是面向底层的数据库操作,所以存在比较大的缺点:
- 需要频繁的创建数据库连接;
- 涉及到的增删改查等功能需要在各个java文件中编写大量代码
- 对于底层事务、数据类型转换等都需要手动处理,效率低下
基于 Spring JdbcTemplate的数据访问层实现
- 为了解决JDBC API的缺点,Spring框架构建Spring JdbcTemplate模板类,封装了所有基于JDBC API的数据访问代码,同时也将数据访问异常统一纳入Spring异常管理。

@Repository
public class UserDAOImpl implements UserDAO {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public List<User> findAll() {
return jdbcTemplate.query("select id,name,email from user;",
new Object[]{}, new BeanPropertyRowMapper<>(User.class));
}
@Override
public User findById(Long id) {
return jdbcTemplate.queryForObject("select id,name,email from user where id=?;",
new Object[]{id}, new BeanPropertyRowMapper<>(User.class));
}
@Override
public Long addUser(User user) {
return Integer.toUnsignedLong(jdbcTemplate.update("insert into user(name,email) values(?,?);"
, user.getName(), user.getEmail()));
}
@Override
public void updateUser(User user) {
jdbcTemplate.update("update user set name=?,email=? where id =?;"
, user.getName(), user.getEmail(), user.getId());
}
@Override
public void deleteById(Long id) {
jdbcTemplate.update("delete from user where id=?", new Object[]{id});
}
@Override
public List<User> findByName(String name) {
return jdbcTemplate.query("select id,name,email from user where name=?;",
new Object[]{name}, new BeanPropertyRowMapper<>(User.class));
}
}
- 从以上代码可以看出,使用Spring JdbcTemplate模板类,开发人员只需关心与数据访问逻辑相关的东西 ,对于JDBC API底层实现的相关细节不用过多地考虑。
将SQLException转译到DataAccessException
- Spring JdbcTemplate对SQLException所提供的异常信息进行统一转译,将基于JDBC API的数据访问异常纳入Spring身的异常体系中,极大地简化了业务逻辑层对数据访问异常的处理。

- 转译抽象类源码
public abstract class AbstractFallbackSQLExceptionTranslator implements SQLExceptionTranslator {
@Override
@Nullable
public DataAccessException translate(String task, @Nullable String sql, SQLException ex) {
Assert.notNull(ex, "Cannot translate a null SQLException");
DataAccessException dae = doTranslate(task, sql, ex);
if (dae != null) {
return dae;
}
SQLExceptionTranslator fallback = getFallbackTranslator();
if (fallback != null) {
return fallback.translate(task, sql, ex);
}
return null;
}
...
}
SpringBoot使用JdbcTemplate的配置
- 在SpringBoot中使用JdbcTemplate需完成以下配置:
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/user_info
username: root
password: root
JdbcTemplate的常用方法
- 查询方法
|
|
query |
查询并对结果集自行封装 |
queryForObject() |
查询并返回一个对象 |
queryForList() |
查询并返回多条记录 |
queryForMap() |
查询并返回一条记录 |
- 操作方法
|
|
execute |
执行sql语句,无返回值 |
update |
执行sql语句,返回受影响的行数 |
batchUpdate |
执行批量更新 |
完整案例
- 可参考本人文章Spring全家桶的深入学习(三):实现数据持久化