블로그 이미지
LifeisSimple

calendar

1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

Notice

2011. 3. 31. 17:53 Brain Trainning/NoSQL
Replication Set 에서 DB 커넥팅 방법

                  public void testFindAll() throws UnknownHostException, MongoException {

                                   // TODO Auto-generated method stub

                                   ArrayList<ServerAddress> addrs = new ArrayList<ServerAddress>();

                   addrs.add(new ServerAddress("192.168.1.101", 27017));

                   addrs.add(new ServerAddress("192.168.1.102", 27017));

                   addrs.add(new ServerAddress("192.168.1.103", 27017));
 

                   Mongo connection = new Mongo(addrs);

                     

                                   DB mongoJUnit = connection.getDB("deptDB");

                                   DBCollection dept = mongoJUnit.getCollection("deptJUnit");

                                  

                                   DBCursor cur = dept.find();

                                  

                                   int index = 1;

                                   for ( Iterator<DBObject> it = cur.iterator(); it.hasNext(); ++index) {

                                                     DBObject obj = it.next();

                                                    

                                                     System.out.println("data("+ index+"):"+obj.toString());

                                   }

                                  

                                   System.out.println(connection.getAddress());

                  }

posted by LifeisSimple
2011. 3. 4. 17:28 Brain Trainning/PRG Language
http://msdn.microsoft.com/ko-kr/library/bb879937.aspx

선택 버퍼링 사용

선택 버퍼링은 서버 커서 오버헤드 없이 모든 종류의 큰 값 데이터를 검색할 수 있는 기능입니다. 응용 프로그램은 드라이버가 지원하는 SQL Server의 모든 버전에서 선택 버퍼링 기능을 사용할 수 있습니다.

일반적으로 Microsoft SQL Server JDBC 드라이버는 쿼리를 실행할 때 모든 결과를 서버에서 검색하여 응용 프로그램 메모리에 넣습니다. 이 방법은 SQL Server에서 리소스 소비를 최소화하지만 매우 큰 결과를 생성하는 쿼리의 경우 JDBC 응용 프로그램에서 OutOfMemoryError가 발생할 수 있습니다.

응용 프로그램에서 매우 큰 결과를 처리할 수 있도록 하기 위해 Microsoft SQL Server JDBC 드라이버에서는 선택 버퍼링을 제공합니다. 선택 버퍼링을 사용하면 드라이버는 SQL Server에서 문 실행 결과를 한 번에 모두 검색하는 것이 아니라 응용 프로그램에 필요할 때 검색합니다. 또한 응용 프로그램에서 더 이상 액세스할 수 없는 결과를 즉시 삭제합니다. 다음은 선택 버퍼링을 유용하게 사용할 수 있는 몇 가지 예입니다.

  • 쿼리로 매우 큰 결과 집합이 생성되는 경우: 메모리에 저장할 수 있는 행보다 더 많은 행을 생성하는 SELECT 문을 응용 프로그램에서 실행하는 경우가 있습니다. 이전 릴리스에서는 OutOfMemoryError를 방지하기 위해 응용 프로그램에서 서버 커서를 사용해야 했습니다. 선택 버퍼링을 사용하면 서버 커서 없이도 임의의 큰 결과 집합을 정방향 읽기 전용으로 처리할 수 있습니다.
  • 쿼리로 매우 큰 SQLServerResultSet 열 또는 SQLServerCallableStatement OUT 매개 변수 값: 너무 커서 응용 프로그램 메모리에 저장할 수 없는 단일 값(열 또는 OUT 매개 변수)을 응용 프로그램에서 검색할 수 있습니다. 선택 버퍼링은 getAsciiStream, getBinaryStream, 또는 getCharacterStream 메서드를 사용하여 클라이언트 응용 프로그램에서 이러한 값을 스트림으로 검색할 수 있도록 합니다. 응용 프로그램은 스트림에서 읽으면서 SQL Server에서 해당 값을 검색합니다.

Bb879937.note(ko-kr,SQL.105).gif참고:
선택 버퍼링을 사용하면 JDBC 드라이버는 필요한 양의 데이터만 버퍼링합니다. 드라이버는 버퍼 크기를 제어 또는 제한하는 공용 메서드를 제공하지 않습니다.

