Non so da dove iniziare o quali informazioni sono rilevanti per favore fatemi sapere quali informazioni aggiuntive potrebbero essere utili per risolvere questo problema.Perché mongodb sembra salvare alcuni oggetti binari e non altri?
Sto sviluppando una semplice applicazione cometd e sto usando mongodb come back-end di archiviazione. Ottengo una singola istanza di mongodb all'avvio dell'applicazione e utilizzo questa istanza per tutte le query. Questo è infatti raccomandato dalla documentazione del driver mongo java come indicato qui: http://www.mongodb.org/display/DOCS/Java+Driver+Concurrency. Stavo cercando di capire che il problema aveva qualcosa a che fare con la sicurezza dei thread, ma secondo questo link mongodb è completamente thread-safe.
Ecco dove diventa interessante. Ho una classe che estende BasicDBObject
.
public class MyBasicDBObject {
private static final String MAP = "map";
public boolean updateMapAnd(String submap, String key, byte[] value) {
Map topMap = (Map)this.get(MAP);
Map embeddedMap = topMap.get(submap);
byte[] oldValue = embeddedMap.get(key);
newValue = UtilityClass.binaryAnd(oldValue, value);
embeddedMap.put(key, newValue);
topMap.put(submap, embeddedMap);
this.put(MAP, topMap);
}
public boolean updateMapXor(String submap, String key, byte[] value) {
Map topMap = (Map)this.get(MAP);
Map embeddedMap = topMap.get(submap);
byte[] oldValue = embeddedMap.get(key);
newValue = UtilityClass.binaryXor(oldValue, value);
embeddedMap.put(key, newValue);
topMap.put(submap, embeddedMap);
this.put(MAP, topMap);
}
}
Le prossime due classi di scheletro che si estendono MyBasicDBObject
.
public class FirstDBObject extends MyBasicDBObject { //no code }
public class SecondDBObject extends MyBasicDBObject { //no code }
L'unica ragione per cui ho creato le mie classi in questo modo è quello di migliorare la leggibilità del codice nel trattare con questi due oggetti all'interno dello stesso ambito. Questo mi permette di effettuare le seguenti ...
//a cometd service callback
public void updateMapObjectsFoo(ServerSession remote, Message message) {
//locate the objects to update...
FirstDBObject first = (FirstDBObject) firstCollection.findOne({ ... });
SecondDBObject second = (SecondDBObject) secondCollection.findOne({ ... });
//update them as follows
first.updateMapAnd("default", "someKey1", newBinaryData1);
second.updateMapAnd("default", "someKey2", newBinaryData2);
//save (update) them to their respective collections
firstCollection.save(first);
secondCollection.save(second);
}
public void updateMapObjectsBar(ServerSession remote, Message message) {
//locate the objects to update...
FirstDBObject first = (FirstDBObject) firstCollection.findOne({ ... });
SecondDBObject second = (SecondDBObject) secondCollection.findOne({ ... });
/**
* the only difference is these two calls
*/
first.updateMapXor("default", "someKey1", newBinaryData1);
second.updateMapXor("default", "someKey2", newBinaryData2);
//save (update) them to their respective collections
firstCollection.save(first);
secondCollection.save(second);
}
Il UtilityClass
fa esattamente come i metodi sono chiamati, bit per bit &
e bit ^
mediante iterazione negli array di byte passati.
Questo è il punto in cui sono completamente perso. updateMapObjectsFoo()
funziona esattamente come previsto, sia first
che second
riflettono le modifiche nel database. D'altra parte, updateMapObjectsBar()
riesce a aggiornare correttamente first
.
ispezione tramite il debug updateMapObjectsBar()
mostra che gli oggetti binari vengono infatti aggiornati correttamente su entrambi gli oggetti, ma quando mi dirigo verso la mongo shell di indagare il problema che vedo che first
viene aggiornato nel DB e second
non lo è. Dove ho avuto l'idea che la sicurezza dei thread avesse qualcosa a che fare con questo? L'unica differenza che mi infastidisce è che secondCollection
è utilizzato da altri servizi di cometd mentre non lo è il firstCollection
. Ciò sembra rilevante in una mano, ma non nell'altra poiché le opere Foo
e Bar
no.
Ho strappato il codice e l'ho rimesso insieme e continuo a tornare a questo stesso problema. Cosa diavolo sta succedendo qui?
Sembra che abbia escluso la parte più rilevante di tutto ciò che è l'incubo dei generici java e il ricorso del driver mongodb a questa caratteristica del linguaggio. BasicDBObject
è essenzialmente un wrapper per un Map<String, Object>
. Il problema è che una volta archiviato un oggetto in quella mappa, devi riportarlo indietro a quello che era quando lo hai inserito. Sì, potrebbe sembrare del tutto ovvio, e lo sapevo benissimo prima di pubblicare questa domanda.
Non riesco a individuare ciò che è successo esattamente, ma offrirò questo consiglio agli utenti di java + mongodb. Casterai, MOLTO, e più le tue strutture di dati saranno complesse più cast di cui avrai bisogno. Per farla breve, non farlo:
DBObject obj = (DBObject) collection.findOne(new BasicDBObject("_id", new ObjectId((String)anotherObj.get("objId"))));
Uno fodere sono tentati quando si sta facendo prototipi rapidi, ma quando si inizia a fare che più e più volte si sono tenuti a fare errori.Scrivi più codice ora, e soffrono meno frustrazione più tardi:
DBObject query = new DBObject();
String objId = (String) anotherObj.get("objId");
query.put("_id", new ObjectId(objId));
obj = (DBObject) collection.findOne(query);
Credo che questo sia fastidiosamente verbose ma devo aspettare tanto interagendo direttamente con Mongo invece di utilizzare una sorta di biblioteca per rendere la mia vita più facile. Mi sono reso ridicolo su questo, ma spero che qualcuno imparerà dal mio errore e si risparmia un sacco di frustrazione.
Grazie a tutti per il vostro aiuto.
Il problema, ovviamente, è con la frase "metodo essenzialmente identico", che chiaramente non è se ha un comportamento diverso. Potresti voler includere anche il codice per quel metodo. –
sarebbe utile se è possibile fornire la definizione del metodo updateMapObjectsBar(). Se sono simili, è improbabile che uno lavori e l'altro no. –
Probabilmente entrambi avete ragione che qualcosa è diverso, ma per brevità non posso includere l'intero corpo di entrambi i metodi. Mi sento come se stessi in qualche modo abusando di Mongo poiché l'unica differenza visibile è che il secondo metodo non riesce a memorizzare il secondo oggetto. –