TOTD #166: Using NoSQL database in your Java EE 6 Applications on GlassFish - MongoDB for now!
Posted
by arungupta
on Oracle Blogs
See other posts from Oracle Blogs
or by arungupta
Published on Mon, 27 Jun 2011 02:00:00 -0700
Indexed on
2011/06/27
16:28 UTC
Read the original article
Hit count: 768
/General
- No
need to have a pre-defined schema and that makes them a
schema-less database. Addition of new properties to existing
objects is easy and does not require ALTER TABLE. The unstructured data
gives flexibility to
change the format of data any time without downtime or reduced service
levels. Also there are no joins happening on the server because there
is no structure and thus no relation between them.
- Scalability and performance is more important than the entire set of functionality typically provided by an RDBMS. This set of databases provide eventual consistency and/or transactions restricted to single items but more focus on CRUD.
- Not be restricted to SQL to access the information stored in the backing database.
- Designed to scale-out (horizontal) instead of scale-up (vertical). This is important knowing that databases, and everything else as well, is moving into the cloud. RBDMS can scale-out using sharding but requires complex management and not for the faint of heart.
- Unlike RBDMS which require a separate caching tier, most of the NoSQL databases comes with integrated caching.
- Designed for less management and simpler data models lead to lower administration as well.
- Key-Value stores (e.g. Cassandra and Riak)
- Document databases (MongoDB or CouchDB)
- Graph databases (Neo4J)
- RDBMS have been around for many years, very stable, and functionally rich. This is something CIOs and CTOs can bet their money on without much worry. There is a reason 98% of Fortune 100 companies run Oracle :-) NoSQL is cutting edge, brings excitement to developers, but enterprises are cautious about them.
- Commercial databases like Oracle are well supported by the
backing enterprises in terms of providing support resources on a global
scale. There is a full ecosystem built around these commercial
databases
providing training, performance tuning, architecture guidance, and
everything else. NoSQL is fairly new and typically backed by a single
company not able to meet the scale of these big enterprises.
- NoSQL databases are good for CRUDing operations but business
intelligence is extremely important for enterprises to stay
competitive. RDBMS provide extensive tooling to generate this data but
that was not the original intention of NoSQL databases and is lacking
in that area. Generating any meaningful information other than CRUDing
require extensive programming.
- Not suited for complex transactions such as banking systems or
other highly transactional applications requiring 2-phase commit.
- SQL cannot be used with NoSQL databases and writing simple
queries can be involving.
This blog has published multiple blogs on how to access a RDBMS using JPA in a Java EE 6 application. This Tip Of The Day (TOTD) will show you can use MongoDB (a document-oriented database) with a typical 3-tier Java EE 6 application. |
- Download MongoDB for your platform from here (1.8.2 as of
this writing) and start
the server as:
arun@ArunUbuntu:~/tools/mongodb-linux-x86_64-1.8.2/bin$./mongod
./mongod --help for help and startup options
Sun Jun 26 20:41:11 [initandlisten] MongoDB starting : pid=11210
port=27017 dbpath=/data/db/ 64-bit
Sun Jun 26 20:41:11 [initandlisten] db version v1.8.2, pdfile version
4.5
Sun Jun 26 20:41:11 [initandlisten] git version:
433bbaa14aaba6860da15bd4de8edf600f56501b
Sun Jun 26 20:41:11 [initandlisten] build sys info: Linux
bs-linux64.10gen.cc 2.6.21.7-2.ec2.v1.2.fc8xen #1 SMP Fri Nov 20
17:48:28 EST 2009 x86_64 BOOST_LIB_VERSION=1_41
Sun Jun 26 20:41:11 [initandlisten] waiting for connections on port 27017
Sun Jun 26 20:41:11 [websvr] web admin interface listening on port 28017
The default directory for the database is /data/db and needs to be created as:
You can specify a different directory using "--dbpath" option. Refer to Quickstart for your specific platform.
sudo mkdir -p /data/db/
sudo chown `id -u` /data/db
- Using NetBeans, create a Java EE 6 project and make sure to enable CDI and add JavaServer Faces framework.
- Download MongoDB
Java Driver (2.6.3 of this writing) and add it to the project
library by
selecting "Properties", "LIbraries", "Add Library...", creating a new
library by specifying the location of the JAR file, and adding the
library to the created project.
- Edit the generated "index.xhtml" such that it looks like:
This page has a simple HTML form with three text boxes and a submit button. The text boxes take name, year, and language of a movie and the submit button invokes the "createMovie" method of "movieSessionBean" and then render "show.xhtml".
<h1>Add a new movie</h1>
<h:form>
Name: <h:inputText value="#{movie.name}" size="20"/><br/>
Year: <h:inputText value="#{movie.year}" size="6"/><br/>
Language: <h:inputText value="#{movie.language}" size="20"/><br/>
<h:commandButton actionListener="#{movieSessionBean.createMovie}"
action="show"
title="Add"
value="submit"/>
</h:form>
- Create "show.xhtml" ("New" -> "Other..." -> "Other" ->
"XHTML File") such that it looks like:
This page shows the name, year, and language of all movies stored in the database so far. The list of movies is returned by "movieSessionBean.movies" property.<head>
<title><h1>List of movies</h1></title>
</head>
<body>
<h:form>
<h:dataTable value="#{movieSessionBean.movies}" var="m" >
<h:column><f:facet name="header">Name</f:facet>#{m.name}</h:column>
<h:column><f:facet name="header">Year</f:facet>#{m.year}</h:column>
<h:column><f:facet name="header">Language</f:facet>#{m.language}</h:column>
</h:dataTable>
</h:form>
- Now create the "Movie" class such that it looks like:
Other than the usual boilerplate code, the key methods here are "toDBObject" and "fromDBObject". These methods provide a conversion from "Movie" -> "DBObject" and vice versa. The "DBObject" is a MongoDB class that comes as part of the mongo-2.6.3.jar file and which we added to our project earlier. The complete javadoc for 2.6.3 can be seen here. Notice, this class also uses Bean Validation constraints and will be honored by the JSF layer.
import com.mongodb.BasicDBObject;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import javax.enterprise.inject.Model;
import javax.validation.constraints.Size;
/**
* @author arun
*/
@Model
public class Movie {
@Size(min=1, max=20)
private String name;
@Size(min=1, max=20)
private String language;
private int year;
// getters and setters for "name", "year", "language"
public BasicDBObject toDBObject() {
BasicDBObject doc = new BasicDBObject();
doc.put("name", name);
doc.put("year", year);
doc.put("language", language);
return doc;
}
public static Movie fromDBObject(DBObject doc) {
Movie m = new Movie();
m.name = (String)doc.get("name");
m.year = (int)doc.get("year");
m.language = (String)doc.get("language");
return m;
}
@Override
public String toString() {
return name + ", " + year + ", " + language;
}
}
- Finally, create "MovieSessionBean" stateless EJB with all the
business logic such that it
looks like:
package org.glassfish.samples;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.inject.Named;
/**
* @author arun
*/
@Stateless
@Named
public class MovieSessionBean {
@Inject Movie movie;
DBCollection movieColl;
@PostConstruct
private void initDB() throws UnknownHostException {
Mongo m = new Mongo();
DB db = m.getDB("movieDB");
movieColl = db.getCollection("movies");
if (movieColl == null) {
movieColl = db.createCollection("movies", null);
}
}
public void createMovie() {
BasicDBObject doc = movie.toDBObject();
movieColl.insert(doc);
}
public List<Movie> getMovies() {
List<Movie> movies = new ArrayList();
DBCursor cur = movieColl.find();
System.out.println("getMovies: Found " + cur.size() + " movie(s)");
for (DBObject dbo : cur.toArray()) {
movies.add(Movie.fromDBObject(dbo));
}
return movies;
}
}
The database is initialized in @PostConstruct. Instead of a working with a database table, NoSQL databases work with a schema-less document. The "Movie" class is the document in our case and stored in the collection "movies". The collection allows us to perform query functions on all movies. The "getMovies" method invokes "find" method on the collection which is equivalent to the SQL query "select * from movies" and then returns a List<Movie>.
Also notice that there is no "persistence.xml" in the project.
- Right-click and run the project to see the output as:
Enter some values in the text box and click on enter to see the result as:
If you reached here then you've successfully used MongoDB in your Java EE 6 application, congratulations!
- SQL to MongoDB mapping shows mapping between traditional SQL -> Mongo query language.
- Tutorial shows fun things you can do with MongoDB.
- Try the interactive online shell
- The cookbook provides
common ways of using MongoDB
- Encapsulate database management in a JPA persistence
provider. Is it even worth it because the capabilities are going to be
very different ?
- MongoDB uses "BSonObject" class for JSON representation, add
@XmlRootElement on a POJO and how a compatible JSON representation can
be generated. This will make the fromXXX and toXXX methods redundant.
© Oracle Blogs or respective owner