点击上方 编程牧马人,选择 设为星标
优质项目,及时送达
-----
使用DAO[1]
在传统的多层应用程序中,通常是Web
层调用业务层,业务层调用数据访问层。业务层负责处理各种业务逻辑,而数据访问层只负责对数据进行增删改查。因此,实现数据访问层就是用JdbcTemplate
实现对数据库的操作。
编写数据访问层的时候,可以使用DAO
模式。DAO
即Data Access Object
的缩写,它没有什么神秘之处,实现起来基本如下:
public class UserDao {
@Autowired
JdbcTemplate jdbcTemplate;
User getById(long id) {
...
}
List<User> getUsers(int page) {
...
}
User createUser(User user) {
...
}
User updateUser(User user) {
...
}
void deleteUser(User user) {
...
}
}
Spring
提供了一个JdbcDaoSupport
类,用于简化DAO
的实现。这个JdbcDaoSupport
没什么复杂的,核心代码就是持有一个JdbcTemplate
:
public abstract class JdbcDaoSupport extends DaoSupport {
private JdbcTemplate jdbcTemplate;
public final void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
initTemplateConfig();
}
public final JdbcTemplate getJdbcTemplate() {
return this.jdbcTemplate;
}
...
}
它的意图是子类直接从JdbcDaoSupport
继承后,可以随时调用getJdbcTemplate()
获得JdbcTemplate
的实例。那么问题来了:因为JdbcDaoSupport
的jdbcTemplate
字段没有标记@Autowired
,所以,子类想要注入JdbcTemplate
,还得自己想个办法:
@Component
@Transactional
public class UserDao extends JdbcDaoSupport {
@Autowired
JdbcTemplate jdbcTemplate;
@PostConstruct
public void init() {
super.setJdbcTemplate(jdbcTemplate);
}
}
有的童鞋可能看出来了:既然UserDao
都已经注入了JdbcTemplate
,那再把它放到父类里,通过getJdbcTemplate()
访问岂不是多此一举?
如果使用传统的XML
配置,并不需要编写@Autowired JdbcTemplate jdbcTemplate
,但是考虑到现在基本上是使用注解的方式,我们可以编写一个AbstractDao
,专门负责注入JdbcTemplate
:
public abstract class AbstractDao extends JdbcDaoSupport {
@Autowired
private JdbcTemplate jdbcTemplate;
@PostConstruct
public void init() {
super.setJdbcTemplate(jdbcTemplate);
}
}
这样,子类的代码就非常干净,可以直接调用getJdbcTemplate()
:
@Component
@Transactional
public class UserDao extends AbstractDao {
public User getById(long id) {
return getJdbcTemplate().queryForObject(
"SELECT * FROM users WHERE id = ?",
new BeanPropertyRowMapper<>(User.class),
id
);
}
...
}
倘若肯再多写一点样板代码,就可以把AbstractDao
改成泛型,并实现getById()
,getAll()
,deleteById()
这样的通用方法:
public abstract class AbstractDao<T> extends JdbcDaoSupport {
@Autowired
private JdbcTemplate jdbcTemplate;
@PostConstruct
public void init(){
super.setJdbcTemplate(jdbcTemplate);
}
private String table;// table 相当于 users 表
private Class<T> entityClass;
private RowMapper<T> rowMapper;
public AbstractDao(){
//获取当前类型的泛型类型
this.entityClass = getParameterizedType();
this.table = this.entityClass.getSimpleName().toLowerCase() + "s";
this.rowMapper = new BeanPropertyRowMapper<>(entityClass);
}
public T getById(long id){
return getJdbcTemplate().queryForObject("SELECT * FROM " + table + " WHERE id = ?",
this.rowMapper,id);
}
public List<T> getAll(int pageIndex){
int limit = 100;
int offset = limit * (pageIndex - 1);
return getJdbcTemplate().query("SELECT * FROM " + table + " LIMIT ? OFFSET ? ",
new Object[]{limit,offset},this.rowMapper);
}
public void deleteById(long id){
getJdbcTemplate().update("DELETE FROM " + table + " WHERE id = ?",id);
}
public RowMapper<T> getRowMapper(){
return this.rowMapper;
}
private Class<T> getParameterizedType(){
Type type = getClass().getGenericSuperclass();
System.out.println(type);
if(!(type instanceof ParameterizedType)){
throw new IllegalArgumentException("Class " + getClass().getName() + " does not have parameteriezd type.");
}
ParameterizedType pt = (ParameterizedType) type;
Type[] types = pt.getActualTypeArguments();
if(types.length != 1){
throw new IllegalArgumentException(
"Class " + getClass().getName() + " has more than 1 parameterized types.");
}
Type r = types[0];
if(!(r instanceof Class<?>)){
throw new IllegalArgumentException(
"Class " + getClass().getName() + " does not have parameterized type of class.");
}
return (Class<T>) r;
}
}
这样,每个子类就自动获得了这些通用方法:
@Component
@Transactional
public class UserDao extends AbstractDao<User> {
// 已经有了:
// User getById(long)
// List<User> getAll(int)
// void deleteById(long)
}
@Component
@Transactional
public class BookDao extends AbstractDao<Book> {
// 已经有了:
// Book getById(long)
// List<Book> getAll(int)
// void deleteById(long)
}
可见,DAO
模式就是一个简单的数据访问模式,是否使用DAO
,根据实际情况决定,因为很多时候,直接在Service
层操作数据库也是完全没有问题的。
小结
Spring
提供了JdbcDaoSupport
来便于我们实现DAO
模式;可以基于泛型实现更通用、更简洁的
DAO
模式。
参考资料
使用DAO: https://www.liaoxuefeng.com/wiki/1252599548343744/1282383605137441





