2013-04-22 10 views
8

Wiem, że najlepszą praktyką jest posiadanie zarówno warstwy usługowej, jak i dao oraz dodawanie adnotacji @Transactional na poziomie usługi. Ale w moim przypadku oznacza to, że większość moich klas usług jest tworzona tylko po to, aby powtarzać metody DAO ... To dość irytujące.Jak uniknąć powtarzania metod DAO w klasach usług? @Transactional adnotowane DAO i klasy usług - czy jest to dopuszczalna praktyka?

np.

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) 
    } 
} 

Jakie to głupie?

W większości przypadków naprawdę nie potrzebuję wyrafinowanych metod serwisowania, ponieważ zazwyczaj jest to kwestia zdobycia np. opis kategorii i listę podmiotów pasujących do kategorii. Dlatego szukam uproszczonego rozwiązania. Coś tak wspaniałego jak używanie generycznych, aby uniknąć powtarzania DAO: D http://www.javablog.fr/javahibernate-dont-repeat-the-dao-with-a-genericdao.html

Szukałem odpowiedzi. Między innymi przeczytałem Where does the @Transactional annotation belong? , ale nadal nie znalazłem mojej odpowiedzi.

Więc zastanawiam się, czy przypisywanie metod DAO za pomocą @Transactional jest naprawdę tak złym pomysłem. Zainspirowany przez http://www.baeldung.com/2011/12/26/transaction-configuration-with-jpa-and-spring-3-1/#apistrategy znalazłem rozwiązanie.

CO JEŚLI:

  • Mam tylko jedną klasę usług (co jest naprawdę potrzebne) i opisywanie swoich metod z @Transactional
  • dla wszystkich innych przypadkach (prosty): I opisywanie metody DAO z @Transactional (propagacja = Propagation.MANDATORY) i moje metody kontroler z @Transactional (propagacja = Propagation.REQUIRES_NEW)

** UPDATE 1 **

Wyglądałoby mniej więcej tak:

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"; 
    } 
} 

W każdym przypadku DAO używa sesji, która jest zarządzana "powyżej".

Czy to bardzo zły pomysł? Czy istnieje lepszy sposób na osiągnięcie tego, czego potrzebuję?

+0

Znalazłem podobne pytanie: http://stackoverflow.com/questions/4462785/transactional-controller-vs-service "tak, dodanie @Transactional do metod kontrolera jest całkowicie poprawne." , ale "kontroler nie powinien wiedzieć o warstwie trwałości i może być konieczne ponowne użycie logiki biznesowej w aplikacji komputerowej, w której nie ma już warstwy kontrolera." –

Odpowiedz

2

Nie powiedziałbym, że to zły pomysł, ponieważ zależy to od sytuacji, którą wybrałeś do zaprojektowania aplikacji.

Jeśli uważasz, że nie potrzebujesz żadnych klas usług (tj. Klas z API, które ma więcej niż czysty interfejs API DAO), to uważam, że lepiej jest unikać klas usług i po prostu użyć implementacji DAO bezpośrednio automatycznie podłączonych do kontrolera .

Ale jeśli potrzebujesz dodatkowej logiki i chcesz wydobyć ją jako API, możesz napisać klasę usług, która zaimplementuje tę niestandardową logikę, a także funkcje opakowania dla tych metod DAO (jak podałeś powyżej). Spowoduje to, że kod stanie się czystszy, ponieważ wystarczy podłączyć klasy usług do kontrolera, a jednocześnie można wykonywać połączenia DAO, korzystając z interfejsów API pakietów w klasach usług.

Jeśli utrzymujesz klasy usług tylko dla niestandardowych interfejsów API i nie będziesz miał żadnych interfejsów API dla DAO, to będziesz musiał również podłączyć urządzenia DAO do klasy kontrolera, jeśli chcesz wykonywać połączenia dostępu do danych. Tak więc w tym przypadku skutecznie będzie okablowanie DAO w klasach usług i klasach sterownika.

UPDATE 1

Oto moje klasy Controller i obsługa od jednego z projektów przykładowych

Controller

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) 
     } 

} 

klasy usługi

@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); 
} 
} 

Jak widać tylko usługa jest przewodowa d w klasie kontrolera, a dao są podłączone do klasy usług. To właśnie miałem na myśli w trybie mieszanym. Przepraszam, jeśli cię pomyliłem.

+0

Tak, ostatni akapit opisuje moją sprawę. Więc mówisz, że mieszanie usługi transakcyjnej z trnsactional DAO nie jest w końcu złym pomysłem, prawda? A ponieważ nie doradziłeś mi niczego innego, prawdopodobnie najlepsze rozwiązanie w tej sytuacji, jak rozumiem? –

+0

Tak. Używam go w trybie mieszanym, aby mój kontroler rozmawiał tylko z klasami usług, a nie z dao. To jest lepsze oddzielenie logiki. –

+1

Czekaj, tryb mieszany oznacza dla mnie coś innego. Oznacza to, że niektórzy kontroler używają usług, a niektórzy używają DAO. Wiem, że może to być mylące itp. (Mam na myśli tych, którzy pracują z moim kodem), ale w moim przypadku ma to sens. –