文章目录
  1. 1. 数据库
    1. 1.1. 安装
    2. 1.2. 打开数据库
    3. 1.3. 连接池
    4. 1.4. 连接池配置

数据库

需要使用库来访问关系型数据库。crystal-lang/crystal-db 包提供了访问不同数据库的统一接口。
crystal-db支持下面的数据库类型:

1
2
3
crystal-lang/crystal-sqlite3 for sqlite
crystal-lang/crystal-mysql for mysql & mariadb
will/crystal-pg for postgres

除了标准统一的数据库接口外 ,不同的数据库驱动也会提供一些额外的接口。

安装

需要配置项目中的shard.yml, 调用时不需要使用 “require crystal-lang/crystal-db” 下面是安装mysql的例子

1
2
3
dependencies:
mysql:
github: crystal-lang/crystal-mysql

打开数据库

使用DB.open和连接配置字符串可以很容易创建连接。下面是打开Mysql的例子

1
2
3
4
5
6
7
8
9
10
11
require "db"
require "mysql"

DB.open "mysql://root@localhost/test" do |db|
# ... use db to perform queries
end

# 其它的一些数据库连接字符串
sqlite3:///path/to/data.db
mysql://user:password@server:port/database
postgres://server:port/database

你也可以不通过yield来创建连接,这需要在程序结束前手动关系连接。

1
2
3
4
5
6
7
8
9
require "db"
require "mysql"

db = DB.open "mysql://root@localhost/test"
begin
# ... use db to perform queries
ensure
db.close
end

使用exec执行sql语句

1
db.exec "create table contacts (name varchar(30), age int)"

使用带参数的形式来防止Sql注入

1
2
db.exec "insert into contacts values (?, ?)", "John", 30
db.exec "insert into contacts values (?, ?)", "Sarah", 33

注意:使用Pg数据库时要使用 $1,$2来替代 ?

使用query
通过使用query方法, 可以取到Sql的执行结果 ,参数的使用方法和exec一样。
query返回的rs需要关闭 , 如果是使用块方式进行的调用 rs将会被隐式的关闭。

1
2
3
4
5
db.query "select name, age from contacts order by age desc" do |rs|
rs.each do
# ... perform for each row in the ResultSet
end
end

crystal在编译时无法预知数据库返回记录的字段类型 ,你需要使用 rs.read(T) 使用T来指定期望获取的数据类型。

1
2
3
4
5
6
7
8
9
db.query "select name, age from contacts order by age desc" do |rs|
rs.each do
name = rs.read(String)
age = rs.read(Int32)
puts "#{name} (#{age})"
# => Sarah (33)
# => John Doe (30)
end
end

可以一次读取多个字段

1
name, age = rs.read(String, Int32)

或者只读取一行

1
name, age = db.query_one "select name, age from contacts order by age desc limit 1", as: { String, Int32 }

或者只读取某个值

1
max_age = db.scalar "select max(age) from contacts"

所有这些操作方法都定义在 DB::QueryMethods

连接池

连接通常是指一个打开的Tcp连接或端口。socket会在某个时间处理一个事件。如果一个数据库程序在一个时间内需要处理很多查询或请求,相应的它就需要多个连接。
数据库服务和程序是相对独立的,我们可以使程序不需要关注数据库连接的断开,服务重启之类的事情 。为了达到这个小目标,数据库连接池通常是一个好的方案。
当数据库使用 crystal-db打开之后 , 连接池就建立了。db.open返回一个管理数据库连接池的DB::Database对象。

1
2
3
DB.open("mysql://root@localhost/test") do |db|
# db is a DB::Database
end

当执行 db.query, db.exec, db.scalar等时,连接池执行如下过程:

1
2
3
4
5
1.在池中找到一个有效连接(在必要时会创建一个,如果无法创建 则等待一个有效连接 - 等待时间一般不能是很长)
2.提取出连接
3.执行Sql
4.如果不去取 DB::ResultSet, 连接会被放回连接池中。否则会等到ResultSet关闭时才把连接放回池中。
5.返回结果

连接池配置

1
2
3
4
5
6
7
Name	            Default         value
initial_pool_size 1
max_pool_size 0 (unlimited)
max_idle_pool_size 1
checkout_timeout 5.0 (seconds)
retry_attempts 1
retry_delay 1.0 (seconds)

当调用DB::Database时, initial_pool_size数量的连接将被创建。如果空闲的连接数量大于 max_idle_pool_size时, 返回池中的连接将被关闭。
当连接数达到max_pool_size时, 如果需要调用连接 则要等待checkout_timeout秒 直到现有的连接可用。
当一个连接丢失或无法使用时,将会尝试最多retry_attempts次,

文章目录
  1. 1. 数据库
    1. 1.1. 安装
    2. 1.2. 打开数据库
    3. 1.3. 连接池
    4. 1.4. 连接池配置