Showing posts with label hibernate. Show all posts
Showing posts with label hibernate. Show all posts

Friday, September 18, 2015

menguji atomisitas redis - INCR command

post ini ditujukan untuk menguji sifat atomisitas command INCR redis.

kebutuhannya adalah, misalnya di aplikasi saya membutuhkan sebuah generator kode unik. cara termudah untuk membuat kode unik adalah dengan melakukan increment yang dimulai dari suatu angka, dan seterusnya. nantinya ini bisa dikombinasikan dengan character lain.

jika kita melihat dari 1 jvm, hal ini mudah saja, misalnya kita bisa buat sebuah variable static yang menampung angka tertentu dan menyiapkan sebuah method synchronized bagi thread yang hendak mengambil value tersebut (dan meng-increment-nya).

kira-kira seperti ini gambarannya


namun hal ini akan menjadi masalah saat aplikasi kita semakin besar dan membutuhkan scaling ke lebih dari 1 jvm. karena static variable dan synchronized hanya berlaku di 1 jvm saja. anggaplah kita punya 2 jvm, jika menggunakan static variable dan synchronized method, maka masing-masing jvm akhirnya akan menyimpan angka incrementnya sendiri-sendiri.



sehingga jika digabungkan, misalnya kita hendak menyimpan value itu dalam sebuah database yang sama dimana field tersebut dibuat unique, besar kemungkinannya kita akan kena ConstraintViolationException.

lalu bagaimana solusinya?

idenya adalah kedua jvm tersebut harus mengakses memory yang sama. sebuah cache bisa kita manfaatkan, mari kita coba dengan redis. kita letakkan instance redis di sebuah tempat, bisa di vm yang sama atau berbeda, untuk pengujian ini semuanya berada di 1 vm yang sama. tetapi untuk production jelas sebaiknya masing-masing memiliki vm-nya sendiri-sendiri.

kira-kira seperti ini skema umumnya


dalam percobaan ini, kita akan menggunakan command INCR milik redis,
"The counter pattern is the most obvious thing you can do with Redis atomic increment operations. The idea is simply send an INCR command to Redis every time an operation occurs." -http://redis.io/commands/INCR

command ini bersifat atomic, sehingga aman untuk proses multithread.

skema ini yang akan saya coba


saya akan aktifkan 1 jvm dulu, berkomunikasi dengan redis, memanfaatkan command INCR untuk mendapatkan sebuah value, dan value tersebut akan saya simpan di database. penyimpanan di database ini hanya bertujuan untuk mempermudah pengecekan, nantinya saya akan cek dengan menggunakan query

 select * from (  
     select value, count(1) n from redis_result group by value  
 ) a where a.n>1;  

jika INCR berjalan dengan benar, maka query tersebut akan menghasilkan result kosong.

saya menggunakan springboot 1.2.5 dengan library spring data, orm hibernate, database connection pool menggunakan apache commons-dbcp 1.4, redis connection pool dengan jedis 2.5.2.

skenarionya, saya akan menyiapkan 1 controller untuk memudahkan akses (tadinya saya mau menggunakan junit tapi junit tidak memungkinkan untuk test multithread). controller tersebut akan memanggil suatu class service yang akan mengeksekusi 5 thread. di dalam masing-masing thread tersebut saya akan melakukan looping sebanyak 2000 iterasi yang akan memanggil command INCR ke redis dan menyimpan value-nya ke database (table redis_result).

dengan skenario ini, maka akan ada sebanyak 5*2000 record yang tersimpan di table.

berikut ini configurasi redis connection pool nya:
 <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">  
     <property name="testOnBorrow" value="true"/>  
     <property name="testOnReturn" value="true"/>  
     <property name="testWhileIdle" value="true"/>  
     <property name="numTestsPerEvictionRun" value="10"/>  
     <property name="maxTotal" value="5000" />  
     <property name="minIdle" value="100" />  
   </bean>  
   <!-- for pooling the publisher -->  
   <bean id="redisConnectionPool" class="redis.clients.jedis.JedisPool" destroy-method="destroy">  
     <constructor-arg index="0" ref="jedisPoolConfig"/>  
     <constructor-arg index="1" value="localhost" type="java.lang.String"/>  
     <constructor-arg index="2" value="6379" type="int"/>  
   </bean>  

