2013-03-05 23 views
10

Postanowiłem spróbować użyć mybatis do nowego projektu. Dobrze znam SQL, a ostatnio miałem złe doświadczenia z hibernacją, więc szukam bardziej niskopoziomowego podejścia do DAO.Zbieranie/aktualizowanie kolekcji za pomocą mybatis, jaka jest powszechna praktyka?

Wydaje się być całkiem miłym, z wyjątkiem jednej rzeczy, a to dotyczy kolekcjonowania.

Mam dwa POJO, grupy i użytkownika, które są wiele-do-wielu. Zdecydowałem się na filozofię projektowania, że ​​POJO, które ma kolekcję, powinno jedynie aktualizować relację M-M między tabelami podczas zapisywania. Tak więc, na przykład, kiedy zapisuję obiekt grupowy, który ma kolekcję użytkowników, filozofia projektowania nakazuje, aby użytkownicy byli już zapisywani, a ja muszę tylko zapisać grupę i relację group_user w bazie danych.

tak, dla funkcji saveGroup w interfejsie, zrobiłem to odwzorowanie XML mybatis:

<insert id="saveGroup" keyColumn="id" 
    parameterType="se.myapp.domain.Group"> 
    <choose> 
     <when test="id == null"> 
     INSERT INTO myapp_group (name, description) 
     VALUES 
     (#{username}, #{password}); 
     </when> 
     <otherwise> 
     UPDATE myapp_group set name=#{name}, description=#{description} 
     where id=#{id}; 
     </otherwise> 
    </choose> 

    <if test="users != null"> 
     create temporary table tmpnewgroups (group_id integer, user_id integer); 

     insert into tmpnewgroups (group_id, user_id) values (
     <foreach collection="users" item="user" open="" close="" separator="),()"> 
      #{id},#{user.id} 
     </foreach> 
     ); 

     insert into myapp_user_group(group_id, user_id) 
     select tmp.group_id, tmp.user_id 
     from tmpnewgroups tmp 
     left outer join myapp_user_group ug 
      on ug.group_id = tmp.group_id and ug.user_id = tmp.user_id 
     where ug.group_id is null; 

     delete from myapp_user_group 
     where group_id = #{id} and user_id not in (select user_id from tmpnewgroups); 
    </if> 

</insert> 

ten działa zgodnie z przeznaczeniem (insert/aktualizuje grupę, zapisuje zbiór użytkowników jako stosunków w bazie danych). Ale nie uważam, że to najlepsza praktyka. Aplikacja jest tak wykonana, że ​​w razie potrzeby mogę przejść do hibernacji, więc logika do zapisywania kolekcji powinna znajdować się w warstwie bazy danych. Czy istnieje jakaś "magia" w mybatis, której nie jestem w stanie uświadomić, że mogłaby usprawnić takie operacje?

Jakieś przemyślenia na temat tego, jak to poprawić? Czy powinienem ponownie przemyśleć projekt aplikacji i umieścić w kolekcji dalej obsługę kolekcji?

+0

czy był problem z użyciem '' i jego '' do opisania wielu: wiele relacji? – Gus

+0

Cóż afaik resultmaps służą do uzyskiwania danych, a nie do zapisywania danych. Uzyskanie kolekcji nie stanowi problemu, jest to zapisanie ich, które uważam za kłopotliwe. – Dytut

+0

Czy przyjrzał Ci się [Generator MyBatis] (https://code.google.com/p/mybatis/wiki/Generator)? Wygeneruje podstawowe operacje CRUD, dzięki czemu zaoszczędzisz mnóstwo ręcznie kodowanych instrukcji SQL, więc będziesz musiał pisać tylko bardziej skomplikowane połączenia itd. Możesz użyć wygenerowanego kodu w swoim DAO i przenieść wiele logiki wyboru, które posiadasz Twój XML do DAO. – clav

Odpowiedz

1

Druga część operacji mapowania danych saveGroup jest rzeczywiście powodem do ponownego przemyślenia projektu aplikacji. Utrzymywanie kolekcji użytkowników w pamięci w tabeli tymczasowej w celu jej porównania z utrwaloną w celu wstawienia i usunięcia delt jest dość ciężką operacją, która nie jest konieczna, jeśli tylko nazwa lub opis grupy wymaga aktualizacji, tj. gdy nie ma delt. Niezależnie od tego, czy tak jest, czy nie, decyzję może podjąć serwer bazy danych, czyli aktualne rozwiązanie, lub klient bazy danych, aplikacja.

Oprócz przypadku, w którym grupa i ewentualnie jej użytkownicy potrzebują wstawienia po raz pierwszy, jeśli aplikacja ma zadecydować, czy tablica łączy musi zostać zaktualizowana, aplikacja musi wiedzieć, czy użytkownicy kolekcja zmieniła się od czasu pobrania z bazy danych. Niestety MyBatis nie pomoże twojej aplikacji.

Zobacz, w porównaniu do Hibernate MyBatis jest całkowicie nieświadomy twoich obiektów i stanu, który wykonują po wykonaniu zadania MyBatis, czyli odwzorowaniu danych, a nie odwzorowaniu relacji obiektowych. Hibernacja może automatycznie wykryć tzw. Brudny stan twoich obiektów, MyBatis nie może, ponieważ to nigdy nie było częścią opisu zadania. Więc zostawiasz na własne urządzenia.

Bardzo prostym sposobem byłoby przechowywanie hashcode użytkownika po wyborze i sprawdzenie, czy hashcode się zmienił przy użyciu metody o nazwie isUserDirty(). Możesz po prostu przetestować ten stan z poziomu swojego mapowania za pomocą <if test="isUserDirty">. Nie jest to oczywiście podejście bardzo ogólne i zależy od przyzwoitej implementacji hashCode(). Spójrz na answer z leonbloy na podobne pytanie, aby uzyskać bardziej ogólne podejście. Oczywiście może to być również zbyt proste, zwłaszcza, że ​​mówimy wiele do wielu relacji. To, które podejście jest najlepsze, wszystko zależy od twojej sprawy.

Teraz powinieneś wiedzieć, co robić. Powodzenia!

PS zamiast wstawiania i usuwania delta, radziłbym prostego nadpisania: usuń wszystko, a następnie wstaw wszystkie, w transakcji. Twoja strategia tabeli tymczasowej jest strategią optymalizacji, która w rzeczywistości może nie poprawiać wydajności twojej bazy danych, w rzeczywistości wydaje mi się, że prawdopodobnie to pogorszy. Jeśli odpowiednio wyprofilowałeś tę strategię i wiesz, co robisz, możesz zignorować ten napis.

Powiązane problemy