我知道最佳做法是同时使用服务层和dao层,并在服务级别添加@Transactional注释.但在我的情况下,这意味着我的大多数服务类都是为了重复DAO方法而创建的……这非常令人恼火.
例如.
public interface FooDAO { public List<FooVO> list(int cathegoryId); public List<FooVO> list(int cathegoryId, int ownerId); } @Service @Transactional public class FooService { protected @Autowired FooDAO dao; public List<FooVO> list(int cathegoryId) { dao.list(cathegoryId); } public List<FooVO> list(int cathegoryId, int authorId) { dao.list(cathegoryId, authorId) } }
这有多笨?
在大多数情况下,我真的不需要花哨的服务方法,因为通常这是一个例如.导管描述和与导管相匹配的实体列表.这就是为什么我在寻找简化的解决方案.像使用泛型以避免重复DAO一样辉煌:D http://www.javablog.fr/javahibernate-dont-repeat-the-dao-with-a-genericdao.html
我找到了答案.其中我读过
Where does the @Transactional annotation belong?
但还是没有找到我的答案.
所以我想知道用@Transactional注释DAO方法真是个坏主意.受到 http://www.baeldung.com/2011/12/26/transaction-configuration-with-jpa-and-spring-3-1/#apistrategy 的启发,我找到了解决方案.
如果:
>我只有一个服务类(确实需要)并使用@Transactional注释其方法
>对于所有其他(简单)情况:我使用@Transactional(propagation = Propagation.MANDATORY)注释DAO方法,使用@Transactional注释我的控制器方法(propagation = Propagation.REQUIRES_NEW)
**更新1 **
它看起来像这样:
public interface FooDAO { @Transactional(propagation = Propagation.MANDATORY, readOnly=true) public List<FooVO> list(int cathegoryId); ... } @Service public class FooService { protected @Autowired FooDAO dao; @Transactional // propagation REQUIRED public List<FooVO> magic(FooVO fooVO) { //do sth complicated here ;) } // We do not repeat DAO methods in the Service class. // No wrapping methods here !!! } @Controller public class FooMagicController { protected @Autowired FooService fooService; ... fooService.magic(fooVO); ... } @Controller public class FooController { protected @Autowired FooDAO dao; //DAO wired directly in the Controller class !!! @Transactional(propagation = Propagation.REQUIRES_NEW) @RequestMapping(".....") public String listFoo(Model model,...) throws Exception { model.addAttribute("list", dao.list(13) ); return "xyz"; } }
在每种情况下,DAO使用“上方”管理的会话.
这是非常糟糕的主意吗?有没有更好的方法来实现我的需求?
我不会说这是一个坏主意,因为它取决于您选择设计应用程序的情况.
如果你觉得,你不需要任何服务类(即API的类比纯DAO API更多),那么我觉得最好避免使用服务类,只使用直接自动连接到控制器的DAO实现.
但是如果你需要做一些额外的逻辑并希望将它作为API公开,那么你可以编写服务类,它将实现该自定义逻辑以及这些DAO方法的包装函数(如上所述).这将使代码更清晰,因为您只需要将服务类连接到控制器,同时您可以通过使用服务类中的包装API来进行DAO调用.
如果您只为自定义API保留服务类,而没有DAO的任何包装API,那么如果您需要进行任何数据访问调用,您还需要将DAO连接到控制器类中.因此,在这种情况下,您将有效地连接服务类和控制器类中的DAO.
更新1
以下是其中一个示例项目的Controller和Service类
调节器
public class HomePageController { @Autowired private VideoService videoService; //Controller method @RequestMapping(value = "/tag/mostviewed") public @ResponseBody Map<String, List<Video>> showMostViewedVideosForTag (){ //service api videoService.getMostViewedVideo(curatorTagName) } }
服务类
@Service(value = "videoService") @Transactional(readOnly = true) public class VideoServiceImpl implements VideoService { @Autowired private VideoDAO videoDAO; @Autowired private TagDAO tagDAO; // WRAPPER API FOR THE DAO @Override public List<Video> getMostViewedVideo(String tagName) { return videoDAO.getMostViewedVideo(tagName); } // A non wrapper API which does some business logic @Override @Transactional public void assignTagsToVideo(String videoId, String userId, String... tags) { for (String tag : tags) { if (tagHeritageDAO.getTagHeritage(tag, videoId, userId) == null) { Tag tagObj = tagDAO.getTag(tag); if (tagObj != null) { //some logic here to add tags to video } } } videoDAO.update(video); } }
如您所见,唯一的服务是在控制器类中连接的,并且dao连接到服务类.这就是我所说的混合模式.抱歉,如果我困惑你.
翻译自:https://stackoverflow.com/questions/16147144/how-to-avoid-repeatig-dao-methods-in-service-classes-transactional-annotated-d