configurasi db connection pool:
 <bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">  
     <property name="driverClassName" value="${database.driverClassName}"/>  
     <property name="url" value="${database.url}"/>  
     <property name="username" value="${database.username}"/>  
     <property name="password" value="${database.password}"/>  
     <<property name="validationQuery" value="SELECT version();"/>  
     <property name="initialSize" value="100"/>  
     <property name="maxActive" value="200"/>  
     <property name="maxIdle" value="100">  
   </bean>  

RedisUtil.java, yaitu class yang berfungsi sebagai redis client
 @Component  
 public class RedisUtil {  

   private static final Logger LOGGER = LoggerFactory.getLogger(RedisUtil.class);  

   @Autowired  
   @Qualifier(value = "redisConnectionPool")  
   JedisPool redisConnectionPool;  

   private void releaseJedisConnection(Jedis jedis){  
     if(null != jedis) {  
       LOGGER.debug("Return redis connection to pool");  
       redisConnectionPool.returnResource(jedis);  
     }  
   }  

   /**  
    * INCR key  
    * @param key  
    * @return  
    */  
   public Long increment(String key){  
        Long result = null;  
        Jedis jedis = null;  
     try {  
          jedis = redisConnectionPool.getResource();  
       result = jedis.incr(key);  
     } catch (JedisConnectionException jce) {  
          LOGGER.error("Failed add set to {} :: {}", key, jce.getMessage());  
     } finally {  
          releaseJedisConnection(jedis);  
     }  
     return result;  
   }  

   /**  
    * SET key  
    * @param key  
    * @return  
    */  
   public void set(String key, String value){  
        Jedis jedis = null;  
     try {  
          jedis = redisConnectionPool.getResource();  
       jedis.set(key, value);  
     } catch (JedisConnectionException jce) {  
          LOGGER.error("Failed add set to {} :: {}", key, jce.getMessage());  
     } finally {  
          releaseJedisConnection(jedis);  
     }  
   }  
 }  

RedisTask.java, yaitu class yang meng-increment key di redis dan menyimpan di database (dalam skema di atas, ini sama dengan thread01, thread02, dst..)
 public class RedisTask implements Runnable {  
        
      RedisUtil redisUtil;  
      RedisResultRepository redisResultRepository;  
        
      private static final String INCR_KEY = "incrKey";  
        
      public RedisTask(){  
           redisUtil = ApplicationContextHolder.getApplicationContext().getBean(RedisUtil.class);  
           redisResultRepository = (RedisResultRepository) ApplicationContextHolder.getApplicationContext().getBean("redisResultRepository");  
      }  
        
      public String getIncrValue() {  
           String result = null;  
   
           Long val = redisUtil.increment(INCR_KEY);  
           if (val == null || val.intValue() == 0) {  
                redisUtil.set(INCR_KEY, 1 + "");  
                result = getIncrValue();  
           } else {  
                result = val.toString();  
           }  
   
           return result;  
      }  
   
      @Override  
      public void run() {  
           for(int i=0; i<2000; i++){  
                String value = getIncrValue();  
                RedisResult result = new RedisResult(value);  
                redisResultRepository.save(result);  
           }  
      }  
        
 }  

RedisDemoService.java, yaitu class yang akan mengeksekusi 5 instance RedisTask secara concurrent
 @Service  
 public class RedisDemoService {  
        
      private static final ExecutorService EXECUTOR = Executors.newFixedThreadPool(5);  
        
      public void redisIncrTest(){  
             
           for(int i=0; i<5; i++){  
                System.out.println("execute redis task " + i);  
                EXECUTOR.execute(new RedisTask());  
           }  
             
      }  
        
 }  

RedisResult.java, yaitu POJO model domainnya
 @Entity  
 public class RedisResult extends BaseEntity {  
        
      private static final long serialVersionUID = -4902968469441816467L;  
        
      @Column(name = "value")  
      private String value;  
        
      public RedisResult(){  
             
      }  
        
      public RedisResult(String value){  
           this.value = value;  
      }  
   
      public String getValue() {  
           return value;  
      }  
   
      public void setValue(String value) {  
           this.value = value;  
      }  
 }  

RedisResultRepository.java, yaitu interface dari springdata yang akan menjadi akses komunikasi ke db
 @Repository  
 public interface RedisResultRepository extends JpaRepository<RedisResult, Long> {  
   
 }  