JDBC 드라이버 버전 2.0 이상에서 드라이버의 기본 동작은 "adaptive"입니다. 즉 선택 버퍼링을 사용하기 위해 응용 프로그램에서 명시적으로 선택 동작을 요청할 필요가 없습니다. 그러나 버전 1.2 릴리스에서는 버퍼링 모드가 기본적으로 "full"이므로 응용 프로그램에서 명시적으로 선택 버퍼링 모드를 요청해야 했습니다.

다음은 응용 프로그램에서 문 실행 시 선택 버퍼링을 사용하도록 요청할 수 있는 세 가지 방법입니다.

  • 응용 프로그램에서 연결 속성 responseBuffering을 "adaptive"로 설정할 수 있습니다. 연결 속성을 설정하는 방법은 연결 속성 설정을 참조하십시오.
  • 응용 프로그램에서 SQLServerDataSource 개체의 setResponseBuffering 메서드를 사용하여 해당 SQLServerDataSource 개체를 통해 생성된 모든 연결에 대해 응답 버퍼링 모드를 설정할 수 있습니다.
  • 응용 프로그램에서 SQLServerStatement 클래스의 setResponseBuffering 메서드를 사용하여 특정 문 개체에 대해 응답 버퍼링 모드를 설정할 수 있습니다.

JDBC 드라이버 버전 1.2를 사용하는 경우 응용 프로그램에서 setResponseBuffering 메서드를 사용하여 문 개체를 SQLServerStatement 클래스로 캐스팅해야 했습니다. 큰 데이터 읽기 샘플저장 프로시저로 큰 데이터 읽기 샘플의 코드 예에서는 이러한 이전 사용법을 보여 줍니다.

그러나 JDBC 드라이버 버전 2.0에서는 응용 프로그램에서 isWrapperFor 메서드 및 unwrap 메서드를 사용하여 구현 클래스의 계층 구조에 관계없이 공급업체별 기능에 액세스할 수 있습니다. 예제 코드를 보려면 큰 데이터 업데이트 샘플 항목을 참조하십시오.

get<Type>Stream 메서드를 사용하여 큰 값을 한 번 읽은 다음 SQL Server에서 반환하는 순서로 ResultSet 열과 CallableStatement OUT 매개 변수에 액세스하면 결과를 처리할 때 선택 버퍼링이 응용 프로그램 메모리 사용량을 최소화합니다. 선택 버퍼링을 사용하면 다음과 같은 결과를 얻을 수 있습니다.

  • SQLServerResultSetSQLServerCallableStatement 클래스에 정의된 get<Type>Stream 메서드는 응용 프로그램에서 표시하는 경우 스트림을 재설정할 수 있다 하더라도 기본적으로 한 번 읽기 스트림을 반환합니다. 응용 프로그램에서 스트림 reset을 원할 경우 먼저 해당 스트림에서 mark 메서드를 호출해야 합니다.
  • SQLServerClobSQLServerBlob 클래스에 정의된 get<Type>Stream 메서드는 mark 메서드를 호출하지 않고 항상 스트림의 시작 위치로 변경될 수 있는 스트림을 반환합니다.

응용 프로그램에서 선택 버퍼링을 사용하는 경우 get<Type>Stream 메서드에 의해 검색된 값은 한 번만 검색될 수 있습니다. 같은 개체의 get<Type>Stream 메서드를 호출한 후 같은 열이나 매개 변수에서 get<Type> 메서드를 호출하려고 하면 "데이터에 액세스되었으나 이 열이나 매개 변수에는 사용할 수 없습니다."라는 메시지와 함께 예외가 발생합니다.

