在本教程系列的第一部分中,我介绍了Cassandra的基础知识,并使用CQLSH通过Shell与数据库系统进行通信。 在第二部分中,我将简要介绍CQL中可用的主要数据类型。 然后,我将介绍gocql
的基本知识, gocql
是一个Golang客户端程序包,它实现了Golang的Cassandra驱动程序。 我将介绍如何使用一些配置选项与Cassandra创建会话连接,以及如何使用该会话运行各种查询。
Cassandra提供了对几乎所有数据库系统中都可用的基本数据类型的支持。 除此之外,它还提供了复杂的收集类型,可以以列表,集合和映射的形式存储简单数据的组合。 除此之外,CQL还支持用户定义的类型,使开发人员可以拥有自己的易于理解和理解的数据类型。
基本数据类型
- ascii:表示一个ASCII字符字符串。 在此类型的列中插入任何非ASCII字符都将导致错误。
- bigint:表示64位带符号的长整数 。 用于存储长号。 仅当我们确定我们需要这么长的数字时才应使用此方法,因为与int相比,它占用更多的空间。
- blob:用于存储任意字节。 它以十六进制表示,任何未经验证的数据都可以存储在此字段中。
- 布尔值:存储
true
或false
。
- counter:代表64位有符号整数,但是无法设置此列的值。 此列上只有两个操作:递增和递减。 在带有计数器列的表中,仅允许使用计数器类型和主键。 带有计数器列的表中不允许有
INSERT
语句; 只能使用UPDATE
。 例如:
> CREATE TABLE website_tracker (
id int PRIMARY KEY,
url text,
visitor_count counter
);
> UPDATE website_tracker
SET visitor_count = visitor_count + 1
WHERE id = 1;
> SELECT * FROM website_tracker;
id | url | count
----+------+------
1 | a.com | 1
(1 rows)
- date:表示没有时间值的日期值。 自纪元以来,Cassandra编码为整数。 日期可以用
yyyy-mm-dd
格式的字符串表示。
- 小数:表示精度为十进制的值。 最适合存储货币或财务价值。
- double:存储64位浮点值。
- float:存储32位浮点值。
- inet:表示IPv4或IPv6格式的IP地址字符串。
- int:表示32位有符号整数。 主要在存储整数值时使用。
- smallint:表示2字节(16位)整数。 在存储小整数值以节省空间方面,它比int更为可取。
- text:表示UTF-8编码的字符串。 当我们要存储非ASCII字符时应使用。
- 时间:表示时间值。 以字符串形式表示,格式为
01:02:03.123
并存储64位带符号整数,该整数表示自午夜以来经过的纳秒。
- 时间戳:以毫秒为单位存储日期和时间部分。 可以表示为格式为
2016-12-01 01:02:03.123
。
- tinyint:表示一个1字节(8位)的整数。 与int或smallint相比,它可以首选存储较小的整数值以节省空间。
- timeuuid:存储版本1 UUID。
- uuid:标准格式的UUID。 与timeuuid相比,这是一个较大的值。
- varchar:类似于文本。 两者可以互换使用。
- variant:具有任意精度的整数值。 建议使用要求的精度的数据类型。
收集数据类型
- set:此类型存储值的集合。 这些值按无序存储,但是CQLSH将以排序方式返回它们。 例如,字符串将按字母顺序排序。 让我们修改上面创建的表:
> ALTER TABLE website_tracker ADD tagsSet set<text>;
> UPDATE website_tracker SET tagsSet = {'tag1'} WHERE id = 1;
> SELECT tagsSet FROM website_tracker WHERE id = 1;
tagsSet
----------
{'tag1'}
> UPDATE website_tracker SET tagsSet = tagsSet + {'gat2'} WHERE id = 1;
> SELECT tagsSet FROM website_tracker WHERE id = 1;
tagsSet
------------------
{'gat2', 'tag1'}
您可以使用通常的设置操作(如difference
删除元素。 要清除或替换完整集,请执行SET tags = {<something>}
。
- list:列表还存储值的集合,但以有序方式存储它们,默认情况下按插入顺序。 现在,让我们尝试执行与上面带有列表的集合相同的操作:
> ALTER TABLE website_tracker ADD tagsList list<text>;
> UPDATE website_tracker SET tagsList = ['tag1'] WHERE id = 1;
> SELECT tagsList FROM website_tracker WHERE id = 1;
tagsList
----------
['tag1']
> UPDATE website_tracker SET tagsList = tagsList + ['gat2'] WHERE id = 1;
> SELECT tagsList FROM website_tracker WHERE id = 1;
tagsList
------------------
['tag1', 'gat2']
在列表中,可以在值前添加,减去(如在集合中),通过索引值( SET tags[1] = '<somevalue>'
)插入/替换/删除等。
- map:地图包含键/值对的集合。 这些可以是计数器类型以外的任何东西。 让我们对每个标签进行简短描述。
> ALTER TABLE website_tracker ADD tagsMap map<text, text>;
> UPDATE website_tracker SET tagsMap = {'tag1': 'Tag One'} WHERE id = 1;
> SELECT tagsMap FROM website_tracker WHERE id = 1;
tagsMap
----------------------
{'tag1': 'Tag One'}
> UPDATE website_tracker SET tagsMap['tag2'] = 'Tag Two' WHERE id = 1;
> SELECT tagsMap FROM website_tracker WHERE id = 1;
tagsMap
------------------
{'tag1': 'Tag One', 'tag2': 'Tag Two'}
用户定义的数据类型
在Cassandra中可以定义我们自己的类型。 这提供了很大的灵活性,并使数据的整体维护更加容易。 假设我们要存储网站的注册地址。
> CREATE TYPE address (
... street text,
... city text,
... state text);
> ALTER TABLE website_tracker ADD reg_address address;
为了在嵌套集合中使用用户定义的类型,我们需要将其指定为frozen
集合。
> ALTER TABLE website_tracker ADD reg_addresses map<text, frozen<address>>;
使用GoCQL
我假设您具有使用Golang以及配置和安装软件包的一些知识。
安装
要安装gocql
软件包,请从shell运行以下命令:
$ go get github.com/gocql/gocql
现在,我将创建一个Go脚本,该脚本将解释理解gocql
所需的概念。
编写脚本
main.go
package main
import (
"github.com/gocql/gocql"
"log"
"time"
)
func PerformOperations() {
// Provide the cassandra cluster instance here.
cluster := gocql.NewCluster("127.0.0.1")
// The authenticator is needed if password authentication is
// enabled for your Cassandra installation. If not, this can
// be removed.
cluster.Authenticator = gocql.PasswordAuthenticator{
Username: "some_username",
Password: "some_password",
}
// gocql requires the keyspace to be provided before the session is created.
// In future there might be provisions to do this later.
cluster.Keyspace = "keyspace_name"
// This is time after which the creation of session call would timeout.
// This can be customised as needed.
cluster.Timeout = 5 * time.Second
cluster.ProtoVersion = 4
session, err := cluster.CreateSession()
if err != nil {
log.Fatalf("Could not connect to cassandra cluster: %v", err)
}
// Check if the table already exists. Create if table does not exist
keySpaceMeta, _ := session.KeyspaceMetadata("keyspace_name")
if _, exists := keySpaceMeta.Tables["person"]; exists != true {
// Create a table
session.Query("CREATE TABLE person (" +
"id text, name text, phone text, " +
"PRIMARY KEY (id))").Exec()
}
// DIY: Update table with something if it already exist.
// Insert record into table using prepared statements
session.Query("INSERT INTO person (id, name, phone) VALUES (?, ?, ?)",
"shalabh", "Shalabh Aggarwal", "1234567890").Exec()
// DIY: Update existing record
// Select record and run some process on data fetched
var name string
var phone string
if err := session.Query(
"SELECT name, phone FROM person WHERE id='shalabh'").Scan(
&name, &phone); err != nil {
if err != gocql.ErrNotFound {
log.Fatalf("Query failed: %v", err)
}
}
log.Printf("Name: %v", name)
log.Printf("Phone: %v", phone)
// Fetch multiple rows and run process over them
iter := session.Query("SELECT name, phone FROM person").Iter()
for iter.Scan(&name, &phone) {
log.Printf("Iter Name: %v", name)
log.Printf("Iter Phone: %v", phone)
}
// DIY: Delete record
}
func main() {
PerformOperations()
}
上面的代码本身解释了大多数工作概念。 值得注意的是与session.Query()
一起使用的不同操作。 除了下面的三个操作外,还有更多支持,可以在文档中看到。
-
Exec()
:这将只执行查询而不返回任何行。 返回错误(如果有)。 -
Scan()
:这将在将查询中匹配的第一行中的列值复制到传递的变量时执行查询。 它将丢弃除第一个行以外的任何行。 -
Iter()
:这将执行查询并返回一个迭代器,然后该迭代器将像Scan()
如何为提取的每一行工作一样工作。
运行脚本
要运行该脚本,请在shell中执行以下命令。
$ go run main.go
2017/02/03 12:53:40 Name: Shalabh Aggarwal
2017/02/03 12:53:40 Phone: 1234567890
2017/02/03 12:53:40 Iter Name: Shalabh Aggarwal
2017/02/03 12:53:40 Iter Phone: 1234567890
结论
在本教程系列的第二部分中,我们介绍了Cassandra提供的各种内置数据类型。 我们还看到了集合类型如何工作以及如何使用用户定义的类型来使整体架构更灵活。 我们还看到了如何使用gocql在Golang中以编程方式与Cassandra进行交互。 这个软件包提供了更多的功能,您可以自己探索。