2013-03-05 13 views
10

Ho deciso di provare a utilizzare mybatis per un nuovo progetto. Sono decentemente familiare con SQL e ho avuto alcune brutte esperienze con l'ibernazione di recente, quindi sto cercando un approccio a basso livello per DAO.Salvataggio/Aggiornamento delle raccolte con mybatis, qual è la pratica comune?

Sembra essere molto carino tranne che per una cosa, e questo è gestire le raccolte.

Ho due POJO, gruppo e utente, che sono molti-a-molti. Ho deciso su una filosofia di progettazione che un POJO che ha una collezione dovrebbe solo aggiornare la relazione M-M tra le tabelle quando vengono salvate. Quindi, ad esempio, quando salvi un oggetto di gruppo con una raccolta di utenti, la filosofia di progettazione impone che gli utenti debbano già essere salvati e devo solo salvare la relazione tra gruppo e utente nel database.

così, per la funzione saveGroup nell'interfaccia, ho fatto questa mappatura XML per 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> 

Questo lavoro fa come previsto (inserto/aggiorna il gruppo, salva l'insieme di utenti le relazioni nel database). Ma non credo davvero che questa sia la pratica migliore. L'applicazione è fatta in modo che possa passare alla sospensione se necessario, quindi la logica per salvare la raccolta preferibilmente dovrebbe essere nel livello del database. C'è qualche "magia" in mybatis che non sono a conoscenza di ciò potrebbe semplificare operazioni come questa?

Qualche idea su come migliorare questo? O dovrei riconsiderare la progettazione dell'applicazione e inserire ulteriormente la gestione delle collezioni nel modello?

+0

c'era un problema nell'usare '' e il suo '' per descrivere molti: molte relazioni? – Gus

+0

Le mappe dei risultati possono essere utili per ottenere dati, non per salvare i dati. Ottenere una collezione non è un problema, è salvarli che ho trovato per essere ingombranti. – Dytut

+0

Hai guardato usando [MyBatis Generator] (https://code.google.com/p/mybatis/wiki/Generator)? Genera le operazioni CRUD di base per te risparmiando un sacco di codice SQL codificato a mano, quindi devi solo scrivere i join più complessi, ecc. Puoi usare il codice generato nel tuo DAO e spostare molta della logica di selezione che hai in il tuo XML nel DAO. – clav

risposta

1

La seconda parte dell'operazione di mappatura dei dati di saveGroup è davvero un motivo per ripensare la progettazione dell'applicazione. Perseguire la raccolta degli utenti in memoria su una tabella temporanea per confrontarla con quella persistente al fine di inserire ed eliminare i delta è un'operazione abbastanza pesante che non è affatto necessaria se è necessario aggiornare solo il nome o la descrizione del gruppo, cioè quando non ci sono delta. Se questo è il caso, può essere deciso dal server del database, che è la soluzione corrente o dal client del database, la tua applicazione.

A parte il caso in cui il gruppo e probabilmente gli utenti hanno bisogno di un nuovo inserimento, se si desidera che l'applicazione decida se la tabella dei collegamenti deve essere aggiornata o meno, l'applicazione deve sapere se gli utenti la raccolta è cambiata da quando è stata recuperata dal database. Sfortunatamente MyBatis non aiuterà la tua applicazione a farlo.

Vedi, rispetto a Hibernate MyBatis è beatamente inconsapevole dei tuoi oggetti e dello stato che portano dopo che MyBatis ha fatto il suo lavoro, che è la mappatura dei dati, non la mappatura delle relazioni oggettuali. Hibernate può rilevare automaticamente il cosiddetto stato sporco dei tuoi oggetti, MyBatis non può, in quanto questo non è mai stato parte della sua descrizione dei lavori. Quindi sei lasciato ai tuoi dispositivi.

Un approccio semplicissimo sarebbe quello di memorizzare l'hashcode degli utenti dopo una selezione e verificare se l'hashcode è stato modificato utilizzando un metodo chiamato isUserDirty(). Potresti semplicemente testare quella condizione dall'interno del tuo mapping usando <if test="isUserDirty">. Questo ovviamente non è un approccio molto generico e dipende da una decente implementazione di hashCode(). Dai uno sguardo allo answer di leonbloy a una domanda simile per un approccio più generico. Certamente potrebbe anche essere un po 'troppo semplice, specialmente visto che stiamo parlando di molte e molte relazioni. Quale approccio è meglio dipende dal tuo caso.

Ora dovresti sapere cosa fare. In bocca al lupo!

PS invece di inserire e cancellare il delta consiglierei una semplice sovrascrittura: cancella tutto quindi inserisci tutto, in una transazione. La tua strategia di tabella temporanea è una strategia di ottimizzazione che potrebbe non migliorare affatto le prestazioni del tuo database, infatti la mia ipotesi sarebbe che probabilmente peggiora la situazione. Se hai correttamente profilato questa strategia e sai cosa stai facendo, potresti ignorare questo poscritto.

Problemi correlati