응용 프로그램의 메모리 사용량을 최소화하기 위해 개발자들이 따라야 할 중요한 지침은 다음과 같습니다.

  • 응용 프로그램에서 매우 큰 결과 집합을 처리할 수 있도록 연결 문자열 속성 selectMethod=cursor를 사용하지 않도록 합니다. 선택 버퍼링 기능은 응용 프로그램이 서버 커서를 사용하지 않고도 매우 큰 정방향 전용의 읽기 전용 결과 집합을 처리할 수 있도록 합니다. selectMethod=cursor를 설정하면 해당 연결에서 생성한 모든 정방향 읽기 전용 결과 집합이 영향을 받습니다. 즉, 응용 프로그램에서 행 수가 적은 간단한 결과 집합을 자주 처리하는 경우 각 결과 집합에 대한 서버 커서를 만들고 읽고 닫는 작업을 할 때 selectMethodcursor로 설정되지 않은 경우보다 클라이언트측 및 서버측 모두에서 리소스를 더 많이 사용합니다.
  • getBlob 또는 getClob 메서드 대신 getAsciiStream, getBinaryStream, 또는 getCharacterStream 메서드를 사용하여 큰 텍스트 또는 이진 값을 스트림으로 읽습니다. 버전 1.2 릴리스 이상에서는 이러한 작업을 위해 SQLServerCallableStatement 클래스에 새로운 get<Type>Stream 메서드가 제공됩니다.
  • SELECT 문에서 잠재적으로 큰 값을 갖는 열이 열 목록의 마지막에 배치되도록 하고 SQLServerResultSetget<Type>Stream 메서드를 사용하여 해당 메서드가 선택된 순서로 해당 열에 액세스하도록 합니다.
  • SQLServerCallableStatement 생성에 사용된 SQL에서 잠재적으로 큰 값을 갖는 OUT 매개 변수가 매개 변수 목록의 마지막에 선언되도록 합니다. 또한 SQLServerCallableStatementget<Type>Stream 메서드를 사용하여 해당 메서드가 선언된 순서로 OUT 매개 변수에 액세스하도록 합니다.
  • 둘 이상의 문이 같은 연결에서 동시에 실행되지 않도록 합니다. 이전 문의 결과를 처리하기 전에 다른 문을 실행하면 처리되지 않은 결과가 응용 프로그램 메모리에 버퍼링될 수 있습니다.
  • 다음과 같은 경우에는 responseBuffering=adaptive 대신 selectMethod=cursor를 사용하는 것이 더 좋습니다.
    • 응용 프로그램이 사용자 입력을 받은 후 각 행을 읽는 등 정방향 읽기 전용 결과 집합을 천천히 처리하는 경우 responseBuffering=adaptive 대신 selectMethod=cursor를 사용하면 SQL Server에 의한 리소스 사용을 줄일 수 있습니다.
    • 응용 프로그램이 동일한 연결에서 동시에 둘 이상의 정방향 읽기 전용 결과 집합을 처리하는 경우 responseBuffering=adaptive 대신 selectMethod=cursor을 사용하면 이러한 결과 집합을 처리하는 동안 드라이버에 필요한 메모리를 줄일 수 있습니다.
    두 경우 모두 서버 커서를 만들고 읽고 닫을 때 발생하는 오버헤드를 고려해야 합니다.

또한 다음 목록에서는 스크롤 및 업데이트가 가능한 정방향 전용 결과 집합에 대한 권장 사항에 대해 설명합니다.

  • 스크롤 가능한 결과 집합의 경우 행 블록을 인출할 때 드라이버는 선택 버퍼링이 설정된 경우에도 항상 SQLServerResultSet 개체의 getFetchSize 메서드가 나타내는 행 수를 메모리로 읽어들입니다. 스크롤로 인해 OutOfMemoryError가 발생하는 경우 SQLServerResultSet 개체의 setFetchSize 메서드를 호출하여 인출 크기를 더 적은 행 수(필요한 경우 1도 가능)로 설정함으로써 인출되는 행 수를 줄일 수 있습니다. 이렇게 해도 OutOfMemoryError, 가 발생하는 경우에는 스크롤 가능한 결과 집합에 아주 큰 열을 포함하지 마십시오.
  • 업데이트 가능한 정방향 결과 집합의 경우 행 블록을 인출할 때 드라이버는 해당 연결에 대해 선택 버퍼링이 설정된 경우에도 일반적으로 SQLServerResultSet 개체의 getFetchSize 메서드가 나타내는 행 수를 메모리로 읽어들입니다. SQLServerResultSet 개체의 next 메서드를 호출하여 OutOfMemoryError가 발생하는 경우 SQLServerResultSet 개체의 setFetchSize 메서드를 호출하여 인출 크기를 더 적은 행 수(필요한 경우 1도 가능)로 설정함으로써 인출되는 행 수를 줄일 수 있습니다. 또한 문을 실행하기 전에 "adaptive" 매개 변수를 사용하여 SQLServerStatement 개체의 setResponseBuffering 메서드를 호출하여 드라이버가 행을 버퍼링하지 않도록 지시할 수 있습니다. 결과 집합을 스크롤할 수 없으므로 응용 프로그램이 get<Type>Stream 메서드 중 하나를 사용하여 큰 열 값에 액세스하는 경우 드라이버는 정방향 읽기 전용 결과 집합을 처리할 때와 마찬가지로 응용 프로그램이 값을 읽는 즉시 해당 값을 삭제합니다.

