Upgrade guide
The purpose of this guide is to detail changes made by successive versions of the Java driver.
3.6.0
ConsistencyLevel.LOCAL_SERIAL.isDCLocal()now returns true. In driver code,isDCLocal()is only used when evaluating a Statement’s ConsistencyLevel (which does not include Serial CLs), but as a matter of correctness this was updated.ReadFailureExceptionandWriteFailureExceptionare now surfaced toRetryPolicy.onRequestError. Consider updating customRetryPolicyimplementations to account for this. In the general case, we recommend usingRetryDecision.rethrow(), see JAVA-1944.
3.5.0
-
The
DowngradingConsistencyRetryPolicyis now deprecated, see JAVA-1752. It will also be removed in the next major release of the driver (4.0.0), see JAVA-1376.The main motivation is the agreement that this policy’s behavior should be the application’s concern, not the driver’s.
We recognize that there are use cases where downgrading is good – for instance, a dashboard application would present the latest information by reading at QUORUM, but it’s acceptable for it to display stale information by reading at ONE sometimes.
But APIs provided by the driver should instead encourage idiomatic use of a distributed system like Apache Cassandra, and a downgrading policy works against this. It suggests that an anti-pattern such as “try to read at QUORUM, but fall back to ONE if that fails” is a good idea in general use cases, when in reality it provides no better consistency guarantees than working directly at ONE, but with higher latencies.
We therefore urge users to carefully choose upfront the consistency level that works best for their use cases, and should they decide that the downgrading behavior of
DowngradingConsistencyRetryPolicyremains a good fit for certain use cases, they will now have to implement this logic themselves, either at application level, or alternatively at driver level, by rolling out their own downgrading retry policy.To help users migrate existing applications that rely on
DowngradingConsistencyRetryPolicy, see this online example that illustrates how to implement a downgrading logic at application level. -
The
TokenAwarePolicynow has a new constructor that takes aReplicaOrderingargument, see JAVA-1448.One of the advantages of this feature is the new
NEUTRALordering strategy, which honors its child policy’s ordering, i.e., replicas are returned in the same relative order as in the child policy’s query plan.For example, if the child policy returns the plan [A, B, C, D], and the replicas for the query being routed are [D, A, B], then the token aware policy would return the plan [A, B, D, C].
As a consequence, the constructor taking a boolean parameter
shuffleReplicasis now deprecated and will be removed in the next major release.
3.4.0
QueryBuilder methods in, lt, lte, eq, gt, and gte now accept
Iterable as input rather than just List. This should have no impact unless
you were accessing these methods using reflection in which case you need to
account for these new parameter types.
3.3.1
Speculative executions can now be scheduled without delay: if
SpeculativeExecutionPlan.nextExecution() returns 0, the next execution will be fired immediately.
This allows aggressive policies that hit multiple replicas right away, in order to get the fastest
response possible. Note that this may break existing policies that used 0 to mean “no execution”;
make sure you use a negative value instead.
3.2.0
The SSLOptions interface is now deprecated in favor of
RemoteEndpointAwareSSLOptions.
Similarly, the two existing implementations of that interface,
JdkSSLOptions and NettySSLOptions,
are now deprecated in favor of RemoteEndpointAwareJdkSSLOptions
and RemoteEndpointAwareNettySSLOptions respectively (see
JAVA-1364).
In 3.1.0, the driver would log a warning the first time it would skip a retry for a non-idempotent request; this warning has now been removed as users should now have adjusted their applications accordingly.
The caseSensitive field on @Column and @Field annotation now only
applies to the name field on the annotation and not the name of the
variable / method itself. If you were previously depending on the
name of the field, you should add a name field to the annotation,
i.e.: @Column(name="userName", caseSensitive=true).
3.1.0
This version introduces an important change in the default retry behavior: statements that are not idempotent are not always retried automatically anymore.
Prior to 2.1.10, idempotence was not considered for retries. This exposed applications to the risk of applying a non-idempotent statement twice (counter increment, list append…), or to more subtle bugs with lightweight transactions (see JAVA-819).
In 2.1.10 / 3.0.x, we introduced IdempotenceAwareRetryPolicy, which considers the Statement#isIdempotent() in the
retry decision process. However, for consistency with previous versions, this policy was not enabled by default (in
particular because statements are non-idempotent by default, and we didn’t want applications to suddenly stop retrying
queries that were retried before).
In 3.1.0, the default is now to not retry after a write timeout or request error if the statement is not idempotent.
This is handled internally, the retry policy methods are not even invoked in those cases (and therefore
IdempotenceAwareRetryPolicy has been deprecated). See the manual section about retries for more
information.
In practice, here’s what upgrading to 3.1.0 means for you:
- if you were already handling idempotence in your application, there won’t be any change, but you can stop wrapping
your retry policy with
IdempotenceAwareRetryPolicy; - otherwise, you might want to review how your code positions the
setIdempotentflag on statements. In most cases the driver can’t compute in automatically (because it doesn’t parse query strings), so it takes a conservative approach and sets it tofalseby default. If you know the query is idempotent, you should set it totruemanually. See the query idempotence section of the manual.
The driver logs a warning the first time it ignores a non-idempotent request; this warning will be removed in version 3.2.0.
3.0.4
The connection pool is now fully non-blocking (JAVA-893), which greatly improves asynchronous programming:
-
Session.executeAsyncwon’t ever block the user thread anymore; - you can now safely run async queries on a session connected to a keyspace.
This new implementation brings a couple of changes:
- pool saturation is no longer handled by a timeout, but instead by a bounded queue. As a consequence,
PoolingOptions.setPoolTimeoutMillishas been deprecated, and replaced bysetMaxQueueSize; - a saturated pool will now throw
BusyPoolExceptioninstead ofTimeoutException(note that this exception is not rethrown directly to the client, but wrapped inNoHostAvailableException.getErrors()).
3.0.0
This version brings parity with Cassandra 2.2 and 3.0.
It is not binary compatible with the driver’s 2.1 branch. The main changes were introduced by the custom codecs feature (see below). We’ve also seized the opportunity to remove code that was deprecated in 2.1.
- The default consistency level in
QueryOptionsis nowLOCAL_ONE. -
Custom codecs (JAVA-721) introduce several breaking changes and also modify a few runtime behaviors.
Here is a detailed list of breaking API changes:
-
TypeCodecwas package-private before and is now public. -
DataTypehas no more references toTypeCodec, so methods that dealt with serialization and deserialization of data types have been removed:ByteBuffer serialize(Object value, ProtocolVersion protocolVersion)ByteBuffer serializeValue(Object value, ProtocolVersion protocolVersion)Object deserialize(ByteBuffer bytes, ProtocolVersion protocolVersion)Object deserialize(ByteBuffer bytes, int protocolVersion)Object parse(String value)String format(Object value)Class<?> asJavaClass()
These methods must now be invoked on
TypeCodecdirectly. To resolve theTypeCodecinstance for a particular data type, useCodecRegistry#codecFor. -
GettableByIndexData(affectsRow,BoundStatement,TupleValueandUDTValue). The following public methods were added:<T> T get(int i, Class<T> targetClass)<T> T get(int i, TypeToken<T> targetType)<T> T get(int i, TypeCodec<T> codec)
-
GettableByNameData(affectsRow,BoundStatementandUDTValue). The following public methods were added:<T> T get(String name, Class<T> targetClass)<T> T get(String name, TypeToken<T> targetType)<T> T get(String name, TypeCodec<T> codec)
-
SettableByIndexData(affectsRow,BoundStatement,TupleValueandUDTValue). The following public methods were added:<V> T set(int i, V v, Class<V> targetClass)<V> T set(int i, V v, TypeToken<V> targetType)<V> T set(int i, V v, TypeCodec<V> codec)
-
SettableByNameData(affectsRow,BoundStatementandUDTValue). The following public methods were added:<V> T set(String name, V v, Class<V> targetClass)<V> T set(String name, V v, TypeToken<V> targetType)<V> T set(String name, V v, TypeCodec<V> codec)
-
Statement. The following public methods were modified:-
getRoutingKey(ProtocolVersion, CodecRegistry): both parameters added.
-
-
RegularStatement. The following public methods were modified:-
getValues(ProtocolVersion, CodecRegistry): second parameter added. -
getQueryString(CodecRegistry)andhasValues(CodecRegistry): parameter added. No-arg versions are still present and use the default codec registry; refer to the Javadocs for guidance on which version to use.
-
-
PreparedStatement. The following public method was added:-
CodecRegistry getCodecRegistry().
-
-
TupleType. The following public method was deleted:-
TupleType of(DataType... types); users should now useMetadata.newTupleType(DataType...).
-
The driver runtime behavior changes in the following situations:
- By default, the driver now returns mutable, non thread-safe instances for CQL collection types;
This affects methods
getList,getSet,getMap,getObjectandgetfor all instances ofGettableByIndexDataandGettableByNameData(Row,BoundStatement,TupleValueandUDTValue) -
RuntimeExceptions thrown during serialization or deserialization might not be the same ones as before, due to the newly-introducedCodecNotFoundExceptionand to the dynamic nature of codec search introduced by JAVA-721. -
TypeCodec.format(Object)now returns the CQL keyword"NULL"instead of anullreference fornullinputs.
-
The driver now depends on Guava 16.0.1 (instead of 14.0.1). This update has been mainly motivated by Guava’s Issue #1635, which affects
TypeToken, and hence allTypeCodecimplementations handling parameterized types.-
UDTMapper(the type previously used to convert@UDT-annotated classes to their CQL counterpart) was removed, as well as the corresponding methodMappingManager#udtMapper.The mapper now uses custom codecs to convert UDTs. See more explanations here.
-
All methods that took the protocol version as an
intor assumed a default version have been removed (they were already deprecated in 2.1):AbstractGettableData(int)Cluster.Builder#withProtocolVersion(int)- in
ProtocolOptions:-
NEWEST_SUPPORTED_PROTOCOL_VERSION(replaced byProtocolVersion#NEWEST_SUPPORTED) int getProtocolVersion()
-
There are now variants of these methods using the
ProtocolVersionenum. In addition,ProtocolOptions#getProtocolVersionEnumhas been renamed toProtocolOptions#getProtocolVersion. -
All methods related to the “suspected” host state have been removed (they had been deprecated in 2.1.6 when the suspicion mechanism was removed):
-
Host.StateListener#onSuspected()(was inherited byLoadBalancingPolicy) Host#getInitialReconnectionAttemptFuture()
-
PoolingOptions#setMinSimultaneousRequestsPerConnectionThreshold(HostDistance, int)has been removed. The new connection pool resizing algorithm introduced by JAVA-419 does not need this threshold anymore.-
AddressTranslaterhas been renamed toAddressTranslator. All related methods and classes have also been renamed.In addition, the
close()method has been pulled up intoAddressTranslator, andCloseableAddressTranslatorhas been removed. Existing third-partyAddressTranslatorimplementations only need to add an emptyclose()method. The
close()method has been pulled up intoLoadBalancingPolicy, andCloseableLoadBalancingPolicyhas been removed. Existing third-partyLoadBalancingPolicyimplementations only need to add an emptyclose()method.-
All pluggable components now have callbacks to detect when they get associated with a
Clusterinstance:-
ReconnectionPolicy,RetryPolicy,AddressTranslator, andTimestampGenerator:init(Cluster)close()
-
Host.StateListenerandLatencyTracker:onRegister(Cluster)onUnregister(Cluster)
This gives these components the opportunity to perform initialization / cleanup tasks. Existing third-party implementations only need to add empty methods.
-
LoadBalancingPolicydoes not extendHost.StateListeneranymore: callback methods (onUp,onDown, etc.) have been duplicated. This is unlikely to affect clients.Client-side timestamp generation is now the default (provided that native protocol v3 or higher is in use). The generator used is
AtomicMonotonicTimestampGenerator.If a DNS name resolves to multiple A-records,
Cluster.Builder#addContactPoint(String)will now use all of these addresses as contact points. This gives you the possibility of maintaining contact points in DNS configuration, and having a single, static contact point in your Java code.-
The following methods were added for Custom payloads:
- in
PreparedStatement:getIncomingPayload(),getOutgoingPayload()andsetOutgoingPayload(Map<String,ByteBuffer>) AbstractSession#prepareAsync(String, Map<String,ByteBuffer>)
Also, note that
AbstractSession#prepareAsync(Statement)does not callAbstractSession#prepareAsync(String)anymore, they now both delegate to a protected method.This breaks binary compatibility for these two classes; if you have custom implementations, you will have to adapt them accordingly.
- in
-
Getters and setters have been added to “data-container” classes for new CQL types:
-
getByte/setBytefor theTINYINTtype -
getShort/setShortfor theSMALLINTtype -
getTime/setTimefor theTIMEtype -
getDate/setDatefor theDATEtype
The methods for the
TIMESTAMPCQL type have been renamed togetTimestampandsetTimestamp.This affects
Row,BoundStatement,TupleValueandUDTValue. -
-
New exception types have been added to handle additional server-side errors introduced in Cassandra 2.2:
ReadFailureExceptionWriteFailureExceptionFunctionExecutionException
This is not a breaking change since all driver exceptions are unchecked; but clients might decide to handle these errors in a specific way.
In addition,
QueryTimeoutExceptionhas been renamed toQueryExecutionException(this is an intermediary class in our exception hierarchy, it now has new child classes that are not related to timeouts). ResultSet#fetchMoreResults()now returns aListenableFuture<ResultSet>. This makes the API more friendly if you chain transformations on an async query to process all pages (seeAsyncResultSetTestin the sources for an example).Frozenannotations in the mapper are no longer checked at runtime (see JAVA-843 for more explanations). So they become purely informational at this stage. However it is a good idea to keep using these annotations and make sure they match the schema, in anticipation for the schema generation features that will be added in a future version.AsyncInitSessionhas been removed,initAsync()is now part of theSessioninterface (the only purpose of the extra interface was to preserve binary compatibility on the 2.1 branch).TableMetadata.Optionshas been made a top-level class and renamed toTableOptionsMetadata. It is now also used byMaterializedViewMetadata.-
The mapper annotation
@Enumeratedhas been removed, users should now use the newly-introduceddriver-extrasmodule to get automatic enum-to-CQL mappings. Two new codecs provide the same functionality:EnumOrdinalCodecandEnumNameCodec:enum Foo {...} enum Bar {...} // register the appropriate codecs CodecRegistry.DEFAULT_INSTANCE .register(new EnumOrdinalCodec<Foo>(Foo.class)) .register(new EnumNameCodec<Bar>(Bar.class)) // the following mappings are handled out-of-the-box @Table public class MyPojo { private Foo foo; private List<Bar> bars; ... } The interface
IdempotenceAwarePreparedStatementhas been removed and now thePreparedStatementinterface exposes 2 new methods,setIdempotent(Boolean)andisIdempotent().RetryPolicyandExtendedRetryPolicy(introduced in 2.1.10) were merged together; as a consequence,RetryPolicynow has one more method:onRequestError; see JAVA-819 for more information. Furthermore,FallthroughRetryPolicynow returnsRetryDecision.rethrow()whenonRequestErroris called.DseAuthProviderhas been deprecated and is now replaced byDseGSSAPIAuthProviderfor Kerberos authentication.DsePlainTextAuthProviderhas been introduced to handle plain text authentication with theDseAuthenticator.The constructor of
DCAwareRoundRobinPolicyis not accessible anymore. You should useDCAwareRoundRobinPolicy#builder()to create new instances.ColumnMetadata.getTable()has been renamed toColumnMetadata.getParent(). Also, its return type is nowAbstractTableMetadatawhich can be either aTableMetadataobject or aMaterializedViewMetadataobject. This change is motivated by the fact that a column can now belong to a table or a materialized view.ColumnMetadata.getIndex()has been removed. This is due to the fact that secondary indexes have been completely redesigned in Cassandra 3.0, and the former one-to-one relationship between a column and its index has been replaced with a one-to-many relationship between a table and its indexes. This is reflected in the driver’s API by the new methodsTableMetadata.getIndexes()andTableMetadata.getIndex(String name). See CASSANDRA-9459 and and JAVA-1008 for more details. Unfortunately, there is no easy way to recover the functionality provided by the deleted method, even for Cassandra versions <= 3.0.IndexMetadatais now a top-level class and its structure has been deeply modified. Again, this is due to the fact that secondary indexes have been completely redesigned in Cassandra 3.0.SSLOptionshas been refactored to allow the option to choose between JDK and Netty-based SSL implementations. See JAVA-841 and the SSL documentation for more details.
2.1.8
2.1.8 is binary-compatible with 2.1.7 but introduces a small change in the driver’s behavior:
- The list of contact points provided at startup is now shuffled before trying
to open the control connection, so that multiple clients with the same contact
points don’t all pick the same control host. As a result, you can’t assume that
the driver will try contact points in a deterministic order. In particular, if
you use the
DCAwareRoundRobinPolicywithout specifying a primary datacenter name, make sure that you only provide local hosts as contact points.
2.1.7
This version brings a few changes in the driver’s behavior; none of them break binary compatibility.
The
DefaultRetryPolicy‘s behaviour has changed in the case of an Unavailable exception received from a request. The new behaviour will cause the driver to process a Retry on a different node at most once, otherwise an exception will be thrown. This change makes sense in the case where the node tried initially for the request happens to be isolated from the rest of the cluster (e.g. because of a network partition) but can still answer to the client normally. In this case, trying another node has a chance of success. The previous behaviour was to always throw an exception.-
The following properties in
PoolingOptionswere renamed:-
MaxSimultaneousRequestsPerConnectionThresholdtoNewConnectionThreshold -
MaxSimultaneousRequestsPerHostThresholdtoMaxRequestsPerConnection
The old getters/setters were deprecated, but they delegate to the new ones.
Also, note that the connection pool for protocol v3 can now be configured to use multiple connections. See this page for more information.
-
-
MappingManager(Session)will now force the initialization of theSessionif needed. This is a change from 2.1.6, where if you gave it an uninitialized session (created withCluster#newSession()instead ofCluster#connect()), it would only get initialized on the first request.If this is a problem for you,
MappingManager(Session, ProtocolVersion)preserves the previous behavior (see the API docs for more details). A
BuiltStatementis now considered non-idempotent whenever afcall()orraw()is used to build a value to be inserted in the database. If you know that the CQL functions or expressions are safe, usesetIdempotent(true)on the statement.
2.1.6
See 2.0.10.
2.1.2
2.1.2 brings important internal changes with native protocol v3 support, but the impact on the public API has been kept as low as possible.
User API Changes
- The native protocol version is now modelled as an enum:
ProtocolVersion. Most public methods that take it as an argument have a backward-compatible version that takes anint(the exception beingRegularStatement, described below). For new code, prefer the enum version.
Internal API Changes
RegularStatement.getValuesnow takes the protocol version as aProtocolVersioninstead of anint. This is transparent for callers since there is a backward-compatible alternative, but if you happened to extend the class you’ll need to update your implementation.BatchStatement.setSerialConsistencyLevelnow returnsBatchStatementinstead ofStatement. Again, this only matters if you extended this class (if so, it might be a good idea to also have a covariant return in your child class).The constructor of
UnsupportedFeatureExceptionnow takes aProtocolVersionas a parameter. This should impact few users, as there’s hardly any reason to build instances of that class from client code.
New features
These features are only active when the native protocol v3 is in use.
The driver now uses a single connection per host (as opposed to a pool in 2.1.1). Most options in
PoolingOptionsare ignored, except for a new one calledmaxSimultaneousRequestsPerHostThreshold. See the class’s Javadocs for detailed explanations.You can now provide a default timestamp with each query (but it will be ignored if the CQL query string already contains a
USING TIMESTAMPclause). This can be done on a per-statement basis withStatement.setDefaultTimestamp, or automatically with aTimestampGeneratorspecified withCluster.Builder.withTimestampGenerator(two implementations are provided:ThreadLocalMonotonicTimestampGeneratorandAtomicMonotonicTimestampGenerator). If you specify both, the statement’s timestamp takes precedence over the generator. By default, the driver has the same behavior as 2.1.1 (no generator, timestamps are assigned by Cassandra unlessUSING TIMESTAMPwas specified).BatchStatement.setSerialConsistencyLevelno longer throws an exception, it will honor the serial consistency level for the batch.
2.1.1
Internal API Changes
- The
ResultSetinterface has a newwasApplied()method. This will only affect clients that provide their own implementation of this interface.
2.1.0
User API Changes
The
getCachingmethod ofTableMetadata#Optionsnow returns aMapto account for changes to Cassandra 2.1. Also, thegetIndexIntervalmethod now returns anIntegerinstead of anintwhich will benullwhen connected to Cassandra 2.1 nodes.BoundStatementvariables that have not been set explicitly will no longer default tonull. Instead, all variables must be bound explicitly, otherwise the execution of the statement will fail (this also applies to statements inside of aBatchStatement). For variables that map to a primitive Java type, a newsetToNullmethod has been added. We made this change because the driver might soon distinguish between unset and null variables, so we don’t want clients relying on the “leave unset to set tonull” behavior.
Internal API Changes
The changes listed in this section should normally not impact end users of the driver, but rather third-party frameworks and tools.
The
serializeanddeserializemethods inDataTypenow take an additional parameter: the protocol version. As explained in the javadoc, if unsure, the proper value to use for this parameter is the protocol version in use by the driver, i.e. the value returned bycluster.getConfiguration().getProtocolOptions().getProtocolVersion().The
parsemethod inDataTypenow returns a Java object, not aByteBuffer. The previous behavior can be obtained by calling theserializemethod on the returned object.The
getValuesmethod ofRegularStatementnow takes the protocol version as a parameter. As above, the proper value if unsure is almost surely the protocol version in use (cluster.getConfiguration().getProtocolOptions().getProtocolVersion()).
2.0.11
2.0.11 preserves binary compatibility with previous versions. There are a few changes in the driver’s behavior:
The
DefaultRetryPolicy’s behaviour has changed in the case of an Unavailable exception received from a request. The new behaviour will cause the driver to process a Retry on a different node at most once, otherwise an exception will be thrown. This change makes sense in the case where the node tried initially for the request happens to be isolated from the rest of the cluster (e.g. because of a network partition) but can still answer to the client normally. In this case, trying another node has a chance of success. The previous behaviour was to always throw an exception.A
BuiltStatementis now considered non-idempotent whenever afcall()orraw()is used to build a value to be inserted in the database. If you know that the CQL functions or expressions are safe, usesetIdempotent(true)on the statement.The list of contact points provided at startup is now shuffled before trying to open the control connection, so that multiple clients with the same contact points don’t all pick the same control host. As a result, you can’t assume that the driver will try contact points in a deterministic order. In particular, if you use the
DCAwareRoundRobinPolicywithout specifying a primary datacenter name, make sure that you only provide local hosts as contact points.
2.0.x to 2.0.10
We try to avoid breaking changes within a branch (2.0.x to 2.0.y), but 2.0.10 saw a lot of new features and internal improvements. There is one breaking change:
-
LatencyTracker#updatenow has a different signature and takes two new parameters: the statement that has been executed (never null), and the exception thrown while executing the query (or null, if the query executed successfully). Existing implementations of this interface, once upgraded to the new method signature, should continue to work as before.
The following might also be of interest:
SocketOptions#getTcpNoDelay()is now TRUE by default (it was previously undefined). This reflects the new behavior of Netty (which was upgraded from version 3.9.0 to 4.0.27):TCP_NODELAYis now turned on by default, instead of depending on the OS default like in previous versions.Netty is not shaded anymore in the default Maven artifact. However we publish a shaded artifact under a different classifier.
The internal initialization sequence of the Cluster object has been slightly changed: some fields that were previously initialized in the constructor are now set when the
init()method is called. In particular,Cluster#getMetrics()will returnnulluntil the cluster is initialized.
1.0 to 2.0
We used the opportunity of a major version bump to incorporate your feedback and improve the API, to fix a number of inconsistencies and remove cruft. Unfortunately this means there are some breaking changes, but the new API should be both simpler and more complete.
The following describes the changes for 2.0 that are breaking changes of the 1.0 API. For ease of use, we distinguish two categories of API changes: the “main” ones and the “other” ones.
The “main” API changes are the ones that are either likely to affect most upgraded apps or are incompatible changes that, even if minor, will not be detected at compile time. Upgraders are highly encouraged to check this list of “main” changes while upgrading their application to 2.0 (even though most applications are likely to be affected by only a handful of changes).
The “other” list is, well, other changes: those that are likely to affect a minor number of applications and will be detected by compile time errors anyway. It is ok to skip those initially and only come back to them if you have trouble compiling your application after an upgrade.
Main API changes
The
Queryclass has been renamed intoStatement(it was confusing to some that theBoundStatementwas not aStatement). To allow this, the oldStatementclass has been renamed toRegularStatement.The
ClusterandSessionshutdown API has changed. There is now acloseAsyncthat is asynchronous but returns aFutureon the completion of the shutdown process. There is also acloseshortcut that does the same but blocks. Also,closenow waits for ongoing queries to complete by default (but you can force the closing of all connections if you want to).NoHostAvailableException#getErrorsnow returns the full exception objects for each node instead of just a message. In other words, it returns aMap<InetAddress, Throwable>instead of aMap<InetAddress, String>.Statement#getConsistencyLevel(previouslyQuery#getConsistencyLevel, see first point) will now returnnullby default (instead ofCL.ONE), with the meaning of “use the default consistency level”. The default consistency level can now be configured through the newQueryOptionsobject in the clusterConfiguration.The
Metricsclass now uses the Codahale metrics library version 3 (version 2 was used previously). This new major version of the library has many API changes compared to its version 2 (see the release notes for details), which can thus impact consumers of the Metrics class. Furthermore, the defaultJmxReporternow includes a name specific to the cluster instance (to avoid conflicts when multiple Cluster instances are created in the same JVM). As a result, tools that were polling JMX info will have to be updated accordingly.The
QueryBuilder#inmethod now has the following special case: usingQueryBuilder.in(QueryBuilder.bindMarker())will generate the stringIN ?, notIN (?)as was the case in 1.0. The reasoning being that the former syntax, made valid by CASSANDRA-4210 is a lot more useful thanIN (?), as the latter can more simply use an equality. Note that if you really want to outputIN (?)with the query builder, you can useQueryBuilder.in(QueryBuilder.raw("?")).When binding values by name in
BoundStatement(i.e. using thesetX(String, X)methods), if more than one variable have the same name, then all values corresponding to that variable name are set instead of just the first occurrence.The
QueryBuilder#rawmethod does not automatically add quotes anymore, but rather output its result without any change (as the raw name implies). This means for instance thateq("x", raw(foo))will outputx = foo, notx = 'foo'(you don’t need the raw method to output the latter string).The
QueryBuilderwill now sometimes use the new ability to send value as bytes instead of serializing everything to string. In general the QueryBuilder will do the right thing, but if you were calling thegetQueryString()method on a Statement created with a QueryBuilder (for other reasons than to prepare a query) then the returned string may contain bind markers in place of some of the values provided (and in that case,getValues()will contain the values corresponding to those markers). If need be, it is possible to force the old behavior by using the newsetForceNoValues()method.
Other API Changes
Creating a Cluster instance (through
Cluster#buildFromor theCluster.Builder#buildmethod) does not create any connection right away anymore (and thus cannot throw aNoHostAvailableExceptionor anAuthenticationException). Instead, the initial contact points are checked the first time a call toCluster#connectis done. If for some reason you want to emulate the previous behavior, you can use the new methodCluster#init:Cluster.builder().build()in 1.0 is equivalent toCluster.builder().build().init()in 2.0.Methods from
Metadata,KeyspaceMetadataandTableMetadatanow use by default case insensitive identifiers (for keyspace, table and column names in parameter). You can double-quote an identifier if you want it to be a case sensitive one (as you would do in CQL) and there is aMetadata.quotehelper method for that.The
TableMetadata#getClusteringKeymethod has been renamedTableMetadata#getClusteringColumnsto match the “official” vocabulary.The
UnavailableException#getConsistencymethod has been renamed toUnavailableException#getConsistencyLevelfor consistency with the method ofQueryTimeoutException.The
RegularStatementclass (ex-Statementclass, see above) must now implement two additional methods:RegularStatement#getKeyspaceandRegularStatement#getValues. If you had extended this class, you will have to implement those new methods, but both can return null if they are not useful in your case.The
Cluster.Initializerinterface should now implement 2 new methods:Cluster.Initializer#getInitialListeners(which can return an empty collection) andCluster.Initializer#getClusterName(which can return null).The
Metadata#getReplicasmethod now takes 2 arguments. On top of the partition key, you must now provide the keyspace too. The previous behavior was buggy: it’s impossible to properly return the full list of replica for a partition key without knowing the keyspace since replication may depend on the keyspace).The method
LoadBalancingPolicy#newQueryPlan()method now takes the currently logged keyspace as 2nd argument. This information is necessary to do proper token aware balancing (see preceding point).The
ResultSetFuture#setandResultSetFuture#setExceptionmethods have been removed (from the public API at least). They were never meant to be exposed publicly: aresultSetFutureis always set by the driver itself and should not be set manually.The deprecated since 1.0.2
Host.HealthMonitorclass has been removed. You will now need to useHost#isUpandCluster#registerif you were using that class.
Features available only with Cassandra 2.0
This section details the biggest additions to 2.0 API wise. It is not an exhaustive list of new features in 2.0.
-
The new
BatchStatementclass allows to group any type of insert Statements (BoundStatementorRegularStatement) for execution as a batch. For instance, you can do something like:List<String> values = ...; PreparedStatement ps = session.prepare("INSERT INTO myTable(value) VALUES (?)"); BatchStatement bs = new BatchStatement(); for (String value : values) bs.add(ps.bind(value)); session.execute(bs); -
SimpleStatementcan now take a list of values in addition to the query. This allows to do the equivalent of a prepare+execute but with only one round-trip to the server and without keeping the prepared statement after the execution.This is typically useful if a given query should be executed only once (i.e. you don’t want to prepare it) but you also don’t want to serialize all values into strings. Shortcut
Session#execute()andSession#executeAsync()methods are also provided so you that you can do:String imgName = ...; ByteBuffer imgBytes = ...; session.execute("INSERT INTO images(name, bytes) VALUES (?, ?)", imgName, imgBytes); -
SELECT queries are now “paged” under the hood. In other words, if a query yields a very large result, only the beginning of the
ResultSetwill be fetched initially, the rest being fetched “on-demand”. In practice, this means that:for (Row r : session.execute("SELECT * FROM mytable")) ... process r ...should not timeout or OOM the server anymore even if “mytable” contains a lot of data. In general paging should be transparent for the application (as in the example above), but the implementation provides a number of knobs to fine tune the behavior of that paging:
- the size of each “page” can be set per-query (
Statement#setFetchSize()) - the
ResultSetobject provides 2 methods to check the state of paging (ResultSet#getAvailableWithoutFetchingandResultSet#isFullyFetched) as well as a mean to force the pre-fetching of the next page (ResultSet#fetchMoreResults).
- the size of each “page” can be set per-query (