Cassandra:java客戶端操作
java客戶端介紹
Cassandra有眾多的JAVA客戶端,目前比較流程的都是不同公司開源的客戶端,如:Netfix的astyanax,datastax的java-driver,hector,以及Spring Data for Apache Cassandra。
本文使用datastax的java-driver作為連線cassandra的客戶端。
datastax的java-driver
介紹
是由DataStax公司,開源的用來操作Cassandra的工具包,官網:
https://docs.datastax.com/en/landing_page/doc/landing_page/current.html
在github的搜尋頁面點選 datastax/java-driver
原始碼地址:
在頁面上可以看到使用java-driver的簡單介紹,包含Maven依賴內容,環境相容要求。
可以看到需要jdk8或更版本,支援Cassandra2.1獲取更高版本
入門使用
引入相關依賴:
<!--cassandra 包--> <dependency> <groupId>com.datastax.cassandra</groupId> <artifactId>cassandra-driver-core</artifactId> <version>3.9.0</version> </dependency> <dependency> <groupId>com.datastax.cassandra</groupId> <artifactId>cassandra-driver-mapping</artifactId> <version>3.9.0</version> </dependency> <!--junit 測試--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency>
鍵空間操作
1.查詢鍵空間
Session session; @Before public void init() { String host = "192.168.1.43"; int port = 9042; //連線服務端,獲取會話 Cluster cluster = Cluster.builder() .addContactPoint(() -> new InetSocketAddress(host, port)) .build(); session = cluster.connect(); } /** * 查詢鍵空間 * @author wen.jie * @date 2022/3/16 15:07 */ @Test public void selectKeySpace() { List<KeyspaceMetadata> keyspaces = session.getCluster().getMetadata().getKeyspaces(); for (KeyspaceMetadata keyspace : keyspaces) { System.out.println(keyspace); } }
2.建立鍵空間
/**
* 建立鍵空間
* @author wen.jie
* @date 2022/3/16 15:08
*/
@Test
public void createKeySpace() {
//執行cql語句
//session.execute("CREATE KEYSPACE school_test WITH replication = {'class':'SimpleStrategy', 'replication_factor' : 3};");
//面向物件方式
HashMap<String, Object> map = new HashMap<>();
map.put("class", "SimpleStrategy");
map.put("replication_factor", 1);
KeyspaceOptions opts = SchemaBuilder.createKeyspace("school_test")
.ifNotExists()
.with()
.replication(map);
session.execute(opts);
}
效果:
3.刪除鍵空間
@Test
public void dropKeySpace() {
DropKeyspace dropKeyspace = SchemaBuilder.dropKeyspace("school_test").ifExists();
session.execute(dropKeyspace);
}
4.修改鍵空間
@Test
public void alterKeySpace() {
HashMap<String, Object> map = new HashMap<>();
map.put("class", "SimpleStrategy");
map.put("replication_factor", 2);
KeyspaceOptions options = SchemaBuilder.alterKeyspace("school")
.with().replication(map);
session.execute(options);
}
表操作
1.建立表
@Test
public void createTable() {
Create create = SchemaBuilder.createTable("school", "students")
.addPartitionKey("id", DataType.bigint())
.addColumn("address", DataType.varchar())
.addColumn("name", DataType.varchar())
.addColumn("phone", DataType.CollectionType.list(DataType.varchar()))
.addColumn("interest", DataType.CollectionType.set(DataType.varchar()))
.addColumn("education", DataType.CollectionType.map(DataType.varchar(), DataType.varchar()))
.ifNotExists();
session.execute(create);
}
2.修改表
@Test
public void alterTable() {
SchemaStatement statement = SchemaBuilder.alterTable("school", "students")
.addColumn("email").type(DataType.text());
session.execute(statement);
SchemaStatement statement1 = SchemaBuilder.alterTable("school", "students")
.dropColumn("address");
session.execute(statement1);
}
3.刪除表
@Test
public void dropTable() {
Drop drop = SchemaBuilder.dropTable("school", "students");
session.execute(drop);
}
資料操作
使用Mapper和Bean物件形式儲存資料:
@Data
@Table(keyspace = "school", name = "student")
public class Student implements Serializable {
@PartitionKey //標識當前欄位是分割槽鍵
private Integer id;
private String address;
private Integer age;
private Map<String, String> education;
private Byte gender;
private Set<String> interest;
private String name;
private List<String> phone;
}
測試插入資料
/**
* 使用Mapper和Bean物件形式儲存資料
* @author wen.jie
* @date 2022/3/16 15:51
*/
@Test
public void insert() {
Student student = new Student();
student.setId(1012);
student.setAddress("南京");
student.setAge(17);
student.setEducation(Collections.singletonMap("大學", "abc大學"));
student.setGender((byte)1);
student.setInterest(new HashSet<>(Arrays.asList("看書", "音樂")));
student.setName("tom");
student.setPhone(Arrays.asList("12222222222","13333333333"));
Mapper<Student> mapper = new MappingManager(session).mapper(Student.class);
mapper.save(student);
}
測試查詢全部
@Test
public void findAll() {
ResultSet resultSet = session.execute(QueryBuilder.select().from("school", "student"));
Mapper<Student> mapper = new MappingManager(session).mapper(Student.class);
List<Student> students = mapper.map(resultSet).all();
for (Student student : students) {
System.out.println(student);
}
}
根據id查詢
@Test
public void findById() {
Select.Where where = QueryBuilder.select().from("school", "student").where(QueryBuilder.eq("id", 1012));
ResultSet resultSet = session.execute(where);
Mapper<Student> mapper = new MappingManager(session).mapper(Student.class);
Student student = mapper.map(resultSet).one();
System.out.println(student);
}
根據id刪除
@Test
public void deleteById() {
Mapper<Student> mapper = new MappingManager(session).mapper(Student.class);
mapper.delete(1012);
}
索引操作
建立索引
@Test
public void createIdx() {
SchemaStatement statement = SchemaBuilder.createIndex("name_idx")
.onTable("school", "student")
.andColumn("name");
session.execute(statement);
}
刪除索引
@Test
public void dropIndex() {
Drop drop = SchemaBuilder.dropIndex("school", "name_idx");
session.execute(drop);
}
預編譯操作
cassandra提供了類似jdbc preparedstatement
使用預編譯佔位符。官方文件連結如下:
https://docs.datastax.com/en/developer/java-driver/3.0/manual/statements/prepared/
基本原理:
預編譯statement的時候,Cassandra會解析query語句,快取解析的結果並返回一個唯一的標誌。當繫結並且執行預編譯statement的時候,驅動只會傳送這個標誌,那麼Cassandra就會跳過解析query語句的過程。
應保證query語句只應該被預編譯一次,快取
PreparedStatement
到我們的應用中(PreparedStatement
是執行緒安全的);如果我們對同一個query語句預編譯了多次,那麼驅動輸出印警告日誌;如果一個query語句只執行一次,那麼預編譯不會提供效能上的提高,反而會降低效能,因為是兩次請求,那麼此時可以考慮用 simple statement 來代替
程式碼:
@Test
public void batchPrepare(){
//先把語句預編譯
BatchStatement batch = new BatchStatement();
PreparedStatement ps = session .prepare("INSERT INTO school.student (id,address,age,gender,name,interest, phone,education) VALUES (?,?,?,?,?,?,?,?)");
//迴圈10次,構造不同的student物件
for (int i = 0; i < 10; i++) {
HashMap<String, String> education = new HashMap<>();
education.put("小學", "中心第"+i+"小學");
education.put("中學", "第"+i+"中學");
HashSet<String> interest = new HashSet<>();
interest.add("看書");
interest.add("電影");
List<String> phones = new ArrayList<>();
phones.add("0"+i+"0-66666666");
phones.add("1"+i+"666666666");
Student student = new Student(
1013 + i,
"北京市朝陽區10" + i + "號",
21 + i,
education,
(byte)1,
interest,
"學生"+i,
phones);
BoundStatement bs = ps.bind(student.getId(),
student.getAddress(),
student.getAge(),
student.getGender(),
student.getName(),
student.getInterest(),
student.getPhone(),
student.getEducation());
batch.add(bs);
}
session.execute(batch);
batch.clear();
}
效果: