数据库编程
更新日期:
数据库
需要使用库来访问关系型数据库。crystal-lang/crystal-db 包提供了访问不同数据库的统一接口。
crystal-db支持下面的数据库类型:1
2
3crystal-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
3dependencies:
mysql:
github: crystal-lang/crystal-mysql
打开数据库
使用DB.open和连接配置字符串可以很容易创建连接。下面是打开Mysql的例子1
2
3
4
5
6
7
8
9
10
11require "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
9require "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
2db.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
5db.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
9db.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
3DB.open("mysql://root@localhost/test") do |db|
# db is a DB::Database
end
当执行 db.query, db.exec, db.scalar等时,连接池执行如下过程:1
2
3
4
51.在池中找到一个有效连接(在必要时会创建一个,如果无法创建 则等待一个有效连接 - 等待时间一般不能是很长)
2.提取出连接
3.执行Sql
4.如果不去取 DB::ResultSet, 连接会被放回连接池中。否则会等到ResultSet关闭时才把连接放回池中。
5.返回结果
连接池配置
1 | Name Default value |
当调用DB::Database时, initial_pool_size数量的连接将被创建。如果空闲的连接数量大于 max_idle_pool_size时, 返回池中的连接将被关闭。
当连接数达到max_pool_size时, 如果需要调用连接 则要等待checkout_timeout秒 直到现有的连接可用。
当一个连接丢失或无法使用时,将会尝试最多retry_attempts次,