'Brain Trainning > PRG Language' 카테고리의 다른 글

[GeoIP] .NET API 테스트 결과  (0) 2011.06.13
[Lang] 튜토리얼 사이트 링크  (0) 2011.03.07
[MSSQL] JDBC 연결  (0) 2011.02.25
[MongoDB] Comparison of data serialization formats  (0) 2011.01.18
MSSQL + PHP 연동  (0) 2010.12.21
posted by LifeisSimple
2011. 2. 28. 17:56 Brain Trainning/NoSQL
-- 페이지 아래쪽에 코드 셈플있음... 

Mongo Java Driver 코드 셈플... 강한 에러를 동반할 수 있으니 잘 수정해서 사용해야 합니다.


package com.Mongo.Test;

 

import com.mongodb.*;

import org.junit.Before;

import org.junit.Test;

import static org.junit.Assert.*;

 

public class MongoDBUnitTestII {

    private DBCollection customers;

 

    @Before

    public void setUp() throws Exception {

        Mongo mongo = new Mongo();

        DB db = mongo.getDB("webshop");

        customers = db.getCollection("customer");

        customers.remove(new BasicDBObject());

    }

 

    @Test

    public void shouldWorkWithMongoDB() {

        DBObject customerMaxMustermann = new BasicDBObject()

                .append("id", "4711")

                .append("name","Max Mustermann")

                .append("city","Cologne")

                .append("numberOfOrders", 3);

        customers.insert(customerMaxMustermann);

        DBObject savedCustomer = customers.findOne();

        assertNotNull(savedCustomer);

        assertEquals("4711", savedCustomer.get("id"));

    }

 

   /* {"id" : 1234, "name": "Otto Normal", city: "Berlin",#

      numberOfOrders: 4, bankData: {accountNumber : "9876543210", bankCode : "30020011", accountHolder : "Otto Normal"}*/

 

    private void insertCustomerOttoNormal() {

        Customer customer = new Customer();

        customer.setId("1234");

        customer.setName("Otto Normal");

        customer.setCity("Berlin");

        customer.setNumberOfOrders(4);

 

        BankData bankData = new BankData();

        bankData.setAccountNumber("9876543210");

        bankData.setBankCode("30020011");

        bankData.setAccountHolder("Otto Normal");

        customer.setBankData(bankData);

 

        customers.setObjectClass(Customer.class);

        customers.insert(customer);

    }

 

    @Test

    public void shouldSaveAndFindCustomers() {

        insertCustomerOttoNormal();

 

        // attention: all field names here begin with a capital letter

        DBCursor result = customers.find(new BasicDBObject("City", "Berlin"));

        assertTrue(result.hasNext());

        Customer savedCustomer = (Customer) result.next();

        assertEquals("1234", savedCustomer.getId());

        assertEquals("30020011", savedCustomer.getBankData().getBankCode());

    }

 

    @Test

    public void shouldIncrementTheNumberOfOrdersIfTheCustomerPlaceAnOrder() {

        insertCustomerOttoNormal();

 

        customers.update(new BasicDBObject("Id", "1234"),

                new BasicDBObject("$inc",

                        new BasicDBObject("NumberOfOrders", 1)));

        Customer savedCustomer = (Customer) customers

                .findOne(new BasicDBObject("NumberOfOrders", new BasicDBObject("$gt", 4)));

        assertNotNull(savedCustomer);

        assertEquals("Otto Normal", savedCustomer.getName());

        assertEquals(5, savedCustomer.getNumberOfOrders());

    }

}

 

'Brain Trainning > NoSQL' 카테고리의 다른 글

[MongoDB] 트위터 Collections...  (0) 2011.03.31
[MongoDB] Config 파일 옵션  (0) 2011.03.09
[MongoDB] MSSQL 2 MongoDB  (0) 2011.02.25
[MongoDB] Comparing MongoDB java frameworks  (0) 2011.02.23
[MongoDB] 당신의 모든 Backup  (0) 2011.01.25
posted by LifeisSimple
2011. 2. 25. 12:26 Brain Trainning/NoSQL