dan yang terakhir adalah controller-nya untuk kita akses dengan REST, RedisDemoController.java
 @RestController  
 @RequestMapping(value = "/redis")  
 public class RedisDemoController {  
        
      @Autowired  
      private RedisDemoService redisDemoService;  
   
      @RequestMapping(value = "/demo", method = RequestMethod.GET)  
      @ResponseBody  
      public boolean calculate() throws Exception {  
   
           redisDemoService.redisIncrTest();  
   
           return true;  
      }  
        
 }  

jika aplikasi kita nyalakan pada port 8181, kemudian kita bisa akses dia dengan
 curl -XGET http://localhost:8181/redis/demo  

setelah prosesnya selesai, kita count apakah jumlahnya benar

lalu kita cek apakah ada duplikasi value


oke, aman. sejauh ini tidak ada masalah.
lalu kita harus coba dengan menggunakan 2 jvm, saya menggunakan code yang sama tetapi saya nyalakan pada port yang berbeda, aplikasi kedua ini menggunakan port 8182.

kita coba secara bersama-sama
 curl -XGET http://localhost:8181/redis/demo  
 curl -XGET http://localhost:8182/redis/demo  

kemudian kita cek apakah jumlah recordnya benar


apakah ada duplikasi


woohoo, hasilnya baik-baik saja.

jadi kesimpulannya adalah command INCR redis dapat digunakan untuk kasus seperti di atas. untuk lebih meyakinkan diri mungkin perlu dilakukan lagi dengan 10 atau lebih jvm, tentunya jika memiliki environment yang sesuai.

thanks.

Thursday, June 18, 2015

FullText Search Query : menggunakan Hibernate-Search


Jumpa lagi kita dengan team nostratech. Kali ini kita akan belajar tentang seraching data di database menggunakan Full Text Search. Apa itu full text search?.

Seperti saat kita search di google. Kita ketik keyword apa, maka akan muncul list data yang sesuai (match atau sama persis dengan keyword yang kita ketik) dan juga semua data ada hubungannya dengan keyword yang kita ketik. Misal kita ketik 'hibernate book', maka akan muncul semua list yang ada kata mirip denhan 'hibernate' dan 'book'.



Seperti itulah sederhananya pengertian full text search.

Kita ambil contoh yang sederhana saja.
Misalnya kita punya data list nama contact di tabel seperti ini :


Disini kita asumsikan kita menggunakan ORM hibernate.

Bagaimana caranya search data “Paolo Coelho Jr” ? Kalo menggunakan keyword 'paolo' tentunya kita memakai query :

 select a from Contact where a.name like 'paolo%'  

jika keyword dari usernya 'coelho' :

 select a from Contact where a.name like '%coelho%'  

Nah bagaimana jika keyword dari usernya seperti ini : 'coelho Jr', 'coelho jr paolo', 'famous writer paolo coelho', 'the name of Coelho NM paolo ' dan lain lain.
Tentu kita akan bingung dan akan kesulitan tentunya kita.
Search query classic : name like '%keyword%' tentu tidak bisa menghandle lagi jika sudah menggunakan query yang aneh aneh seperti diatas.
Selain tidak mendapatkan hasil yang diharapkan, tentunya query %% tentu sangat buruk untuk masalah performence kalau datanya sudah terlampau banyak (walaupun field name di tabel Contact sudah di Index).

Solusinya kita bisa menggunakan library hibernate-search untuk menangani search query untuk problem diatas.
Hibernate search didalamnya menggunakan engine apache lucene untuk indexing datanya. Jadi nantinya data Name dari tabel Contact akan disimpan di index lucene.
Hibernate tidak akan langsung mencari data di tabel contact tetapi di cari terlebih dulu di index luncene.

Proses yang terjadi kurang lebih seperti ini :

Hibernate --> search index lucene --> search index name dan get id nya --> search ke tabel contact berdasarkan id --> tampilkan data.

Tambahkan dependency maven di pom.xml

 <dependency>  
   <groupId>org.hibernate</groupId>  
   <artifactId>hibernate-core</artifactId>  
   <version>4.3.9.Final</version>  
 </dependency>  
 <dependency>  
   <groupId>org.hibernate</groupId>  
   <artifactId>hibernate-search-orm</artifactId>  
   <version>5.2.0.Final</version>  
 </dependency>  

Mari kita mulai ke contohnya.

Kita buat dulu model Contact.

