-
Notifications
You must be signed in to change notification settings - Fork 0
Kundera OracleNoSQL
OracleNoSQL is a distributed key-value database. Kundera supports OracleNoSQL (alongwith Redis, which is also a key-value database).
Kundera, being a JPA object-mapper, maps entity class instances with data storage structure provided in underlying database.
Below is a simplified depiction of entity class to key-value pair mapping mechanism adopted by Kundera: (This is a result of saving Person entity with personId, personName and age fields set to "1", "John Smith" and 32 respectively).
- Schema name defined in entity class is mapped to KV Store name.
- Table name and ID column value constitute major key.
- Rest of the column names are stored as minor keys.
- Value of columns are stored as byte array values.
All you have to do is to define persistence unit in persistence.xml file as shown below:
<persistence-unit name="oracle_nosql_pu">
<provider>com.impetus.kundera.KunderaPersistence</provider>
<properties>
<property name="kundera.nodes" value="localhost" />
<property name="kundera.port" value="5000" />
<property name="kundera.client.lookup.class"
value="com.impetus.client.oraclenosql.OracleNoSQLClientFactory" />
<property name="kundera.keyspace" value="HR_Store" />
<property name="kundera.dialect" value="kvstore" />
<property name="kundera.client" value="kvstore" />
<property name="kundera.cache.provider.class"
value="com.impetus.kundera.cache.ehcache.EhCacheProvider" />
<property name="kundera.cache.config.resource" value="/ehcache-test.xml" />
<property name="kundera.indexer.class"
value="com.impetus.client.oraclenosql.index.OracleNoSQLInvertedIndexer" />
</properties>
</persistence-unit>
You may visit here for detailed description of each property.
Insert, Find, Update and Remove operations are pure-JPA and are straightforward.
Person person = new Person();
person.setPersonId("1");
person.setPersonName("John Smith");
person.setAge(32);
EntityManagerFactory emf = Persistence.createEntityManagerFactory("oracle_nosql_pu");
EntityManager em = emf.createEntityManager();
//Insert data
em.persist(person);
em.clear(); //Clear cache before finding record
//Search for data
Person peronFound = em.find(Person.class, "1");
//Update data
person.setAge(33);
em.merge(person);
//Delete data
em.remove(person);
em.close();
emf.close();
Columns of embeddable objects are stored in a way similar to regular columns, with the exception that minor keys have two components: (1) Embedded column name, and (2) Column name in embeddable class.
Let's add an embeddable attribute to our Person class, persist person object and see how it's stored in OracleNoSQL.
@Entity
@Table(name = "PERSON", schema = "HR_Store@oracle_nosql_pu")
@IndexCollection(columns = {@Index(name = "userName") },{@Index(name = "age") })
public class Person
{
@Id
@Column(name = "PERSON_ID")
private String personId;
@Column(name = "PERSON_NAME")
private String personName;
@Column(name = "AGE")
private Integer age;
@Embedded
private Office office;
//Getters and setters
}
@Embeddable
public class Office
{
@Column
private int officeId;
@Column
private String companyName;
@Column
private String location;
//Getters and Setters
}
Here is how data will look like when person entity is persisted.
/PERSON/1/ - /PERSON_NAME ---> John Smith
/PERSON/1/ - /AGE ---> 32
/PERSON/1/ - /office/officeId ---> L1
/PERSON/1/ - /office/companyName ---> Impetus
/PERSON/1/ - /office/location ---> San Jose
When we set below property in persistence.xml, an inverted index is built while persisting data. This is done to facilitate searching of columns/ embedded columns using JPA queries (explained in next section):
<property name="kundera.indexer.class"
value="com.impetus.client.oraclenosql.index.OracleNoSQLInvertedIndexer" />
An illustration of inverted index built by Kundera is given below (Data is similar to Person object from the previous section):
/PERSON_idx/PERSON_NAME/John Smith/ - /1 ---> 1
/PERSON_idx/AGE/32/ - /1 ---> 1
/PERSON_idx/office.officeId/L1/ - /1 ---> 1
/PERSON_idx/office.companyName/Impetus/ - /1 ---> 1
/PERSON_idx/office.location/San Jose/ - /1 ---> 1
Exploiting inverted indexing (or even Lucene Indexing if set using "index.home.dir" property in persistence.xml), Kundera supports JPA queries. Here are some examples:
Query query = em.createQuery("Select p from Person p");
List<Person> persons = query.getResultList();
query = em.createQuery("Select p.age from Person p");
persons = query.getResultList();
query = em.createQuery("Select p from Person p where p.personName=:personName AND p.age=:age");
query.setParameter("personName", "John Smith");
query.setParameter("age", 32);
persons = query.getResultList();
query = em.createQuery("Select p from Person p where p.age>:min OR p.age<=:max");
query.setParameter("min", 10);
query.setParameter("max", 50);
persons = query.getResultList();
query = em.createQuery("Select p from Person p where p.personId between :min AND :max");
query.setParameter("min", 10);
query.setParameter("max", 50);
persons = query.getResultList();
query = em.createQuery("Select p from Person p where p.office.companyName=:companyName");
query.setParameter("companyName", "Impetus");
persons = query.getResultList();
query = em.createQuery("Delete from PersonEmbeddedKVStore p");
int deleteCount = query.executeUpdate();
OracleNoSQL supports reading/ writing of Large Objects LOBs such as audio and video files. Using Kundera, you can read/ write LOBs using attribute of type java.io.File in entity classes.
Here is an example:
@Entity
@Table(name = "USER_PROFILE", schema = "HR_Store@oracle_nosql_pu")
public class UserProfile
{
@Id
@Column(name = "USER_ID")
private int userId;
@Column(name = "USER_NAME")
private String userName;
@Column(name = "PROFILE_PICTURE")
private File profilePicture;
public UserProfile(int userId, String userName, File profilePicture)
{
super();
this.userId = userId;
this.userName = userName;
this.profilePicture = profilePicture;
}
//Getters and setters
}
LOBExample.java (Snippet)
//Insert user profile alongwith picture
File file = new File("/home/amresh/MyPhoto.jpg");
long fileSize = file.getTotalSpace();
UserProfile userProfile = new UserProfile(1, "Amresh", file);
em.persist(userProfile);
//Clear Cache
em.clear();
//Find user profile
UserProfile up = (UserProfile) em.find(UserProfile.class, 1);
File myPicture = up.getProfilePicture();
//Delete Profile
em.remove(userProfile);
Note: Before performing LOB operations, you can configure below parameters that are applied on all operations until em.close() is called. (In absence, default OracleNoSQL settings are applied).
em.setProperty("write.timeout", 10);
em.setProperty("durability", Durability.COMMIT_WRITE_NO_SYNC);
em.setProperty("time.unit", TimeUnit.SECONDS);
em.setProperty("consistency", Consistency.NONE_REQUIRED);
Here is a compilation of what is not supported currently, but we would like to see them in our kitty for Kundera-OracleNoSQL soon:
- Element Collections
- Composite Keys
- Primary Key Auto generation
- Schema Generation
- Native Queries
- Geospatial Persistence and Queries
Also Note:
- Although OracleNoSQL doesn't provide transaction management, Kundera supports JPA/ JTA transactions using its default implementation.
- Batch operations are supported for OracleNoSQL in Kundera. For details, see: Batch insert update.
- Please use the Oracle NoSQL jars from the Oracle NoSQL distribution at http://download.oracle.com/otn-pub/otn_software/nosql-database/kv-ce-2.0.26.zip. For the convenience of those who want to build Kundera from source we have additionally placed the jars at http://kundera.googlecode.com/svn/maven2/maven-missing-resources/.
- Polyglot Persistence of OracleNoSQL, as you may have guessed, works seamlessly with other databases supported by Kundera.