There are about millions of rows of data that need to be written to Cassandra.I have tried the following methods:
The first: According to the reference code given by Datastax java-driver or python-driver on GitHub, my code is similar to:
// The following code is fixed, and this part will be omitted later.
String cassandraHost = "******";
String keyspace = "******";
String table = "******";
String insertCqlStr = " insert into " + keyspace + "." + table +"( "
+ "id,date,value)"
+ " values ( ?, ?, ?) ;";
CqlSession session = CqlSession.builder()
.addContactPoint(new InetSocketAddress(cassandraHost, 9042))
.withLocalDatacenter("datacenter1")
.withKeyspace(CqlIdentifier.fromCql(keyspace))
.build();
PreparedStatement preparedStatement = session.prepare(insertCqlStr);
// The code below is changed, or just what I think it is.
for(List<String> row: rows){
session.execute(
preparedInsertStatement.bind(row.get(0),
row.get(1), row.get(2))
.setConsistencyLevel(ConsistencyLevel.ANY));
}
session.close();
This code works fine, but it's just too inefficient to write for me to accept.So I tried the asynchronous API provided by the driver, and the code is almost the same as the above code:
for(List<String> row: rows){
session.executeAsync(
preparedInsertStatement.bind(row.get(0),
row.get(1), row.get(2))
.setConsistencyLevel(ConsistencyLevel.ANY));
}
session.close();
Please excuse my lack of asynchronous programming experience for being so rude. It works, but it has a fatal problem, I found that it does not write all the data into the database. I would like to know the correct usage for calling an async API.
Also, I tried the relevant methods of the BatchStatement provided by the driver. I know this method is officially deprecated to improve performance and it has many limitations. For example, as far as I know, the number of statements in a batch cannot exceed 65535, and in the default configuration, the data length warning limit of batch is 5kb, and the error limit is 50kb. But I kept the number of statements below 65535 and modified the above default configuration:
List<BoundStatement> boundStatements = new ArrayList<>();
Integer count = 0;
BatchStatement batchStatement = BatchStatement.newInstance(BatchType.UNLOGGED);
for (List<String> row : rows){
// The actual code here is looping multiple times instead of exiting directly.
if(count >= 65535){
break;
}
BoundStatement boundStatement = preparedStatement.bind(row.get(0),
row.get(1), row.get(2));
boundStatements.add(boundStatement);
count += 1;
}
BatchStatement batch = batchStatement.addAll(boundStatements);
session.execute(batch.setConsistencyLevel(ConsistencyLevel.ANY));
// session.executeAsync(batch.setConsistencyLevel().ANY);
session.close();
It also works. And it is actually more efficient than asynchronous APIs, and using synchronous interfaces can ensure data integrity. If the asynchronous API is used to execute BatchStatement here, the incomplete data mentioned above will also occur. But this method still doesn't meet my requirements, I need to execute it with multithreading. When I execute multiple threads it gives error: Caused by: com.datastax.oss.driver.api.core.DriverTimeoutException: Query timed out after PT2S
Summary: I've tried both synchronous and asynchronous writes and Batch related methods, and there are some issues that I can't accept. I now need to know how to properly use the async API to not lose data, and why I'm wrong. As for the BatchStatement related methods, I don't expect it to work, it would be great if you could give me a workable suggestion. Thank you!