Set property mana yang akan diindex menggunakan @Field

 import javax.persistence.Entity;  
 import javax.persistence.Id;  
 import javax.persistence.Table;  
 import org.apache.lucene.analysis.core.LowerCaseFilterFactory;  
 import org.apache.lucene.analysis.snowball.SnowballPorterFilterFactory;  
 import org.apache.lucene.analysis.standard.StandardTokenizerFactory;  
 import org.hibernate.search.annotations.*;  
 /**  
  * The persistent class for the contact database table.  
  */  
 @Entity  
 @Indexed  
 @AnalyzerDef(name = "customanalyzer",  
     tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),  
     filters = {  
         @TokenFilterDef(factory = LowerCaseFilterFactory.class)  
         , @TokenFilterDef(factory = SnowballPorterFilterFactory.class  
     )  
     })  
 @Table(name = "contact")  
 public class Contact {  
   @Id  
   @DocumentId  
   private Integer id;  
   @Field(index = Index.YES, store = Store.NO)  
   @Analyzer(definition = "customanalyzer")  
   private String name;  
   private String email;  
      /// setter + getter  
 }  

Hibernate config xml
 <?xml version="1.0" encoding="UTF-8"?>  
 <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"   
 "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">  
 <hibernate-configuration>  
   <session-factory>  
    <property name="show_sql">false</property>  
    <property name="format_sql">true</property>  
    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>  
    <property name="connection.driver_class">com.mysql.jdbc.Driver</property>  
    <property name="connection.url">jdbc:mysql://localhost:3306/test</property>  
    <property name="connection.username">root</property>  
    <property name="connection.password"></property>  
    <property name="hibernate.hbm2ddl.auto">update</property>  
    <property name="hibernate.show_sql">true</property>  
    <property name="hibernate.search.default.directory_provider">filesystem</property>  
    <property name="hibernate.search.default.indexBase">/tmp/lucene/indexes</property>  
    <mapping class="com.srccodes.example.hibernate.Contact"/>  
   </session-factory>  
 </hibernate-configuration>  

untuk menentukan dimana kita menyimpan file index nya.

 <property name="hibernate.search.default.directory_provider">filesystem</property>  
 <property name="hibernate.search.default.indexBase">/tmp/lucene/indexes</property>  


Hibernate session until (kalau kita mengunakan JPA diatas hibernate kita bisa menggunakan entity manager)

 public class HibernateUtil {  
   private static SessionFactory sessionFactory = null;   
   private static ServiceRegistry serviceRegistry = null;   
   private static SessionFactory configureSessionFactory() throws HibernateException {   
     Configuration configuration = new Configuration();   
     configuration.configure();   
     Properties properties = configuration.getProperties();  
    serviceRegistry = new ServiceRegistryBuilder().applySettings(properties).buildServiceRegistry();       
     sessionFactory = configuration.buildSessionFactory(serviceRegistry);   
     return sessionFactory;   
   }  
   static {  
    configureSessionFactory();  
   }  
   private HibernateUtil() {}  
   public static Session getSession() {  
    return sessionFactory.openSession();  
   }  
 }  

Create indexing pada setiap insert, update, delete data agar index di lucene terupdate mengikuti data di tabel.

 private void doIndex() throws InterruptedException {  
   Session session = HibernateUtil.getSession();  
   FullTextSession fullTextSession = Search.getFullTextSession(session);  
   fullTextSession.createIndexer().startAndWait();  
   fullTextSession.close();  
 }  

Create fulltext session dan lucene query yang nantinya akan diterjemahkan ke JPA/hibernate query. Jadi kita tidak perlu secara detail tahu tentang lucene query karen sudah dihandle oleh si hibernate.

 private List<Contact> search(String queryString) {  
   Session session = HibernateUtil.getSession();  
   FullTextSession fullTextSession = Search.getFullTextSession(session);  
   QueryBuilder queryBuilder = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(Contact.class).get();  
   org.apache.lucene.search.Query luceneQuery = queryBuilder  
   .keyword().onFields("name").matching(queryString).createQuery();  
   org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery(luceneQuery, Contact.class);  
   List<Contact> contactList = fullTextQuery.list();  
   fullTextSession.close();  
   return contactList;  
 }  

jika dilihat di sq log maka query ditabel contact hanya mengunakan where id (yg didapat dari lucene index) tidak ada pencarian berasarkan 'name'. Karena name sudah dihandle oleh hibernate-search.

 Hibernate:   
   select  
     this_.id as id1_0_0_,  
     this_.email as email2_0_0_,  
     this_.name as name3_0_0_   
   from  
     contact this_   
   where  
     (  
       this_.id in (  
         ?  
       )  
     )  


Berikut contoh pencarian data dengan beberapa keyword :
 >>>>>>Record found for 'paolo coelho' count : 1  
 Id: 2 | Name:Paolo Coelho | Email:paolo@gmail.com  
 ===============================================  
 >>>>>>Record found for 'mr coelho paolo is his name' count : 1  
 Id: 2 | Name:Paolo Coelho | Email:paolo@gmail.com  
 ===============================================  
 >>>>>>Record found for 'who is mister coelho paolo ?' count : 1  
 Id: 2 | Name:Paolo Coelho | Email:paolo@gmail.com  
 ===============================================  
 >>>>>>Record found for 'famous writer paolo coelho' count : 1  
 Id: 2 | Name:Paolo Coelho | Email:paolo@gmail.com  
 ===============================================  

Sekedar tambahan file index lucene bisa dibuka menggunakan software Luke.


Setiap kata di property Contact -> name di index oleh lucene (dan disimpan Id nya). Dari sinilah hibernate mencari index beradasarkan keyword yang diinginkan





Happy coding & selamat menjalankan ibadah puasa ramadhan bagi yang menjalankan.




Sunday, March 15, 2015

Hibernate - Optimisasi query

Pada blog kali ini saya akan memberikan tips untuk meningkatkan performance Hibernate aplikasi.

Skenario :
Kita mempunyai tabel dengan Department(Master) dan Employee(Detail).
Pada aplikasi akan menampilkan semua data pada Master dan Detail. Jika aplikasi berjalan sangat lamban mungkin hal ini terjadi dikarenakan Hibernate mengeksekusi query yang tidak diharapkan. Hal ini terjadi dikarenakan relasi one to many atau one to one antar master dan detail. Pertama - tama kita lakukan konfigurasi hibernate.cfg.xml dengan menambahkan :

<property name="hibernate.show_sql" value="true" />

Jika di set true SQL statements akan ditampilkan di console.

Entity class Department :
 

package com.byteslounge.spring.tx.model;
import java.util.Set;
/**
 * Created by nostra on 1/14/15.
 */
import javax.persistence.*;

@Entity
public class Department
{
    @Id
    @GeneratedValue( strategy=GenerationType.AUTO )
    private int id;
    @OneToMany(mappedBy = "eid",fetch = FetchType.EAGER)
    private Set<Employee> employeeCollection;
    private String name;

    public int getId()
    {
        return id;
    }

    public void setId(int id)
    {
        this.id = id;
    }

    public String getName( )
    {
        return name;
    }

    public void setName( String deptName )
    {
        this.name = deptName;
    }

    public Set getEmployeeCollection() {
        return employeeCollection;
    }

    public void setEmployeeCollection(Set employeeCollection) {
        this.employeeCollection = employeeCollection;
    }
}
Entity Class Employee:
 
package com.byteslounge.spring.tx.model;

import javax.persistence.*;

/**
 * Created by nostra on 1/14/15.
 */
@Entity
public class Employee
{
    @Id
    @GeneratedValue( strategy= GenerationType.AUTO )
    private int eid;
    private String ename;
    private double salary;
    private String deg;
    @ManyToOne
    private Department department;

    public Employee(int eid,
                    String ename, double salary, String deg)
    {
        super( );
        this.eid = eid;
        this.ename = ename;
        this.salary = salary;
        this.deg = deg;
    }

    public Employee( )
    {
        super();
    }

    public int getEid( )
    {
        return eid;
    }
    public void setEid(int eid)
    {
        this.eid = eid;
    }

    public String getEname( )
    {
        return ename;
    }
    public void setEname(String ename)
    {
        this.ename = ename;
    }

    public double getSalary( )
    {
        return salary;
    }
    public void setSalary(double salary)
    {
        this.salary = salary;
    }

    public String getDeg( )
    {
        return deg;
    }
    public void setDeg(String deg)
    {
        this.deg = deg;
    }

    public Department getDepartment() {
        return department;
    }

    public void setDepartment(Department department) {
        this.department = department;
    }
}
Java Code :
 
      List <department> listDeprt= sess.createQuery("from department").list();
             for(Department dept : listDeprt){
            for(Employee emp : dept.getEmployeeCollection()){
                //do Something
            }
        }

Hibernate akan mengeksekusi 1+ N (jumlah row di Department) select statement. 1 Untuk mendapatkan data Department dan N untuk Employee. Jika ada 20 data pada tabel Master maka hibernate akan mengeksekusi 1+20 select statement.

Dan untuk solusi ini adalah:

Pertama dengan menggunakan @BatchSize
@OneToMany(mappedBy = "eid",fetch = FetchType.EAGER)
@BatchSize(size = 10) 
private Set<Employee> employeeCollection;
Jika terdapat 20 data pada tabel master maka select statement yang dihasilkan adalah 3 statement, Keterangan:

  • Select statement untuk mendapatkan semua data Department(Master).
  • Select statement untuk 10 data pertama.
  • Select statement untuk 10 data selanjutnya.

Kedua dengan menggunakan @Fetch(FetchMode.JOIN)
  @OneToMany(mappedBy = "eid")
  @Fetch(FetchMode.JOIN)
  private Set employeeCollection;
Maka hibernate akan mengeksekusi satu query (join column) .


Sekian blog dari saya, semoga bermanfaat :)

Monday, June 16, 2014

Hibernate OGM

Hibernate OGM (Object Grid Mapper) merupakan persistence framework untuk NoSQL datastore (seperti MongoDB). Berbeda dengan Hibernate ORM yang khusus untuk relational database seperti MySQL, Oracle, postgresql dll.
Sayang sekali versi yang terakhir direlease masih Beta (belum final atau stable), yakni 4.1.0.Beta4. Jadi kemungkinan masih banyak kekurangan dan perlu banyak pengembangan.
Jika kita sudah familiar dengan JPA tentunya akan lebih mudah untuk menggunakan framework ini.
Untuk dokumentasi lebih lengkapnya bisa dilihat disini.

Sekarang kita mulai saja dengan contohnya.

Database yang akan digunakan adalah MongoDB.
Start mongoDB admin dan client nya
 $ mongod  
 $ mongo  

Create java project dengan struktur maven. Tambahkan library MongoDB driver dan MongoDB hibernate OGM di pom.xml
 <dependency>  
       <groupId>org.mongodb</groupId>  
       <artifactId>mongo-java-driver</artifactId>  
       <version>2.12.2</version>  
 </dependency>  
 <dependency>  
       <groupId>org.hibernate.ogm</groupId>  
       <artifactId>hibernate-ogm-mongodb</artifactId>  
       <version>4.1.0.Beta3</version>  
     </dependency>  


Tambahkan library core untuk Hibernate OGM
 <dependency>  
       <groupId>org.hibernate.ogm</groupId>  
       <artifactId>hibernate-ogm-core</artifactId>  
       <version>4.1.0.Beta4</version>  
     </dependency>  
     <dependency>  
       <groupId>org.hibernate.ogm</groupId>  
       <artifactId>hibernate-ogm-infinispan</artifactId>  
       <version>4.1.0.Beta4</version>  
     </dependency>  

Create satu contoh domain entity class. Misalnya class Employee. Hampir sama dengan hibernate ORM, karena kita memakai standart JPA.

 @Entity  
 public class Employee {  
   @Id  
   @GeneratedValue(strategy = GenerationType.AUTO)  
   private Integer id;  
   @Column(name = "firstname")  
   private String firstname;  
   @Column(name = "lastname")  
   private String lastname;  
   @Column(name = "phone")  
   private String phone;  
   ……       
 }  


Create persistence.xml di resource/META-INF yang berisi daftar class mapping dan koneksi ke datastrore.

Jangan lupa providernya diset  “org.hibernate.ogm.jpa.HibernateOgmPersistence”.
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>  
 <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">  
 <persistence-unit name="samplePersistenceUnit" transaction-type="RESOURCE_LOCAL">  
   <!-- Use Hibernate OGM provider: configuration will be transparent -->  
   <provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>  
   <class>com.andri.hibernate.sample.persistence.domain.Employee</class>  
   <class>com.andri.hibernate.sample.persistence.domain.Address</class>  
   <properties>  
       <!-- Configure Hibernate OGM to mount Infinispan -->  
       <property name="hibernate.ogm.datastore.provider" value="org.hibernate.ogm.datastore.mongodb.impl.MongoDBDatastoreProvider"/>  
       <property name="hibernate.ogm.datastore.database" value="sample-mongo-test"/>  
       <property name="hibernate.ogm.datastore.host" value="localhost"/>  
       <property name="hibernate.search.default.directory_provider" value="filesystem"/>  
       <property name="hibernate.search.default.indexBase" value="/tmp/.hibernate_ogm_demo_luceneindexes"/>  
       <property name="hibernate.ogm.datastore.grid_dialect" value="org.hibernate.ogm.datastore.mongodb.MongoDBDialect" />  
   </properties>  
   </persistence-unit>  
 </persistence>  

Create sample class DAO yang mengimplementasikan proses CRUD untuk domain yang sudah kita buat tadi (persist, merge, delete).
 public class EmployeeDao {  
   private EntityManagerFactory emf = Persistence.createEntityManagerFactory("samplePersistenceUnit");  
   private EntityManager em = emf.createEntityManager();  
   public void save(Employee employee){  
     EntityTransaction transaction = em.getTransaction();  
     try {  
       transaction.begin();  
       em.persist(employee);  
       transaction.commit();  
     }catch (Exception e){  
       if(transaction !=null && transaction.isActive())  
         transaction.rollback();  
     }  
   }  
   public void update(Employee employee){  
     EntityTransaction transaction = em.getTransaction();  
     try {  
       if(findById(employee.getId())!=null) {  
         transaction.begin();  
         em.merge(employee);  
         transaction.commit();  
       }  
     }catch (Exception e){  
       if(transaction !=null && transaction.isActive())  
         transaction.rollback();  
     }  
   }  
   public void delete(Employee employee){  
     EntityTransaction transaction = em.getTransaction();  
     try {  
       if(findById(employee.getId())!=null) {  
         transaction.begin();  
         em.remove(employee);  
         transaction.commit();  
       }  
     }catch (Exception e){  
       if(transaction !=null && transaction.isActive())  
         transaction.rollback();  
     }  
   }  
   public void deleteById(Integer id){  
     EntityTransaction transaction = em.getTransaction();  
     try {  
       Employee find = findById(id);  
       if(find != null) {  
         transaction.begin();  
         em.remove(find);  
         transaction.commit();  
       }  
     }catch (Exception e){  
       if(transaction !=null && transaction.isActive())  
         transaction.rollback();  
     }  
   }  
   public Employee findById(Integer id) {  
     try {  
       return em.find(Employee.class, id);  
     } catch (Exception ex) {  
       System.out.println("Could not find Employee with id: " + id + "; " + ex.getMessage());  
     }  
     return null;  
   }  
   public EntityManager getEntityManager() {  
     return em;  
   }  
 }  

Create Test class untuk mencoba proses CRUD di dao.
 public class EmployeeDaoTest {  
   private EmployeeDao employeeDao = new EmployeeDao();  
   @Test  
   public void testInsert(){  
     Employee employeeFirst = new Employee();  
     employeeFirst.setFirstname("Andri");  
     employeeFirst.setLastname("Sasuke");  
     employeeFirst.setPhone("0817777");  
     Employee employeeSecond = new Employee();  
     employeeSecond.setFirstname("Budi");  
     employeeSecond.setLastname("Ini");  
     employeeSecond.setPhone("081888");  
     employeeDao.save(employeeFirst);  
     employeeDao.save(employeeSecond);  
     Assert.assertTrue(employeeFirst.getId()!=null && employeeSecond.getId()!=null);  
   }  
   ………..  
 }  

Masuk mongoDB client,  dapat dilihat data yang kita insert masuk.
Dengan perintah : $ db.Employee.find()


Data formatnya JSON. Kalau di MongoDB table dianggap menjadi sebuah Collection da nisi datanya formatnya JSON.
Untuk spesifikasi lebih lanjut tentang MongoDB bisa diliat di sini.

Untuk proses select query saya masih belum menemukan caranya. Jika digunakan query JP-QL ternyata masih error. Kalo dibaca baca di documentasinya mungkin bisa menggunakan Hibernate Search.

Source code tutorial ini bisa dilihat di sini : https://github.com/andrisasuke/sample-hibernate-ogm-mongoDB

Mungkin kedepannya tutorial ini bisa dilengkapi dengan Spring atau Spring MVC

Selamat mencoba dan maaf atas kekurangannya. J