-
Notifications
You must be signed in to change notification settings - Fork 92
Quick Reference
Let's consider the following entity for all the below examples:
@Entity
public class User
{
@Id
private Long userId;
@Column
private String firstname;
@Column
private String lastname;
@Column
private Counter tweetCount;
public User(){}
public User(Long userId, String firstname, String lastname){...}
public User(Long userId, String firstname, String lastname, Counter tweetCount){...}
}
## Persisting a transient entity
em.persist(new User(10L,"John","DOE"));
or
em.merge(new User(10L,"John","DOE"));
Warning! Theorically nothing prevents you from persisting twice different users with the same primary key. In this case, all data from previous user will be wiped out and data from new user inserted.
Achilles persist()
doest not work like an upsert.
The CQL implementation achieves it by a single INSERT statement, null values from the entity will be translated into column removal by the Cassandra engine. The Thrift implementation removes first the whole row before inserting new data, which is less performant.
## Updating an entity ### Updating a managed entity
User user = em.find(User.class,10L);
user.setFirstname("Jonathan");
em.merge(user);
The drawback of the above update is the need to load the entity before updating it (the dreadful read-before-write pattern). However it has the benefit to guarantee you that the entity you are updating does really exist.
To avoid reading before update, use Direct Update as described below
User user = em.getReference(User.class,10L);
user.setFirstname("Jonathan");
em.merge(user);
Unlike find()
, getReference()
does not hit the database. Achilles simply instanciates a new User
object, sets the primary key and returns a proxified version of the entity to you. Upon call to merge()
, Achilles updates the firstname.
If you are sure that you entity does exist in Cassandra, prefer getReference()
to find()
## Removing an entity ### Removing a managed entity ```java User user = em.find(User.class,10L); em.remove(user); ``` ### Direct removal ```java em.removeById(User.class,10L); ```
## Finding clustered entities
For all examples in this section, let's consider the following clustered entity representing a tweet line
public class TweetLine
{
@EmbeddedId
private TweetKey id;
@Column
private String content;
public static class TweetKey
{
@Order(1)
private Long userId;
@Order(2)
LineType type;
@Order(3)
UUID tweetId;
}
public static enum LineType
{ USERLINE, TIMELINE, FAVORITELINE, MENTIONLINE}
}
Get the last 10 tweets from timeline, starting from tweet with lastUUID
List<TweetLine> tweets = em.sliceQuery(TweetLine.class)
.partitionKey(10L)
.fromClusterings(LineType.TIMELINE,lastUUID)
.toClusterings(LineType.TIMELINE)
.orderind(OrderingMode.DESCENDING)
.limit(10)
.get();
Same as above but using TweetKey
instead of clustering components
List<TweetLine> tweets = em.sliceQuery(TweetLine.class)
.fromEmbededId(new TweetKey(10L,LineType.TIMELINE,lastUUID))
.toClusterings(new TweetKey(10L,LineType.TIMELINE))
.orderind(OrderingMode.DESCENDING)
.limit(10)
.get();
Fetch all timeline tweets by batch of 100 tweets
Iterator<TweetLine> iterator = em.sliceQuery(TweetLine.class)
.partitionKey(10L)
.fromClusterings(LineType.TIMELINE,lastUUID)
.toClusterings(LineType.TIMELINE)
.orderind(OrderingMode.DESCENDING)
.iterator(100);
while(iterator.hasNext())
{
TweetLine timelineTweet = iterator.next();
...
}
Removing all timeline tweets
em.sliceQuery(TweetLine.class)
.partitionKey(10L)
.fromClusterings(LineType.TIMELINE)
.toClusterings(LineType.TIMELINE)
.remove();
Right now, due some technical limitation on the protocol side (internally it's feasible) it is not possible to perform range deletion. This limitation may be lifted in a near future when the protocol (native or Thrift) will support range deletion.
## Querying Cassandra ### Native query ```java List> rows = em.nativeQuery("SELECT firstname,lastname FROM user LIMIT 100");
for(Map<String,Object> row : rows)
{
String firstname = row.get("firstname");
String lastname = row.get("lastname");
...
}
Please note that the returned Map structure is indeed a `LinkedHashMap` which preserves the insertion order, which is the order of the columns declared in the query string (here _firstname_ then _lastname_ )
### Typed query
```java
List<User> users = em.typedQuery(User.class,"SELECT userId,firstname,lastname FROM user LIMIT 100");
for(User user : user)
{
...
}
Please note that the Typed Query returned managed instanced of the entities. Thus the primary key/compound primary keys/select * should be present in the query string.
List<User> users = em.typedQuery(User.class,"SELECT firstname,lastname FROM user LIMIT 100");
for(User user : user)
{
...
}
Similar to Typed Query, except that the resuls are transient entities. Consequently the restriction on mandatory primary key columns in the query string is lifted.
## Working with consistency ### Defining consistency statically
@Entity
@Consistency(read=ConsistecyLevel.ONE,write=ConsistencyLevel.QUORUM)
public class User
{
...
}
Write consistency
em.persist(new User(10L,"John","DOE"), OptionsBuilder.withConsistency(ConsistencyLevel.QUORUM));
or
em.merge(new User(10L,"John","DOE"),OptionsBuilder.withConsistency(ConsistencyLevel.QUORUM));
**Read consistency** ```java User user = em.find(User.class,10L,OptionsBuilder.withConsistency(ConsistencyLevel.ALL)); ```
or
User user = em.getReference(User.class,10L,OptionsBuilder.withConsistency(ConsistencyLevel.ALL));
The default consistency level is ONE when not set
Check [OptionsBuilder] for more details on available settings.
## Working with TTL ### Setting TTL on an entity ```java em.persist(new User(10L,"John","DOE"), OptionsBuilder.withTtl(150)); // Expire in 150 secs ```
or
em.merge(new User(10L,"John","DOE"),OptionsBuilder.withTtl(150)); // Expire in 150 secs
User user = em.getReference(User.class,10L);
user.setFirstname("temporary firstname");
/* Firstname value will expire in 150 secs,
* leaving the user with only userId and
* lastname
*/
em.merge(user,OptionsBuilder.withTtl(150));
Please notice the usage of getReference()
to save a read from Cassandra
Check [OptionsBuilder] for more details on available settings.
## Working with Timestamp ### Setting Timestamp on an entity ```java // Set timestamp value on the all fields of User entity em.persist(new User(10L,"John","DOE"), OptionsBuilder.withTimestamp(1357949499999L)); ```
or
// Set timestamp value on the all fields of User entity
em.merge(new User(10L,"John","DOE"),OptionsBuilder.withTimestamp(1357949499999L));
User user = em.getReference(User.class,10L);
user.setFirstname("temporary firstname");
/* Only firstname value will have timestamp set
* to 1357949499999L
*/
em.merge(user,OptionsBuilder.withTimestamp(1357949499999L));
Check [OptionsBuilder] for more details on available settings.
## Setting multiple options Of course it is possible to specify the TTL value, timestamp and/or consistency level at the same time:
em.persist(new User(10L,"John","DOE"), OptionsBuilder
.withConsistency(ALL)
.ttl(10)
.timestamp(1357949499999L));
or
em.merge(new User(10L,"John","DOE"), OptionsBuilder
.withConsistency(ALL)
.ttl(10)
.timestamp(1357949499999L));
Check [OptionsBuilder] for more details on available settings.
## Using counter type ### Persisting new counter value
// Creating new user John DOE with 13 tweets
em.persist(new User(10L,"John","DOE",CounterBuilder.incr(13L)));
User user = em.find(User.class,10L);
// Increment tweet count by 2
user.getTweetCount().incr(2L);
User user = em.getReference(User.class,10L);
// Increment tweet count by 2
user.getTweetCount().incr(2L);
Again, direct update using getReference()
is much more performant than the find()
version
User user = em.getReference(User.class,10L);
// Increment tweet count by 2 with consistency ALL
user.getTweetCount().incr(2L,ConsistencyLevel.ALL);
## Unwrapping entities ```java User user = em.find(User.class,10L);
// Transient instance of User entity
User transient = em.unwrap(user);
The `unwrap()` method also accept `List` or `Set` of entities as argument
[OptionsBuilder]: https://github.com/doanduyhai/Achilles/wiki/Achilles-Custom-Types#optionsbuilder
-
Bootstraping Achilles at runtime
- Runtime Configuration Parameters
-
Manager
-
Consistency Level
-
Cassandra Options at runtime
-
Lightweight Transaction (LWT)
-
JSON Serialization
-
Interceptors
-
Bean Validation (JSR-303)