import java.net.UnknownHostException;

import java.util.Calendar;

import java.util.GregorianCalendar;

import java.util.Iterator;

import java.util.List;

import java.util.regex.Pattern;

import org.junit.Test;

import java.sql.*;

 

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 com.mongodb.MongoException;

 

 

Public Class MongoDB {

       @Test

       // MSSQL 연결

       public void testMSSQLConnection() throws Exception {

             // TODO Auto-generated method stub

             Connection conSQL = null;

             Statement stmt = null;

             ResultSet rs = null;

            

             // MSSQL

             String strJDBCDrv = "com.microsoft.sqlserver.jdbc.SQLServerDriver";

             String strJDBCUrl = "jdbc:sqlserver://localhost:1433;DatabaseName=SQLDB";

             String strQuery = "select testID, testName from T_Test order by testID desc";

            

             // MongoDB

             Mongo connection = new Mongo("MongoDBIP", 27017);

             DB mongoJUnit = connection.getDB("testDB");

             DBCollection dept = mongoJUnit.getCollection("T_Test");

            

             /*

             try{

                    Class.forName(strJDBCDrv);

                    System.err.println("드라이버 검색 성공");

             }

             catch(ClassNotFoundException ee) {

                    ee.printStackTrace();

                    System.err.println("드라이버 검색 실패");

             }

             */

             try {

                    Class.forName(strJDBCDrv).newInstance();

                    conSQL = DriverManager.getConnection(strJDBCUrl, "sa", "1231231");

                   

                    stmt = conSQL.createStatement();

                    rs = stmt.executeQuery(strQuery);

                   

                    BasicDBObject putDB = new BasicDBObject();

                    //GregorianCalendar cal = new GregorianCalendar();

                   

                    while(rs.next()){

                           // System.out.println(rs.getString(1));

                          

                           putDB.put("testID", rs.getInt(1));

                           putDB.put("testName", rs.getString(2));

                          

                           dept.insert(putDB);

                          

                           putDB.clear();

                    }

             }

             catch (Exception e){

                    e.printStackTrace();

             }

             finally {

                    conSQL.close();

                    stmt.close();

                    rs.close();

             }

       }

}

'Brain Trainning > NoSQL' 카테고리의 다른 글

[MongoDB] Config 파일 옵션  (0) 2011.03.09
[MongoDB] Java Code Sample  (0) 2011.02.28
[MongoDB] Comparing MongoDB java frameworks  (0) 2011.02.23
[MongoDB] 당신의 모든 Backup  (0) 2011.01.25
[MongoDB] MongoDB Cacti Plugin Templates  (0) 2011.01.21
posted by LifeisSimple
2011. 2. 23. 17:21 Brain Trainning/NoSQL

출처 : http://blog.knuthaugen.no/2010/07/comparing-mongodb-java-frameworks.html

Comparing MongoDB java frameworks

| 4 Comments | No TrackBacks

I while ago I gave a talk at a Oslo JavaBin meeting on NoSQL and in the research for that I wounded up writing some sample code for three different frameworks for using MongoDB from Java. The code is available on GitHub. The three are the 10Gen mongo driver (and not really a framework), morphia and mungbean.

The Whole Dynamic Thing

MongoDB is a schema-free document database and does not impose any restriction on what you can store in a collection. There is nothing stopping you from puttting entirely different objects into the same collection and thus nothing stopping you from omitting fields in two different objects of the same kind either. So how does this play with Javas strong static typing compared to a dynamic language like Ruby?

Dude, Where's My ORM?

Developers used to relational databases have been using ORMs for a long time to abstract away the dirty details of dealing with the database and separating the domain from the persistence. So, are any of the three frameworks an ORM for MongoDB? Well, no. But a more interesting question is: Do I need one? MongoDB is a very different beast than oracle/mysql/MSsql/PostgreSQL and different beasts need different handling. You need an abstraction model for MongoDB, not necessarily the ORM abstraction model.

MongoDB Java Driver

