【问题标题】:Can Spring DAO be merged into Service layer?Spring DAO 可以合并到 Service 层吗?
【发布时间】:2016-11-28 08:49:54
【问题描述】:

我正在用spring框架和mybatis开发一个web应用。

在大多数情况下(至少对我而言),DAO 的方法非常简短,如下所示:

public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
  public User getUser(String userId) {
    return (User) getSqlSession().selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser", userId);
  }
}

所以基本上,我需要在 DAO 中为每个被转发到正在使用它的服务对象的查询编写一个方法(例如getUser(String userId))。对我来说,这似乎是不必要的冗余。

我的同事正在努力让它变得简单。他这样写CommonDao

@Repository
public class CommonDao {
    @Autowired
    private SqlSessionTemplate sqlSession;

    public Object insert(String queryId, Object params) {
        return sqlSession.insert(queryId, params);
    }

    public Object update(String queryId, Object params) {
        return sqlSession.update(queryId, params);
    }

    public Object delete(String queryId, Object params) {
        return sqlSession.delete(queryId, params);
    }

    public Object selectOne(String queryId) {
        return sqlSession.selectOne(queryId);
    }

    public Object selectOne(String queryId, Object params) {
        return sqlSession.selectOne(queryId, params);
    }
}

所以我们可以在如下服务中使用这些方法:

@Service
public class CrudService {
    ...
    @Autowired
    private CommonDao commonDao;
    ...

    public UserDto selectUser(Integer userId) {
        ...
        UserDto userDto = (UserDto) commonDao.selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser", userId);
        ...
    }
}

我有点喜欢这种方法,因为它使代码更简单。但我不确定这是一个很好的做法。

【问题讨论】:

  • 不是,使用泛型,会有很大帮助。想想当你重构其中一个类的命名时,你需要找到所有这样写的名称并手动更改它们。
  • 另外,查看 Spring 数据,特别是 -> 存储库。将为您节省大量的 CRUD 输入
  • ps:返回对象是不好的做法。你打算怎么处理他们?

标签: java spring web-applications dao mybatis


【解决方案1】:

要避免样板代码,同时具有类型安全性,并使您的服务层不受 DAO 实现细节的影响,请使用 spring-mybatisMapperScannerConfigurer

在这种情况下,您可以用类型安全的映射器替换您的 DAO。

相当于你的 DAO

public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
  public User getUser(String userId) {
    return (User)getSqlSession().selectOne(
        "org.mybatis.spring.sample.mapper.UserMapper.getUser", userId);
  }
}

将是这个映射器类

package org.mybatis.spring.sample.mapper;

interface UserMapper {
  User getUser(String userId);
}

如果您将其重命名为 UserDao,则根本不需要更改您的服务。服务只依赖于声明的映射器接口。

请注意,您需要定义此接口以确保类型安全并定义您的服务的依赖关系。

当然,您需要配置spring-mybatis,以便它根据您代码中定义的映射器接口生成映射器实现。这很简单,有many options 怎么做。

【讨论】:

  • getUser 方法可以在 UserMapper 中无正文吗?
  • 这是我已修正的错字。它应该是原因的接口。
【解决方案2】:

嗯,你在苦苦挣扎,在 MyBatis 中是正常的。

您的同事为您指明了某个方向...但是CommonDao 在这种形状中的真正价值是什么?对我来说它不是很有用。您仍然需要几乎相同数量的代码 - 而且您仍然需要进行大量转换。

正如@Rom Konoval 所说,MapperScannerConfigurer 可以生成映射器实现 - 这样您就不会编写冗余实现并受益于类型安全 - 类型转换仍然会发生,但对您隐藏。你可以试试。
这是 GitHub 上的 sample usage

或者,您可以自己创建 DAO 实现(就像您已经做过的那样),或者直接在您的服务中使用 SqlSessionTemplate。由你决定。只要保持您的代码库尽可能小并遵循常识即可。

【讨论】:

  • 谢谢。你能告诉我一种“直接在服务层与你的数据库对话”的方法吗?我在想的是在服务中使用 SqlSessionTemplate 而不是 DAO,但这仍然会使用泛型。
  • 只是为了解释“您仍然需要几乎相同数量的代码” - 可能有多个选择查询。正如我所说,我需要为每个查询编写一个方法。通过使用CommonDao,我只需要编写一种方法(例如selectOne)来使用选择查询。因此,代码量减少了。不过,这是一种不好的做法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
  • 2016-05-06
  • 2018-05-02
  • 1970-01-01
  • 2012-11-22
  • 2011-10-17
  • 1970-01-01
相关资源
最近更新 更多