1. 程式人生 > 其它 >Cassandra:java客戶端操作

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

原始碼地址:

https://github.com/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();
    }

效果: