In diesem Teil meiner Blogserie werden wir sehen, wie einfach sich mit Spring Data MongoDB der Zugriff auf einen MongoDB Datastore gestaltet.
MongoDB
Bei MongoDB handelt es sich um einen sogenannten NoSQL -Datastore, der auf die Persistierung von Dokumenten-orientierten Objekten spezialisiert ist. Für den Einstieg in die Entwicklung empfehle einen Blick in die Developer Zone auf der MongoDB Homepage. Nach dem Download der MongoDB legen wir ein Verzeichnis an und starten die Datenbank mit
1${MONGO_HOME}/bin/mkdir ../data ${MONGO_HOME}/bin/mongod --dbpath ../data --rest
und werden unter http://localhost:28017/ mit einem Admin-Interface belohnt. Für die erste Schritte bietet sich die interaktvie Mongo Shell an, die man wie folgt startet:
1C:\dev\bin\mongo\bin>mongo
2MongoDB shell version: 2.0.2
3connecting to: test
4> show dbs
5admin (empty)
6local (empty)
7test 0.078125GB
8> show collections
9foo
10system.indexes
11> db.foo.save({a:1, b:"bar"})
12> db.foo.save({a:1, b:"bar"})
13> db.foo.save({c:2, d:"doo"})
14> db.foo.find()
15{ "_id" : ObjectId("4f1e575efc25822cd8ff8cf2"), "a" : 1, "b" : "bar" }
16{ "_id" : ObjectId("4f1e5766fc25822cd8ff8cf3"), "a" : 1, "b" : "bar" }
17{ "_id" : ObjectId("4f1e5771fc25822cd8ff8cf4"), "c" : 2, "d" : "doo" }
Wir lassen uns die Namen der Datenbanken ausgeben, dann die Collections (eine Collection ist ein logischer Namensraum) innerhalb der Default-Datenbank test
. Danach speichern wir in der Collection foo
drei Dokumente, die wir in JSON-Notation angeben. Dabei fällt auf, dass
- jedes Dokument automatisch eine eindeutige Id erhält
- Dokumente mit gleichen Attributlisten existieren können
- Dokumente verschiedener Struktur innerhalb der gleichen Collections abgelegt werden können
Daher kann man eine Collection nur bedingt mit einer Tabelle einer relationalen Datenbank vergleichen. Ebenfalls müssen wir uns von ACID-Transaktionen verabschieden. Warum das so ist, kann man u.a. in diesem Artikel nachlesen: Grundlagen Cloud Computing: CAP-Theorem .
Spring Data MongoDB
Spring Data MongoDB verfolgt prinzipiell den gleichen Ansatz wie Spring Data JPA , nämlich die Definition von Repository-Findern allein als Interface-Methoden, deren Implementierung zur Laufzeit von Spring bereitgestellt wird. Ebenso werden Methoden für CRUD-Operation angeboten.
Konfiguration
Zunächst lassen wir Maven die aktuelle Release-Version von Spring Data MongoDB herunterladen:
1<dependency> 2 <groupId>org.springframework.data</groupId> 3 <artifactId>spring-data-mongodb</artifactId> 4 <version>1.0.0.RELEASE</version> 5 </dependency>
Im Spring Application Context gibt es einen eigenen XML Namespace mongo
, der die Konfiguration sehr einfach macht:
1<!-- Connection to MongoDB server --> 2 <mongo:db-factory host="localhost" port="27017" dbname="test" /> 3 <!-- MongoDB Template --> 4 <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> 5 <constructor-arg name="mongoDbFactory" ref="mongoDbFactory" /> 6 </bean> 7 <!-- Package w/ automagic repositories --> 8 <mongo:repositories base-package="mongodb" />
Mit
geben wird die Verbindungsinformationen zum MongoDB-Server und den Namen der Datenbank an. Zum Finetuning der Verbindungsinformationen (Connection Pooling, Clustering etc.) kann man alternativ die Elemente
und
verwenden. Anschließend definieren wir ein Template, das die DB-Factory übergeben bekommt. Zum Schluss müssen wir (wie auch bei Spring Data JPA) angeben, in welchem Paket unsere Repositories liegen. Dabei wird automatisch das einzige MongoDB-Template im Context verwendet. Hat man mehr als ein solches Template, kann man mit
ein bestimmtes auswählen.
Beispiel
Genau wie im Beitrag über Spring Data JPA wollen wir Objekte der Klasse User
persistieren:
1@Document
2public class User {
3
4 @Id
5 private String id;
6
7 @Indexed
8 private String fullName;
9
10 private Date lastLogin;
11 ...
Zur reinen Persistierung sind die Annotation nicht zwingend notwendig. Zum Definieren eines Index mittels @Indexed
muss man aber dann schon auf Annotationen zurückgreifen. Nun schnell noch ein Repository definieren …
1public interface UserRepository extends MongoRepository <User, String> {}
… und wir können die ersten Dokumente in unserer MongoDB speichern:
java5public class MongoDBRepoTest {
@Autowired UserRepository repo;
@Before public void setUp() {
repo.save(new User("root", "Superuser"));
for ( int i = 0; i < 6; i++ ) {
repo.save( new User( String.format("user%02d", i), "User " + i ) );
}
}
Ein Blick in die Mongo-Konsole zeigt, dass unsere Dokumente dort angekommen sind:
1MongoDB shell version: 1.8.3
2connecting to: test
3> db.user.find()
4{ "_id" : "user00", "_class" : "mongodb.User", "fullName" : "User 0", "lastLogin" : ISODate("2012-01-27T08:16:37.589Z") }
5{ "_id" : "user01", "_class" : "mongodb.User", "fullName" : "User 1", "lastLogin" : ISODate("2012-01-27T08:16:37.589Z") }
6{ "_id" : "user02", "_class" : "mongodb.User", "fullName" : "User 2", "lastLogin" : ISODate("2012-01-27T08:16:37.590Z") }
7{ "_id" : "user03", "_class" : "mongodb.User", "fullName" : "User 3", "lastLogin" : ISODate("2012-01-27T08:16:37.590Z") }
8{ "_id" : "user04", "_class" : "mongodb.User", "fullName" : "User 4", "lastLogin" : ISODate("2012-01-27T08:16:37.591Z") }
9{ "_id" : "user05", "_class" : "mongodb.User", "fullName" : "User 5", "lastLogin" : ISODate("2012-01-27T08:16:37.591Z") }
10{ "_id" : "root", "_class" : "mongodb.User", "fullName" : "Superuser", "lastLogin" : ISODate("2012-01-27T08:16:37.576Z") }
11> db.user.count()
127
13> db.user.getIndexes()
14[
15 {
16 "name" : "_id_",
17 "ns" : "test.user",
18 "key" : {
19 "_id" : 1
20 },
21 "v" : 0
22 },
23 {
24 "name" : "fullName",
25 "ns" : "test.user",
26 "dropDups" : false,
27 "sparse" : false,
28 "unique" : false,
29 "key" : {
30 "fullName" : 1
31 },
32 "v" : 0
33 }
34]
Zu beachten ist, dass automatisch beim ersten Speichern eine Collection namens user
angelegt wurde. Soll die Collection abweichend vom Klassenname angelegt werden, kann dies über die Annotation @Document(collection="...")
festgelegt werden. Der Java-Klassenname wird in einem Attribut _class
abgespeichert. Die Ausgabe der Indexe zeigt, dass neben dem Index für die Id auch unser mit @Indexed
annotiertes Attribut fullName
zur Anlage eines Index geführt hat.
Nun erweitern wird unser Repository um einige eigene Finder-Methoden:
1public interface UserRepository extends MongoRepository<User, String> {
2 @Query("{ fullName: ?0 }")
3 List<User> findByTheUsersFullName(String fullName);
4
5 List<User> findByFullNameLike(String fullName, Sort sort);
6}
Mit der @Query
Annotation können frei definierbare Queries in MongoDB-Syntax definiert werden. Die zweite Query demonstriert eine Suche mit regulären Ausdrücken. Beim Schreiben der ersten Queries ist der Vergleich zwischen MongoDB und SQL sehr hilfreich.
Der komplette Quellecode kann auf Github heruntergeladen werden.
MongoDBTemplate
Für weitergehende Zugriffe reicht ein Interface-basiertes Repository allerdings nicht aus. Für die Verwaltung von Collections oder den Einsatz von Map/Reduce -Funktionen muss man auf das MongoDBTemplate
zurückgreifen.
Zusammenfassung
Nach einer kurzen Einführung zur MongoDB konnten wir mittels Spring Data MongoDB sehr einfach die ersten Objekte abspeichern. Danach haben wir gezeigt, wie man eigene Finder-Methoden durch das Schreiben von Interface-Methoden implementiert.
Prinzipiell kann eine Spring Anwendung, die ihre Persistenz mit Spring Data MongoDB realisiert, nun etwa auf CloudFoundry deployt werden, was in diesem Blog ausführlich erklärt wird.
Was bisher geschah
Teil 1: Spring Data Commons
Teil 2: Spring Data JPA
Ausblick
Die Projekte Spring Data Neo4j und Spring GemFire sind gute Kandidaten für weitere Beiträge in dieser Serie.
Weitere Beiträge
von Tobias Trelle
Dein Job bei codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
Weitere Artikel in diesem Themenbereich
Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Blog-Autor*in
Tobias Trelle
Software Architect
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.