//

Spring Data – Teil 3: MongoDB

1.2.2012 | 5 Minuten Lesezeit

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
2${MONGO_HOME}/bin/mongod --dbpath ../data --rest
3

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

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

  1. jedes Dokument automatisch eine eindeutige Id erhält
  2. Dokumente mit gleichen Attributlisten existieren können
  3. 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>
6

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 
8<!-- Package w/ automagic repositories -->
9<mongo:repositories base-package="mongodb"/>
10

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    ...
12

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> {}
2

… und wir können die ersten Dokumente in unserer MongoDB speichern:

1public class MongoDBRepoTest {
2 
3  @Autowired UserRepository repo;
4 
5  @Before public void setUp() {
6    repo.save(new User("root", "Superuser"));
7    for ( int i = 0; i < 6; i++ ) {
8      repo.save( new User( String.format("user%02d", i), "User " + i ) );
9    }
10  }
11

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]
35

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

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.

Beitrag teilen

Gefällt mir

0

//

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.