10Gen java driver basically gives you to options when storing data in MongoDB: Either subclassBasicDBObject which is the general database object, or implement the DBObject interface. Both approaches gives you the interface of Map from the standard java library and lets you put and get keys and values. The drawback is that there are a lot of methods in this interface and it will soon become tedious to implement them all for different domain objects. This it the DBObject interface methods:

public Object put(String s, Object o) { }
 
public void putAll(DBObject dbObject) { }
 
public void putAll(Map map) { }
 
public Object get(String s) { }
 
public Map toMap() { }
 
public Object removeField(String s) { }
 
public boolean containsKey(String s) { }
 
public boolean containsField(String s) { }
 
public Set<string> keySet() { }
 
public void markAsPartialObject() { }
 
public boolean isPartialObject() {}
</string>

So I'd prefer to subclass BasicDBObject instead or wrap it.

So how does code using it look like? Assume the very minimal domain objects Person andAddress

package no.kh.mongo.direct;
import com.mongodb.BasicDBObject;
 
public class Person extends BasicDBObject {
 
public Person () { }
 
public Person(String fullName, Address newAddress) {
put("name", fullName);
put("address", newAddress);
 
}
 
}
package no.kh.mongo.direct;
import com.mongodb.BasicDBObject;
 
public class Address extends BasicDBObject {
 
public Address() {
}
 
public Address(String streetName, String postalCode, String place, String country) {
put("street", streetName);
put("postalcode", postalCode);
put("place", place);
put("country", country);
}
 
public String place(){
return (String) get("place");
}
 
}

Using this class is done like this in the form of functional/integration tests, since they touch the database but written in Junit:

package no.kh.mongo.direct;
 
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.Mongo;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
 
import java.net.UnknownHostException;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
 
public class PersonPersistance {
 
DB testDb;
DBCollection persons;
 
@Before
public void setUp() throws UnknownHostException {
Mongo m = new Mongo( "127.0.0.1" 27017 );
 
testDb = m.getDB( "test" );
persons = testDb.getCollection("persons");
persons.setObjectClass(Person.class);
}
 
@Test
public void insertPersonSavesPersonToDatabase () {
 
Person test = new Person("Knut Haugen",
new Address("Josefines gate""0401",
"Oslo""Norge"));
persons.insert(test);
assertNotNull(test.get("_id"));
 
}
 
 
@Test
public void personWithDocumentNotMatchingObject(){
BasicDBObject tmp = new BasicDBObject();
tmp.append("foo""value");
persons.insert(tmp);
 
Person test2 = (Person) persons.findOne();
assertEquals(test2.get("foo"), "value");
assertNull(test2.get("name"));
}
 
@Test
public void retrievePersonFromDatabase(){
Person test = new Person("Knut Haugen",
new Address("Josefines gate""0401",
"oslo""Norge"));
persons.insert(test);
 
Person test2 = (Person) persons.findOne();
assertEquals(test.get("name"), test2.get("name"));
assertEquals( ((Address) test.get("address")).place(), "oslo");
}
 
@After
public void tearDown(){
persons.drop();
}
 
}

Notice the call to setObjectClass() on the collection object to get "type-safe" operations even though you still have to cast the return value from findOne() to get you precious object back. Other than that it is pretty straight forward. Call insert() on the collection to insert an object,findOne() or any other query method to retrieve it. But to the bottom line is this driver really begs for some more abstraction when you're beyond toy samples. The positive effect is more direct access to the data which is often the way it's done in dynamic languages. But does that suit Java? I'm not sure but tend to think no. And how about those nulls? Well, if one object doesn't store a value in a field, the field is null when returned from the database, as you can see from the test personWithDocumentNotMatchingObject.

Morphia

Morphia is a (according to the blurb) a light-weight type-safe mapper for MongoDB providing DAOand Datastore abstractions. It takes the annotation approach. Here's our Person and Addressclasses for Morphia:

package no.kh.mongo.morphia;
import com.google.code.morphia.annotations.Embedded;
import com.google.code.morphia.annotations.Entity;
import com.google.code.morphia.annotations.Id;
 
@Entity
public class Person {
 
@Id
private String id;
private String name;
 
@Embedded
private Address address;
 
public Person() {
address = new Address("""""""");
}
 
public Person(Address newAddress){
address = newAddress;
}
 
public String getId() {
return id;
}
 
 
public String getName() {
return name;
}
 
public void setId(String newId) {
id = newId;
}
 
public void setName(String newName) {
name = newName;
}
 
public void setAddress(Address newAddress) {
address = newAddress;
}
 
}
package no.kh.mongo.morphia;
import com.google.code.morphia.annotations.Embedded;
 
