spring-data-cassanra的簡單使用

以前寫了JAVA操做cassandra驅動包,如今來看看spring-data對cassandra的支持。這裏是spring-data-cassandra的官方文檔:http://docs.spring.io/spring-data/cassandra/docs/1.5.0.M1/reference/html/  html

這個目錄下還有api、版本日誌等:http://docs.spring.io/spring-data/cassandra/docs/1.5.0.M1/java

  1. 引入jar包
    <!-- 這裏對應的是cassandra3.0以後的版本 -->
    <dependency>
       <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-cassandra</artifactId>
        <version>1.5.0.M1</version>
    </dependency>
  2. 定義域模型(實體類)
    不存在複合主鍵的狀況:
    package com.my.domin.pojo;
    
    import org.springframework.data.cassandra.mapping.Column;
    import org.springframework.data.cassandra.mapping.PrimaryKey;
    import org.springframework.data.cassandra.mapping.Table;
    
    @Table
    public class Person
    {
        // 主鍵
        @PrimaryKey
        private String id;
    
        // 列名 與數據庫列名一致時可不加
        @Column(value = "name")
        private String name;
    
        private int age;
    
        // 支持構造函數
        public Person(String id, String name, int age)
        {
            this.id = id;
            this.name = name;
            this.age = age;
        }
    
        public String getId()
        {
            return id;
        }
    
        public void setId(String id)
        {
            this.id = id;
        }
    
        public String getName()
        {
            return name;
        }
    
        public void setName(String name)
        {
            this.name = name;
        }
    
        public int getAge()
        {
            return age;
        }
    
        public void setAge(int age)
        {
            this.age = age;
        }
    
        @Override
        public String toString()
        {
            return "Person [id=" + id + ", name=" + name + ", age=" + age + "]";
        }
    
    }

    對應的CQL建表語句spring

    CREATE TABLE mydb.person (
        id text PRIMARY KEY,
        age int,
        name text
    )

    能夠看出和JPA的註解很相似,不一樣的是cassandra主鍵用的是@PrimaryKey,並且容許使用構造函數。
    若是存在複合主鍵,則要先映射一個主鍵的實體類,再映射一個包含這個主鍵的實體類數據庫

    package com.my.domin.pojo;
    
    import org.springframework.cassandra.core.Ordering;
    import org.springframework.cassandra.core.PrimaryKeyType;
    import org.springframework.data.cassandra.mapping.PrimaryKeyClass;
    import org.springframework.data.cassandra.mapping.PrimaryKeyColumn;
    
    @PrimaryKeyClass
    public class Person2Key
    {
    
        // 分區鍵
        @PrimaryKeyColumn(name = "id", ordinal = 0, type = PrimaryKeyType.PARTITIONED)
        private String id;
    
        // 集羣鍵
        @PrimaryKeyColumn(name = "name", ordinal = 1, type = PrimaryKeyType.CLUSTERED, ordering = Ordering.DESCENDING)
        private String name;
    
        public String getId()
        {
            return id;
        }
    
        public void setId(String id)
        {
            this.id = id;
        }
    
        public String getName()
        {
            return name;
        }
    
        public void setName(String name)
        {
            this.name = name;
        }
    
        @Override
        public String toString()
        {
            return "Person2Key [id=" + id + ", name=" + name + "]";
        }
    
    }
    package com.my.domin.pojo;
    
    import org.springframework.data.cassandra.mapping.PrimaryKey;
    import org.springframework.data.cassandra.mapping.Table;
    
    @Table(value = "person2")
    public class Person2
    {
        @PrimaryKey
        private Person2Key pKey;
    
        private int age;
    
        public Person2Key getpKey()
        {
            return pKey;
        }
    
        public void setpKey(Person2Key pKey)
        {
            this.pKey = pKey;
        }
    
        public int getAge()
        {
            return age;
        }
    
        public void setAge(int age)
        {
            this.age = age;
        }
    
        @Override
        public String toString()
        {
            return "Person2 [pKey=" + pKey + ", age=" + age + "]";
        }
    
    }

     對應的CQL建表語句express

    CREATE TABLE mydb.person2 (
        id text,
        name text,
        age int,
        PRIMARY KEY (id, name)
    ) WITH CLUSTERING ORDER BY (name DESC)

    其中的WITH CLUSTERING ORDER BY (name DESC) 對應主鍵類裏的ordering = Ordering.DESCENDING,按照name降序存儲,只有集羣鍵才能在建表時設置降序存儲。
    其實還有更加複雜的複合分區鍵、複合集羣鍵組合成的主鍵,看懂了上面應該就能觸類旁通了,並且用的很少,這裏就不寫了。apache

  3. 定義spring-data接口
    package com.my.repository;
    
    import java.util.List;
    
    import org.springframework.data.cassandra.repository.Query;
    import org.springframework.data.repository.CrudRepository;
    import org.springframework.stereotype.Repository;
    
    import com.my.domin.pojo.Person2;
    
    @Repository
    public interface PersonRepository extends CrudRepository<Person2, String>
    {
        @Query("select * from Person2 where id= ?1 and name= ?2")
        List<Person2> findByIdAndName(String id, String name);
    }

    咱們能夠看看繼承的CrudRepository這個倉庫接口類api

    /*
     * Copyright 2008-2011 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package org.springframework.data.repository;
    
    import java.io.Serializable;
    
    /**
     * Interface for generic CRUD operations on a repository for a specific type.
     * 
     * @author Oliver Gierke
     * @author Eberhard Wolff
     */
    @NoRepositoryBean
    public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
    
        /**
         * Saves a given entity. Use the returned instance for further operations as the save operation might have changed the
         * entity instance completely.
         * 
         * @param entity
         * @return the saved entity
         */
        <S extends T> S save(S entity);
    
        /**
         * Saves all given entities.
         * 
         * @param entities
         * @return the saved entities
         * @throws IllegalArgumentException in case the given entity is {@literal null}.
         */
        <S extends T> Iterable<S> save(Iterable<S> entities);
    
        /**
         * Retrieves an entity by its id.
         * 
         * @param id must not be {@literal null}.
         * @return the entity with the given id or {@literal null} if none found
         * @throws IllegalArgumentException if {@code id} is {@literal null}
         */
        T findOne(ID id);
    
        /**
         * Returns whether an entity with the given id exists.
         * 
         * @param id must not be {@literal null}.
         * @return true if an entity with the given id exists, {@literal false} otherwise
         * @throws IllegalArgumentException if {@code id} is {@literal null}
         */
        boolean exists(ID id);
    
        /**
         * Returns all instances of the type.
         * 
         * @return all entities
         */
        Iterable<T> findAll();
    
        /**
         * Returns all instances of the type with the given IDs.
         * 
         * @param ids
         * @return
         */
        Iterable<T> findAll(Iterable<ID> ids);
    
        /**
         * Returns the number of entities available.
         * 
         * @return the number of entities
         */
        long count();
    
        /**
         * Deletes the entity with the given id.
         * 
         * @param id must not be {@literal null}.
         * @throws IllegalArgumentException in case the given {@code id} is {@literal null}
         */
        void delete(ID id);
    
        /**
         * Deletes a given entity.
         * 
         * @param entity
         * @throws IllegalArgumentException in case the given entity is {@literal null}.
         */
        void delete(T entity);
    
        /**
         * Deletes the given entities.
         * 
         * @param entities
         * @throws IllegalArgumentException in case the given {@link Iterable} is {@literal null}.
         */
        void delete(Iterable<? extends T> entities);
    
        /**
         * Deletes all entities managed by the repository.
         */
        void deleteAll();
    }

    這裏面實現了一組CURD方法,若是要寫一些條件查詢的話能夠參考session

    @Query("select * from Person where id= ?1 and name= ?2 ALLOW FILTERING")
     List<Person> findByIdAndName(String id, String name);

    這裏要注意的是cassandra支持的查詢是有限制的,能夠參考這篇文章http://zhaoyanblog.com/archives/265.html 。3.0以後的版本改善了許多(如上面的查詢3.0如下的版本是不支持的,name爲非主鍵字段),一個是支持了非主鍵的條件查詢,一個是下降了集羣鍵的查詢限制條件,這裏最好本身在cql中測試一下。
    spring-data-cassandra文檔裏還提到一個分頁的倉庫接口類PagingAndSortingRepository,這個繼承自CrudRepository,並且提供了2個分頁方法。可是通過測試是不能用的。。至少我沒有測試經過,不知道是沒有實現(比較傾向於這個,cassandra分頁的確比較麻煩),仍是本身沒有正確使用。app

  4. application.xml配置文件
    看名字就知道spring-data-cassandra是和spring一塊兒使用的,下面的配置只是最最基本的,更多的配置選項能夠參考 https://my.oschina.net/u/2392555/blog/469893 這篇文章。
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:cassandra="http://www.springframework.org/schema/data/cassandra"
     xmlns:context="http://www.springframework.org/schema/context"
     xmlns:p="http://www.springframework.org/schema/p"
     xsi:schemaLocation="http://www.springframework.org/schema/data/cassandra
        http://www.springframework.org/schema/data/cassandra/spring-cassandra-1.0.xsd
        http://www.springframework.org/schema/data/cassandra/spring-cql.xsd
        http://www.springframework.org/schema/data/cassandra/spring-cql-1.0.xsd
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        ">
        
        <!-- 引入屬性文件 -->
        <context:property-placeholder location="classpath:cassandra.properties" />
         
        <!-- 自動掃描(自動注入) -->
        <context:component-scan base-package="com.my" />
        
        <!-- 註解方式配置事物 -->
        <tx:annotation-driven transaction-manager="transactionManager" />
        
        <!-- spring-cassandra -->
        <cassandra:cluster contact-points="${cassandra_contactpoints}" port="${cassandra_port}" username="${cassandra_username}" password="${cassandra_password}" />
        
        <!-- 當前使用scheam -->
          <cassandra:session keyspace-name="${cassandra_keyspace}" />
          
        <!-- orm -->
         <cassandra:mapping />
         
        <!-- 類型轉換 -->
          <cassandra:converter />
          
        <!-- cassandra operater -->
          <cassandra:template id="cqlTemplate" />
          
        <!-- spring data 接口 -->
          <cassandra:repositories base-package="com.my.repository" />
    
    </beans>

    這個配置文件都有註釋,沒什麼可講的,惟一要注意的是<cassandra:template id="cqlTemplate" /> ,官方文檔上寫的是<cassandra:template id="cassandraTemplate" />,通過測試官方文檔上寫的不能使用,改成上面的就行了。
    其中cassandra.properties文件配置less

    #cassandra數據庫鏈接
    #節點ip
    cassandra_contactpoints=192.168.3.89
    #端口
    cassandra_port=9042
    #當前操做鍵空間
    cassandra_keyspace=mydb
    #登陸用戶名
    cassandra_username=cassandra
    #登陸密碼
    cassandra_password=cassandra
  5. 使用測試
    cassandra數據庫person表中數據以下:

    測試方法:
    package com.my.serviceImpl;
    
    import java.util.Iterator;
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.cassandra.core.CassandraOperations;
    import org.springframework.stereotype.Service;
    
    import com.datastax.driver.core.querybuilder.QueryBuilder;
    import com.datastax.driver.core.querybuilder.Select;
    import com.my.domin.pojo.Person;
    import com.my.repository.PersonRepository;
    import com.my.service.PersonService;
    
    @Service
    public class PersonServiceImpl implements PersonService
    {
        @Autowired
        private PersonRepository personRepository;
    
        @Autowired
        private CassandraOperations cassandraOperations;
    
        @Override
        public void test()
        {
            //經過Repository查詢
            Iterable<Person> iterable = personRepository.findAll();
            Iterator<Person> it = iterable.iterator();
            System.out.println("==>findAll:");
            while (it.hasNext())
            {
                Person p = it.next();
                System.out.println(p.toString());
            }
            
            //經過Repository 自定義查詢查詢
            List<Person> list = personRepository.findByIdAndName("1", "one");
            System.out.println("==>findByIdAndName:");
            for (Person person : list)
            {
                System.out.println(person.toString());
            }
            //經過cassandraOperations查詢
            Select select = QueryBuilder.select().from("person");
            select.where(QueryBuilder.eq("id", "1"));
            Person person = cassandraOperations.selectOne(select, Person.class);
            System.out.println("==>cassandraOperations:");
            System.out.println(person.toString());
    
        }
    
    }

    打印結果


    這裏麪包含2種使用方法,一個是使用本身定義的倉庫接口類,另外一個是spring-data-cassandra提供的CassandraOperations類。CassandraOperations使用方式不少,上面只是列舉了一種,其餘具體應用官方文檔都有說明。

  6. 到這裏就告一段落了,官方文檔還有不少內容,等有時間再去慢慢看了。
相關文章
相關標籤/搜索