@Embedded
public class Address {
 
private String streetName;
private String postalCode;
private String place;
private String country;
 
public Address() {
}
 
public Address(String streetName, String postalCode, String place, String country) {
this.streetName = streetName;
this.postalCode = postalCode;
this.place = place;
this.country = country;
}
 
}

Where Address is annotated as an embedded object. This is the same approach taken by the ruby Mongo_Mapper with its MongoMapper::Document and MongoMapper::EmbeddedDocument classes.

package no.kh.mongo.morphia;
 
import com.google.code.morphia.Morphia;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.Mongo;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
 
import java.net.UnknownHostException;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;
 
public class PersistanceThroughMorphia {
 
Morphia morph;
Mongo mongo;
DBCollection persons;
 
@Before
public void setUp() throws UnknownHostException {
morph = new Morphia();
mongo = new Mongo("127.0.0.1"27017);
// This is where we map Persons and addresses
// But shouldn't the annotation be able to handle that?
morph.map(Person.class).map(Address.class);
DB testDb = mongo.getDB( "test" );
persons = testDb.getCollection("persons");
}
 
@Test
public void storePersonThroughMorphiaMapping () {
 
Person test = new Person(new Address("Josefines gate""0401""Oslo","Norge") );
test.setName("Knut Haugen");
 
persons.save(morph.toDBObject(test));
Person test2 = morph.fromDBObject(Person.class, persons.findOne());
assertNotNull(test2.getId());
 
}
 
 
@Test
public void personMissingField () {
 
Person test = new Person(new Address("Josefines gate""0401""Oslo","Norge"));
 
persons.save(morph.toDBObject(test));
Person test2 = morph.fromDBObject(Person.class, persons.findOne());
assertNull(test2.getName());
 
}
 
 
@After
public void tearDown(){
persons.drop();
}
 
}

It seems like something out of the department of redundancy department that you annotate the document and the embedded document and then have to specify the relationship between them in a method call. My first reaction was that that would have been cleaner if the relationship could be specified in the annotation too. The calls to morph.toDBObject() and morph.fromDBObject()breaks up an otherwise elegant solution. It also introduces some more code and it basically wraps up a cast. That could have been a lot cleaner.

Mungbean

Mungbean is our last contestant and represents a third way of doing the mapping. It wraps upeverything you need for accessing MongoDB with generic collection classes and introduces a DSL for querys and the like. There's also a clojure version if that is more like your poison. The domain classes with mungbean:

package no.kh.mongo.mungbean;
 
public class Address {
 
private String streetName;
private String postalCode;
private String place;
private String country;
 
public Address() {
}
 
public Address(String streetName, String postalCode, String place, String country) {
this.streetName = streetName;
this.postalCode = postalCode;
this.place = place;
this.country = country;
}
 
public String place(){
return place;
}
 
}

Nothing special here, no imports and no annotations. (Almost the) Same with Person except for the import and field of type ObjectID which handles the object ids generated by mongo on insert:

package no.kh.mongo.mungbean;
import mungbean.ObjectId;
 
public class Person {
private String name;
private ObjectId _id = new ObjectId();
private String address;
 
 
public Person(String name, String address){
this.name = name;
this.address = address;
}
 
public String getAddress(){
return address;
}
 
public ObjectId getId(){
return _id;
}
}

Using it on the other hand, creates a very different looking code than the other two, thanks to the wrapper classes for mongodb connections, the generic collections and the query DSL:

package no.kh.mongo.mungbean;
 
import mungbean.DBCollection;
import mungbean.Database;
import mungbean.Mungbean;
import mungbean.Settings;
import mungbean.query.Query;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
 
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
 
public class mungbeanPersistence {
 
private Database test;
private Person testPerson;
private DBCollection<person> persons;
 
 
@Before
public void create() {
test = new Mungbean(new Settings(), "localhost"27017).openDatabase("test");
testPerson = new Person("Knut Haugen""josefines gate");
persons = test.openCollection("persons", Person.class);
 
}
 
@Test
public void storePerson(){
persons.save(testPerson);
assertEquals(persons.query(new Query().field("name").is("Knut Haugen")).size(),1);
 
}
 
 
@Test
public void personGetGeneratedIdAndAddress(){
persons.save(testPerson);
Person found = persons.query(new Query().field("name").is("Knut Haugen")).get(0);
assertNotNull(found.getId());
assertEquals(found.getAddress(), "josefines gate");
 
}
 
 
@After
public void destroy() {
test.dbAdmin().dropDatabase();
}
 
}
</person>

The syntax is nice but perhaps a tad verbose for mye taste. I find the abstraction quite good, at least better than the other two. I also like the fact that there is almost no trace of the library in the domain classes and as such it is by far the best of the three.

The Verdict

It's Mungbean, by a nose! Mainly because of the cleaner domain objects and the DSL. There is more code involved but I found it to be more elegant than the other approaches. I want to note that both morphia and mungbean are not immensely mature and done by any definition of the word and that has to come into consideration when using them. And it may be that a wordy statically typed language like Java has a bit of friction with a very dynamic database backend like MongoDB. I don't know, but I'll be looking into ruby drivers in the future and we'll see.

I haven't looked into the different code generation frameworks for mongo, namely Sculptor andGuicyData which take a different approach to accessing MongoDB. That's for another time and another post.

No TrackBacks

TrackBack URL: http://blog.knuthaugen.no/mt/mt-tb.cgi/30

4 Comments

The last two you are mentioning (GuicyData and Sculptor) are covered here:http://nosql.mypopescu.com/post/816470307/tutorial-mongodb-in-java

You are using the low-level mapping capabilities of morphia instead of the much nicer datastore, or DAO interfaces. There should be no need to use the driver DBCollection object. You can remove most of your code by using the higher-level abstractions. Also, all the annotations (except @Id) are optional in your example.


@Before
public void setUp() throws UnknownHostException {
ds = new Morphia().createDatastore("test");
}

public void storePersonThroughMorphiaMapping () {

Person test = new Person(new Address("Josefines gate", "0401", "Oslo", "Norge") );
test.setName("Knut Haugen");

ds.save(test);
Person test2 = ds.get(Person.class, test.getId());
assertNotNull(test2.getId());
}

'Brain Trainning > NoSQL' 카테고리의 다른 글

[MongoDB] Java Code Sample  (0) 2011.02.28
[MongoDB] MSSQL 2 MongoDB  (0) 2011.02.25
[MongoDB] 당신의 모든 Backup  (0) 2011.01.25
[MongoDB] MongoDB Cacti Plugin Templates  (0) 2011.01.21
[MongoDB] Why MongoDB is Awesome  (0) 2011.01.21
posted by LifeisSimple
2011. 1. 7. 17:56 Brain Trainning/NoSQL

import java.net.UnknownHostException;

import java.util.Iterator;

 

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 com.mongodb.MongoException;

 

public class MongoDBTest {

 

       public MongoDBTest() {

             // TODO Auto-generated constructor stub

       }

 

       /**

        * @param args

        * @throws MongoException

        * @throws UnknownHostException

        */

       public static void main(String[] args) throws UnknownHostException, MongoException {

             // TODO Auto-generated method stub

             Mongo connection = new Mongo("172.16.72.38", 27017);

            

             DB db = connection.getDB("test");

             DBCollection dept = db.getCollection("department");

             BasicDBObject query = new BasicDBObject();

            

             // query string : db.department.find({dptcode:"HR"})

             query.put("dptcode", "HR");

             DBCursor cur = dept.find(query);

            

             int index = 1;

             for ( Iterator<DBObject> it = cur.iterator(); it.hasNext(); ++index) {

                    DBObject obj = it.next();

                   

                    System.out.println("data("+ index+"):"+obj);

             }

            

             // query string : db.department.insert({dptcode:"IT", dptname:"한글이사", dptnote:"주워먹을건 아무것도 없음"})

             BasicDBObject putDB = new BasicDBObject();

            

             /*

             putDB.put("dptcode", "IT");

             putDB.put("dptname", "한글이사");

             putDB.put("dptnote", "주워먹을건 아무것도 없음");

            

             dept.insert(putDB);

             */

            

             query.put("dptcode", "IT");

            

             System.out.println(dept.findOne(query));

       }

posted by LifeisSimple
prev 1 next