1660506840
Psycopg 3
Psycopg 3 is a modern implementation of a PostgreSQL adapter for Python.
Quick version:
pip install --upgrade pip # upgrade pip to at least 20.3
pip install "psycopg[binary,pool]" # install binary dependencies
For further information about installation please check the documentation.
In order to work on the Psycopg source code you need to have the libpq
PostgreSQL client library installed in the system. For instance, on Debian systems, you can obtain it by running:
sudo apt install libpq5
After which you can clone this repository:
git clone https://github.com/psycopg/psycopg.git
cd psycopg
Please note that the repository contains the source code of several Python packages: that's why you don't see a setup.py
here. The packages may have different requirements:
psycopg
directory contains the pure python implementation of psycopg
. The package has only a runtime dependency on the libpq
, the PostgreSQL client library, which should be installed in your system.psycopg_c
directory contains an optimization module written in C/Cython. In order to build it you will need a few development tools: please look at Local installation in the docs for the details.psycopg_pool
directory contains the connection pools implementations. This is kept as a separate package to allow a different release cycle.You can create a local virtualenv and install there the packages in development mode, together with their development and testing requirements:
python -m venv .venv
source .venv/bin/activate
pip install -e "./psycopg[dev,test]" # for the base Python package
pip install -e ./psycopg_c # for the C extension module
pip install -e ./psycopg_pool # for the connection pool
Now hack away! You can use tox to validate the code:
pip install tox
tox -p4
and to run the tests:
psql -c 'create database psycopg_test'
export PSYCOPG_TEST_DSN="dbname=psycopg_test"
tox -c psycopg -s
tox -c psycopg_c -s
Please look at the commands definitions in the tox.ini
files if you want to run some of them interactively: the dependency should be already in your virtualenv. Feel free to adapt these recipes if you follow a different development pattern.
Author: psycopg
Source code: https://github.com/psycopg/psycopg
License: LGPL-3.0 license
#python #postgresql #database
1660485000
在本教程中,我们将探讨在 Rust 中与关系数据库交互时使用的两个库:Diesel 和 SQLx。
本文将使用一个简单的课堂数据库与学生一起演示每种方法。我们将使用 Diesel ORM 和 SQLx 执行 CRUD 操作。
要学习本教程,您需要具备Rust 的工作知识以及访问和使用 Rust、Rust 的构建系统和包管理器 Cargo以及 MySQL 服务器实例的能力。
Diesel 是一个支持 PostgreSQL、MySQL、SQLite 的 ORM。ORM 代表对象-关系映射。ORM 帮助面向对象的程序员抽象出关系数据库的细节。
ORM 附带查询构建器,因此您不必担心编写原始 SQL 查询。使用 ORM,您可以与关系数据库进行通信,就好像它们是面向对象的一样。
对于经验不足的开发人员,使用 ORM 可能会更好,因为 ORM 会优化 SQL 查询。ORM 还使您更不容易受到 SQL 注入攻击。
与 Diesel 不同,SQLx 不是 ORM。SQLx 是一个异步 Rust SQL crate,具有编译时 SQL 查询检查功能。它与数据库和运行时无关。
SQLx 支持连接池、跨平台开发、嵌套池、异步通知、传输层安全性和其他令人兴奋的特性。使用 SQLx 时,您必须自己制作 SQL 查询和迁移。
触及表面之后,让我们探索如何使用 Diesel 和 SQLx 与关系数据库进行交互。
以下步骤演示了如何使用使用 Diesel ORM 的 Cargo 设置 Rust 项目。
第一步是通过运行以下命令来初始化项目:
cargo new -- lib classroom_diesel
cd classroom_diesel
在上面的代码中,我们设置了项目并将其命名为classroom_diesel
。新的项目目录应如下所示:
./
│
├── src/
│ └── lib.rs
│
├── .gitignore
└── Cargo.toml
我们还需要使用项目中需要的依赖项更新Cargo.toml
文件,如下所示:
[dependencies]
diesel = { version = "1.4.4", features = ["mysql"] }
dotenv = "0.15.0"
依赖帮助我们管理项目中的dotenv
环境变量。
Diesel 使用单独的 CLI 工具。它是一个独立的二进制文件;我们不需要将它作为依赖项添加到cargo.toml
文件中。只需使用以下命令安装它:
cargo install diesel_cli
我们需要DATABASE_URL
在我们的环境中设置一个变量。这就是 Diesel 知道要连接到哪个 MySQL 数据库的方式:
echo DATABASE_URL=mysql://<username>:<password>@localhost/<database> > .env
编辑连接字符串以匹配您的本地数据库凭据。
您的项目目录现在将如下所示:
./
│
├── src/
│ └── lib.rs
│
├── .env
├── .gitignore
└── Cargo.toml
现在运行以下命令:
diesel setup
该命令将帮助我们设置数据库并创建一个空的迁移目录来管理数据库模式。
迁移帮助 ORM 跟踪数据库操作,例如添加字段或删除表。您可以将它们视为数据库的版本控制系统。
首先,让我们使用 Diesel CLI 为课堂应用程序创建一些迁移。理想情况下,我们应该有一个包含课堂学生数据的表格。
我们需要创建空的迁移文件,然后用 SQL 填充它们以创建表。
diesel migration generate create_students
您的文件树将类似于以下内容:
./
│
├── migrations/
│ │
│ ├── 2022-07-04-062521_create_students/
│ │ ├── down.sql
│ │ └── up.sql
│ │
│ └── .gitkeep
│
├── src/
│ └── lib.rs
│
├── .env
├── .gitignore
├── Cargo.toml
└── diesel.toml
该up.sql
文件用于创建迁移,而该down.sql
文件用于反转它。
up.sql
使用 SQL更新文件以进行迁移:
sql
CREATE TABLE students (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
firstname VARCHAR(255) NOT NULL,
lastname TEXT NOT NULL,
age INTEGER NOT NULL
);
down.sql
用可以反向迁移的 SQL修改文件:
sql
DROP TABLE students;
创建up
和down
迁移后,我们需要在数据库上执行 SQL:
diesel migration run
我们可以开始编写 Rust 来对表执行查询。
让我们编写代码以使用文件中设置的连接字符串建立与 MySQL 服务器的连接.env
。
#[macro_use]
extern crate diesel;
extern crate dotenv;
pub mod models;
pub mod schema;
use diesel::prelude::*;
use dotenv::dotenv;
use std::env;
pub fn create_connection() -> MysqlConnection {
dotenv().ok();
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
MysqlConnection::establish(&database_url)
.unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
}
Students
接下来,我们必须为表编写一个模型。模型是发生对象关系映射的地方。Students
该模型将生成将表上的一行或多行转换为Student
Rust 中的结构所需的代码。
cd ./src
touch model.rs
在我们刚刚创建的新model.rs
文件中,添加以下内容:
use super::schema::students;
#[derive(Queryable)]
pub struct Student {
pub id: i32,
pub firstname: String,
pub lastname: String,
pub age: i32,
}
#[derive(Insertable)]
#[table_name = "students"]
pub struct NewStudent<'a> {
pub firstname: &'a str,
pub lastname: &'a str,
pub age: &'a i32,
}
使用此模型,Students
表中的信息将映射到 Rust 中的相应Student
结构。该src
文件夹现在应如下所示:
src/
├── lib.rs
├── models.rs
└── schema.rs
现在,我们可以编写一个脚本来添加一个学生:
cd src mkdir bin cd bin touch create_students.rs
在该create_students.rs
文件中,我们可以调用之前编写的模型和函数来创建一个新学生:
extern crate classroom_diesel;
extern crate diesel;
use self::classroom_diesel::*;
fn main() {
let connection = create_connection();
let firstname = "John";
let lastname = "Doe";
let age: i32 = 64;
let student = create_post(&connection, firstname, lastname, &age);
println!(
"Saved student {} with id {}",
student.firstname, student.id
);
}
该项目的结构现在看起来与此类似:
./
│
├── migrations/
│ │
│ ├── 2022-07-04-062521_create_students/
│ │ ├── down.sql
│ │ └── up.sql
│ │
│ └── .gitkeep
│
├── src/
│ │
│ ├── bin/
│ │ └── create_students.rs
│ │
│ ├── lib.rs
│ ├── models.rs
│ └── schema.rs
│
├── .env
├── .gitignore
├── Cargo.lock
├── Cargo.toml
└── diesel.toml
使用以下命令执行新脚本:
cargo run --bin create_students
正如您在下图中看到的,新的学生文件John
已保存id
为1
. 我们可以使用它id
来查询 Rust 数据库,我们将在下一节中介绍。
在上一节中,我们回顾了如何使用 Diesel ORM 在 Rust 中写入数据库。了解查询或阅读的工作原理也很重要。
让我们编写一个脚本来查询一个学生id
的1
. 首先创建一个query_students.rs
文件:
cd bin
touch query_students.rs
然后,在query_students.rs
我们刚刚创建的文件中,添加以下内容:
extern crate classroom_diesel;
extern crate diesel;
use self::models::*;
use classroom_diesel::*;
use diesel::prelude::*;
fn main() {
use self::schema::students::dsl::*;
let connection = create_connection();
let result = students
.filter(id.eq(1))
.load::<Student>(&connection)
.expect("Error loading students");
println!(
"Student: {} {} {} years",
result[0].firstname, result[0].lastname, result[0].age
);
}
执行脚本:
cargo run --bin query_students
如下图所示,结果是一个打印行,其中包含我们从数据库中查询的学生文件的名字、姓氏和年龄:
现在我们知道如何创建一个使用 Diesel ORM 与 Rust 中的数据库交互的项目,让我们看看如何创建一个使用 SQLx 的项目。
首先运行以下命令:
cargo new classroom_sqlx --bin
然后,将所需的依赖项添加到cargo.toml
文件中:
[dependencies]
sqlx = { version = "0.5", features = [ "runtime-async-std-native-tls", "mysql" ] }
async-std = { version = "1", features = [ "attributes" ] }
这就是您在设置方面所需要的一切。很简单,对吧?
要使用 SQLx 与 Rust 中的数据库交互,我们所要做的就是编写一些 SQL 查询和 Rust 代码。在 Diesel ORM 部分,我们创建并读取了学生记录;在本节中,我们将编写查询来更新和删除记录。
首先,我们需要编写一些 Rust 代码来将 SQLx 连接到 MySQL 服务器:
//main.rs
use sqlx::mysql::MySqlPoolOptions;
#[async_std::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(7)
.connect("mysql://root:@localhost/classroom_diesel")
.await?;
Ok(())
}
SQLx 支持准备好的和未准备好的 SQL 查询。准备好的 SQL 查询反对 SQL 注入。
让我们看看如何更新主键为 1 的记录的名字和姓氏:
use sqlx::mysql::MySqlPoolOptions;
#[async_std::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(5)
.connect("mysql://root:@localhost/classroom_diesel")
.await?;
sqlx::query("UPDATE students SET firstname=?, lastname=? WHERE id=?")
.bind("Richard")
.bind("Roe")
.bind(1)
.execute(&pool)
.await?;
Ok(())
}
使用以下命令执行脚本:
cargo run
删除记录也采用类似的模式;唯一的区别是 SQL 查询:
use sqlx::mysql::MySqlPoolOptions;
#[async_std::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(5)
.connect("mysql://root:@localhost/classroom_diesel")
.await?;
sqlx::query("DELETE FROM students WHERE id=?")
.bind(1)
.execute(&pool)
.await?;
Ok(())
}
使用以下命令执行脚本:
cargo run
现在,您可以使用 Diesel 或 SQLx 与 Rust 中的数据库进行交互。
像 Diesel 这样的 ORM 就足够了;它们可以帮助您生成一些您需要的 SQL。大多数时候,足够的就是您的应用程序所需要的。
然而,在更广泛的应用程序中,可能需要更多的“魔法”——换句话说,你的时间和精力——才能使 ORM 正常工作并生成高性能的 SQL 查询。
如果需要创建具有高容量和低延迟要求的更复杂的查询,最好使用 SQLx 等库来执行原始 SQL 查询。
来源:https ://blog.logrocket.com/interacting-databases-rust-diesel-vs-sqlx/
1660482300
Neste tutorial, exploraremos duas bibliotecas usadas ao interagir com bancos de dados relacionais em Rust: Diesel e SQLx.
Este artigo usará um banco de dados de sala de aula simples com os alunos para demonstrar cada abordagem. Realizaremos operações CRUD usando Diesel ORM e SQLx.
Para acompanhar este tutorial, você precisará de um conhecimento prático do Rust , juntamente com a capacidade de acessar e usar o Rust, o sistema de compilação do Rust e o gerenciador de pacotes Cargo e uma instância do servidor MySQL.
Diesel é um ORM que suporta PostgreSQL, MySQL, SQLite. ORM significa mapeamento relacional de objeto. Os ORMs ajudam os programadores orientados a objetos a abstrair os detalhes dos bancos de dados relacionais.
Os ORMs são fornecidos com construtores de consultas, portanto, você não precisa se preocupar em escrever consultas SQL brutas. Usando ORMs, você pode se comunicar com bancos de dados relacionais como se fossem orientados a objetos.
Para desenvolvedores menos experientes, o uso de ORMs pode ser melhor porque os ORMs criam consultas SQL otimizadas. Os ORMs também o tornam menos propenso a ataques de injeção de SQL.
Ao contrário do Diesel, o SQLx não é um ORM. SQLx é uma caixa de Rust SQL assíncrona que apresenta verificações de consulta SQL em tempo de compilação. É independente de banco de dados e de tempo de execução.
O SQLx suporta pool de conexão, desenvolvimento multiplataforma, pool aninhado, notificações assíncronas, segurança da camada de transporte e outros recursos interessantes. Ao usar o SQLx, você mesmo deve criar as consultas e migrações SQL.
Tendo arranhado a superfície, vamos explorar como interagir com bancos de dados relacionais com Diesel e SQLx.
As etapas a seguir demonstram como configurar um projeto Rust com Cargo que usa Diesel ORM.
Sua primeira etapa é inicializar o projeto executando o seguinte comando:
cargo new -- lib classroom_diesel
cd classroom_diesel
No código acima, configuramos o projeto e o nomeamos classroom_diesel
. O novo diretório do projeto deve ficar assim:
./
│
├── src/
│ └── lib.rs
│
├── .gitignore
└── Cargo.toml
Também precisamos atualizar o Cargo.toml
arquivo com as dependências que precisamos no projeto, assim:
[dependencies]
diesel = { version = "1.4.4", features = ["mysql"] }
dotenv = "0.15.0"
A dotenv
dependência nos ajuda a gerenciar variáveis de ambiente no projeto.
Diesel usa uma ferramenta CLI separada . É um binário autônomo; não precisamos adicioná-lo como uma dependência no cargo.toml
arquivo. Basta instalá-lo com o comando abaixo:
cargo install diesel_cli
Precisamos definir uma DATABASE_URL
variável em nosso ambiente. É assim que Diesel sabe a qual banco de dados MySQL se conectar:
echo DATABASE_URL=mysql://<username>:<password>@localhost/<database> > .env
Edite a cadeia de conexão para corresponder às credenciais do banco de dados local.
O diretório do seu projeto agora ficará assim:
./
│
├── src/
│ └── lib.rs
│
├── .env
├── .gitignore
└── Cargo.toml
Agora execute o seguinte comando:
diesel setup
Este comando nos ajudará a configurar o banco de dados e criar um diretório de migrações vazio para gerenciar o esquema do banco de dados.
As migrações ajudam o ORM a acompanhar as operações do banco de dados, como adicionar um campo ou excluir uma tabela. Você pode pensar neles como um sistema de controle de versão para seu banco de dados.
Primeiro, vamos criar algumas migrações para o aplicativo de sala de aula usando o Diesel CLI. Idealmente, deveríamos ter uma tabela contendo dados sobre os alunos da sala de aula.
Precisamos criar arquivos de migração vazios e preenchê-los com SQL para criar uma tabela.
diesel migration generate create_students
Sua árvore de arquivos será semelhante a esta:
./
│
├── migrations/
│ │
│ ├── 2022-07-04-062521_create_students/
│ │ ├── down.sql
│ │ └── up.sql
│ │
│ └── .gitkeep
│
├── src/
│ └── lib.rs
│
├── .env
├── .gitignore
├── Cargo.toml
└── diesel.toml
O up.sql
arquivo é para criar uma migração, enquanto o down.sql
arquivo é para revertê-la.
Atualize o up.sql
arquivo com o SQL para a migração:
sql
CREATE TABLE students (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
firstname VARCHAR(255) NOT NULL,
lastname TEXT NOT NULL,
age INTEGER NOT NULL
);
Modifique o down.sql
arquivo com SQL que pode reverter a migração:
sql
DROP TABLE students;
Após criar as migrações up
e down
, precisamos executar o SQL no banco de dados:
diesel migration run
Podemos começar a escrever Rust para realizar consultas na tabela.
Vamos escrever o código para estabelecer uma conexão com o servidor MySQL usando a string de conexão definida no .env
arquivo.
#[macro_use]
extern crate diesel;
extern crate dotenv;
pub mod models;
pub mod schema;
use diesel::prelude::*;
use dotenv::dotenv;
use std::env;
pub fn create_connection() -> MysqlConnection {
dotenv().ok();
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
MysqlConnection::establish(&database_url)
.unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
}
Em seguida, devemos escrever um modelo para a Students
tabela. Os modelos são onde o mapeamento relacional de objeto ocorre. O modelo irá gerar o código necessário para converter uma linha ou linhas na Students
tabela em um Student
struct em Rust .
cd ./src
touch model.rs
No novo model.rs
arquivo que acabamos de criar, adicione o seguinte:
use super::schema::students;
#[derive(Queryable)]
pub struct Student {
pub id: i32,
pub firstname: String,
pub lastname: String,
pub age: i32,
}
#[derive(Insertable)]
#[table_name = "students"]
pub struct NewStudent<'a> {
pub firstname: &'a str,
pub lastname: &'a str,
pub age: &'a i32,
}
Com este modelo, as informações da Students
tabela serão mapeadas para a Student
estrutura correspondente em Rust. A src
pasta agora deve ficar assim:
src/
├── lib.rs
├── models.rs
└── schema.rs
Agora, podemos escrever um script para adicionar um aluno:
cd src mkdir bin cd bin touch create_students.rs
No create_students.rs
arquivo, podemos invocar os modelos e funções escritos anteriormente para criar um novo aluno:
extern crate classroom_diesel;
extern crate diesel;
use self::classroom_diesel::*;
fn main() {
let connection = create_connection();
let firstname = "John";
let lastname = "Doe";
let age: i32 = 64;
let student = create_post(&connection, firstname, lastname, &age);
println!(
"Saved student {} with id {}",
student.firstname, student.id
);
}
A estrutura do projeto agora será semelhante a esta:
./
│
├── migrations/
│ │
│ ├── 2022-07-04-062521_create_students/
│ │ ├── down.sql
│ │ └── up.sql
│ │
│ └── .gitkeep
│
├── src/
│ │
│ ├── bin/
│ │ └── create_students.rs
│ │
│ ├── lib.rs
│ ├── models.rs
│ └── schema.rs
│
├── .env
├── .gitignore
├── Cargo.lock
├── Cargo.toml
└── diesel.toml
Execute o novo script usando o seguinte comando:
cargo run --bin create_students
Como você pode ver na imagem abaixo, o novo arquivo do aluno para John
foi salvo com uma extensão id
de 1
. Podemos usar isso id
para consultar bancos de dados Rust, que veremos na próxima seção.
Na seção anterior, revisamos como gravar no banco de dados em Rust usando Diesel ORM. Também é essencial entender como a consulta, ou leitura, funciona.
Vamos escrever um script para consultar um aluno cujo id
é 1
. Comece criando um query_students.rs
arquivo:
cd bin
touch query_students.rs
Em seguida, no query_students.rs
arquivo que acabamos de criar, adicione o seguinte:
extern crate classroom_diesel;
extern crate diesel;
use self::models::*;
use classroom_diesel::*;
use diesel::prelude::*;
fn main() {
use self::schema::students::dsl::*;
let connection = create_connection();
let result = students
.filter(id.eq(1))
.load::<Student>(&connection)
.expect("Error loading students");
println!(
"Student: {} {} {} years",
result[0].firstname, result[0].lastname, result[0].age
);
}
Execute o script:
cargo run --bin query_students
Como você pode ver na imagem abaixo, o resultado é uma linha impressa contendo o nome, sobrenome e idade do arquivo do aluno que consultamos no banco de dados:
Agora que sabemos como criar um projeto que usa Diesel ORM para interagir com bancos de dados em Rust, vamos dar uma olhada em como criar um projeto que usa SQLx.
Comece executando o comando abaixo:
cargo new classroom_sqlx --bin
Em seguida, adicione as dependências necessárias ao cargo.toml
arquivo:
[dependencies]
sqlx = { version = "0.5", features = [ "runtime-async-std-native-tls", "mysql" ] }
async-std = { version = "1", features = [ "attributes" ] }
Isso é tudo que você precisa com relação à configuração. Simples, certo?
Para usar o SQLx para interagir com bancos de dados em Rust, tudo o que precisamos fazer é escrever algumas consultas SQL e código Rust. Na seção Diesel ORM, criamos e lemos um registro do aluno; nesta seção, escreveremos consultas para atualizar e excluir um registro.
Primeiro, precisamos escrever algum código Rust para conectar o SQLx ao servidor MySQL:
//main.rs
use sqlx::mysql::MySqlPoolOptions;
#[async_std::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(7)
.connect("mysql://root:@localhost/classroom_diesel")
.await?;
Ok(())
}
SQLx suporta consultas SQL preparadas e não preparadas. As consultas SQL preparadas são avessas à injeção de SQL.
Vamos ver como atualizar o nome e o sobrenome de um registro com uma chave primária de 1:
use sqlx::mysql::MySqlPoolOptions;
#[async_std::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(5)
.connect("mysql://root:@localhost/classroom_diesel")
.await?;
sqlx::query("UPDATE students SET firstname=?, lastname=? WHERE id=?")
.bind("Richard")
.bind("Roe")
.bind(1)
.execute(&pool)
.await?;
Ok(())
}
Execute o script com o comando abaixo:
cargo run
A exclusão do registro também segue um padrão semelhante; a única diferença é a consulta SQL:
use sqlx::mysql::MySqlPoolOptions;
#[async_std::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(5)
.connect("mysql://root:@localhost/classroom_diesel")
.await?;
sqlx::query("DELETE FROM students WHERE id=?")
.bind(1)
.execute(&pool)
.await?;
Ok(())
}
Execute o script com o comando abaixo:
cargo run
Agora você pode interagir com bancos de dados em Rust usando Diesel ou SQLx.
ORMs como Diesel são adequados; eles ajudam a gerar parte do SQL de que você precisa. Na maioria das vezes, adequado é tudo o que você precisa em suas aplicações.
No entanto, pode levar mais “mágica” – em outras palavras, seu tempo e esforço – em aplicativos mais extensos para que os ORMs funcionem corretamente e gerem consultas SQL de alto desempenho.
Se surgir a necessidade de criar consultas mais complicadas com requisitos de alto volume e baixa latência, pode ser melhor usar bibliotecas como SQLx para executar consultas SQL brutas.
Fonte: https://blog.logrocket.com/interacting-databases-rust-diesel-vs-sqlx/
1660481340
Dans ce didacticiel, nous allons explorer deux bibliothèques utilisées lors de l'interaction avec des bases de données relationnelles dans Rust : Diesel et SQLx.
Cet article utilisera une simple base de données de classe avec des étudiants pour démontrer chaque approche. Nous effectuerons des opérations CRUD en utilisant Diesel ORM et SQLx.
Pour suivre ce didacticiel, vous aurez besoin d'une connaissance pratique de Rust ainsi que de la capacité d'accéder à Rust et de l'utiliser, du système de construction et du gestionnaire de packages Cargo de Rust , ainsi que d'une instance de serveur MySQL.
Diesel est un ORM qui prend en charge PostgreSQL, MySQL, SQLite. ORM signifie mappage objet-relationnel. Les ORM aident les programmeurs orientés objet à résumer les détails des bases de données relationnelles.
Les ORM sont livrés avec des générateurs de requêtes, vous n'avez donc pas à vous soucier d'écrire des requêtes SQL brutes. En utilisant les ORM, vous pouvez communiquer avec des bases de données relationnelles comme si elles étaient orientées objet.
Pour les développeurs moins expérimentés, l'utilisation des ORM peut être préférable car les ORM élaborent des requêtes SQL optimisées. Les ORM vous rendent également moins sujet aux attaques par injection SQL.
Contrairement à Diesel, SQLx n'est pas un ORM. SQLx est un crate Rust SQL asynchrone qui propose des vérifications de requêtes SQL au moment de la compilation. Il est à la fois indépendant de la base de données et de l'exécution.
SQLx prend en charge le regroupement de connexions, le développement multiplateforme, le regroupement imbriqué, les notifications asynchrones, la sécurité de la couche de transport et d'autres fonctionnalités intéressantes. Lorsque vous utilisez SQLx, vous devez créer vous-même les requêtes SQL et les migrations.
Après avoir effleuré la surface, explorons comment interagir avec les bases de données relationnelles avec Diesel et SQLx.
Les étapes suivantes montrent comment configurer un projet Rust avec Cargo qui utilise Diesel ORM.
La première étape consiste à initialiser le projet en exécutant la commande suivante :
cargo new -- lib classroom_diesel
cd classroom_diesel
Dans le code ci-dessus, nous avons configuré le projet et l'avons nommé classroom_diesel
. Le nouveau répertoire du projet devrait ressembler à ceci :
./
│
├── src/
│ └── lib.rs
│
├── .gitignore
└── Cargo.toml
Nous devons également mettre à jour le Cargo.toml
fichier avec les dépendances dont nous avons besoin dans le projet, comme ceci :
[dependencies]
diesel = { version = "1.4.4", features = ["mysql"] }
dotenv = "0.15.0"
La dotenv
dépendance nous aide à gérer les variables d'environnement dans le projet.
Diesel utilise un outil CLI séparé . C'est un binaire autonome ; nous n'avons pas besoin de l'ajouter en tant que dépendance dans le cargo.toml
fichier. Installez-le simplement avec la commande ci-dessous :
cargo install diesel_cli
Nous devons définir une DATABASE_URL
variable dans notre environnement. C'est ainsi que Diesel sait à quelle base de données MySQL se connecter :
echo DATABASE_URL=mysql://<username>:<password>@localhost/<database> > .env
Modifiez la chaîne de connexion pour qu'elle corresponde aux informations d'identification de votre base de données locale.
Votre répertoire de projet ressemblera maintenant à ceci :
./
│
├── src/
│ └── lib.rs
│
├── .env
├── .gitignore
└── Cargo.toml
Exécutez maintenant la commande suivante :
diesel setup
Cette commande nous aidera à configurer la base de données et à créer un répertoire de migrations vide pour gérer le schéma de la base de données.
Les migrations aident l'ORM à suivre les opérations de la base de données, telles que l'ajout d'un champ ou la suppression d'une table. Vous pouvez les considérer comme un système de contrôle de version pour votre base de données.
Commençons par créer des migrations pour l'application de classe à l'aide de Diesel CLI. Idéalement, nous devrions avoir un tableau contenant des données sur les élèves de la classe.
Nous devons créer des fichiers de migration vides, puis les remplir avec SQL pour créer une table.
diesel migration generate create_students
Votre arborescence de fichiers ressemblera à ceci :
./
│
├── migrations/
│ │
│ ├── 2022-07-04-062521_create_students/
│ │ ├── down.sql
│ │ └── up.sql
│ │
│ └── .gitkeep
│
├── src/
│ └── lib.rs
│
├── .env
├── .gitignore
├── Cargo.toml
└── diesel.toml
Le up.sql
fichier sert à créer une migration, tandis que le down.sql
fichier sert à l'inverser.
Mettez à jour le up.sql
fichier avec le SQL pour la migration :
sql
CREATE TABLE students (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
firstname VARCHAR(255) NOT NULL,
lastname TEXT NOT NULL,
age INTEGER NOT NULL
);
Modifiez le down.sql
fichier avec SQL qui peut inverser la migration :
sql
DROP TABLE students;
Après avoir créé les migrations up
et down
, nous devons exécuter le SQL sur la base de données :
diesel migration run
Nous pouvons commencer à écrire Rust pour effectuer des requêtes sur la table.
Écrivons du code pour établir une connexion au serveur MySQL en utilisant la chaîne de connexion définie dans le .env
fichier.
#[macro_use]
extern crate diesel;
extern crate dotenv;
pub mod models;
pub mod schema;
use diesel::prelude::*;
use dotenv::dotenv;
use std::env;
pub fn create_connection() -> MysqlConnection {
dotenv().ok();
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
MysqlConnection::establish(&database_url)
.unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
}
Ensuite, nous devons écrire un modèle pour la Students
table. Les modèles sont l'endroit où le mappage objet-relationnel a lieu. Le modèle générera le code nécessaire pour convertir une ou plusieurs lignes de la Students
table en une Student
structure dans Rust .
cd ./src
touch model.rs
Dans le nouveau model.rs
fichier que nous venons de créer, ajoutez ce qui suit :
use super::schema::students;
#[derive(Queryable)]
pub struct Student {
pub id: i32,
pub firstname: String,
pub lastname: String,
pub age: i32,
}
#[derive(Insertable)]
#[table_name = "students"]
pub struct NewStudent<'a> {
pub firstname: &'a str,
pub lastname: &'a str,
pub age: &'a i32,
}
Avec ce modèle, les informations de la Students
table seront mappées à la structure correspondante Student
dans Rust. Le src
dossier devrait maintenant ressembler à ceci :
src/
├── lib.rs
├── models.rs
└── schema.rs
Maintenant, nous pouvons écrire un script pour ajouter un étudiant :
cd src mkdir bin cd bin tactile create_students.rs
Dans le create_students.rs
fichier, nous pouvons invoquer les modèles et fonctions écrits précédemment pour créer un nouvel étudiant :
extern crate classroom_diesel;
extern crate diesel;
use self::classroom_diesel::*;
fn main() {
let connection = create_connection();
let firstname = "John";
let lastname = "Doe";
let age: i32 = 64;
let student = create_post(&connection, firstname, lastname, &age);
println!(
"Saved student {} with id {}",
student.firstname, student.id
);
}
La structure du projet ressemblera maintenant à ceci :
./
│
├── migrations/
│ │
│ ├── 2022-07-04-062521_create_students/
│ │ ├── down.sql
│ │ └── up.sql
│ │
│ └── .gitkeep
│
├── src/
│ │
│ ├── bin/
│ │ └── create_students.rs
│ │
│ ├── lib.rs
│ ├── models.rs
│ └── schema.rs
│
├── .env
├── .gitignore
├── Cargo.lock
├── Cargo.toml
└── diesel.toml
Exécutez le nouveau script à l'aide de la commande suivante :
cargo run --bin create_students
Comme vous pouvez le voir dans l'image ci-dessous, le nouveau fichier étudiant pour John
a été enregistré avec l' id
extension 1
. Nous pouvons l'utiliser id
pour interroger les bases de données Rust, que nous examinerons dans la section suivante.
Dans la section précédente, nous avons examiné comment écrire dans la base de données de Rust à l'aide de Diesel ORM. Il est également essentiel de comprendre comment l'interrogation, ou la lecture, fonctionne.
Écrivons un script pour interroger un étudiant dont id
est 1
. Commencez par créer un query_students.rs
fichier :
cd bin
touch query_students.rs
Ensuite, dans le query_students.rs
fichier que nous venons de créer, ajoutez ce qui suit :
extern crate classroom_diesel;
extern crate diesel;
use self::models::*;
use classroom_diesel::*;
use diesel::prelude::*;
fn main() {
use self::schema::students::dsl::*;
let connection = create_connection();
let result = students
.filter(id.eq(1))
.load::<Student>(&connection)
.expect("Error loading students");
println!(
"Student: {} {} {} years",
result[0].firstname, result[0].lastname, result[0].age
);
}
Exécutez le script :
cargo run --bin query_students
Comme vous pouvez le voir dans l'image ci-dessous, le résultat est une ligne imprimée contenant le prénom, le nom et l'âge du dossier étudiant que nous avons interrogé dans la base de données :
Maintenant que nous savons comment créer un projet qui utilise Diesel ORM pour interagir avec des bases de données dans Rust, voyons comment créer un projet qui utilise SQLx à la place.
Commencez par exécuter la commande ci-dessous :
cargo new classroom_sqlx --bin
Ajoutez ensuite les dépendances requises au cargo.toml
fichier :
[dependencies]
sqlx = { version = "0.5", features = [ "runtime-async-std-native-tls", "mysql" ] }
async-std = { version = "1", features = [ "attributes" ] }
C'est tout ce dont vous avez besoin pour la mise en place. Simple, non ?
Pour utiliser SQLx pour interagir avec les bases de données dans Rust, tout ce que nous avons à faire est d'écrire des requêtes SQL et du code Rust. Dans la section Diesel ORM, nous avons créé et lu un dossier étudiant; dans cette section, nous allons écrire des requêtes pour mettre à jour et supprimer un enregistrement.
Tout d'abord, nous devons écrire du code Rust pour connecter SQLx au serveur MySQL :
//main.rs
use sqlx::mysql::MySqlPoolOptions;
#[async_std::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(7)
.connect("mysql://root:@localhost/classroom_diesel")
.await?;
Ok(())
}
SQLx prend en charge les requêtes SQL préparées et non préparées. Les requêtes SQL préparées sont opposées à l'injection SQL.
Voyons comment mettre à jour le prénom et le nom d'un enregistrement avec une clé primaire de 1 :
use sqlx::mysql::MySqlPoolOptions;
#[async_std::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(5)
.connect("mysql://root:@localhost/classroom_diesel")
.await?;
sqlx::query("UPDATE students SET firstname=?, lastname=? WHERE id=?")
.bind("Richard")
.bind("Roe")
.bind(1)
.execute(&pool)
.await?;
Ok(())
}
Exécutez le script avec la commande ci-dessous :
cargo run
La suppression de l'enregistrement suit également un schéma similaire ; la seule différence est la requête SQL :
use sqlx::mysql::MySqlPoolOptions;
#[async_std::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(5)
.connect("mysql://root:@localhost/classroom_diesel")
.await?;
sqlx::query("DELETE FROM students WHERE id=?")
.bind(1)
.execute(&pool)
.await?;
Ok(())
}
Exécutez le script avec la commande ci-dessous :
cargo run
Vous pouvez désormais interagir avec les bases de données dans Rust en utilisant Diesel ou SQLx.
Les ORM comme Diesel sont adéquats ; ils vous aident à générer une partie du SQL dont vous avez besoin. La plupart du temps, vous n'avez besoin que d'adéquat dans vos applications.
Cependant, cela peut prendre plus de "magie" - en d'autres termes, votre temps et vos efforts - dans des applications plus étendues pour que les ORM fonctionnent correctement et génèrent des requêtes SQL performantes.
S'il s'avère nécessaire de créer des requêtes plus complexes avec des exigences de volume élevé et de faible latence, il peut être préférable d'utiliser des bibliothèques comme SQLx pour exécuter des requêtes SQL brutes.
Source : https://blog.logrocket.com/interacting-databases-rust-diesel-vs-sqlx/
1660481280
En este tutorial, exploraremos dos bibliotecas utilizadas al interactuar con bases de datos relacionales en Rust: Diesel y SQLx.
Este artículo utilizará una base de datos de aula simple con estudiantes para demostrar cada enfoque. Realizaremos operaciones CRUD usando Diesel ORM y SQLx.
Para seguir este tutorial, necesitará un conocimiento práctico de Rust junto con la capacidad de acceder y usar Rust, el sistema de compilación de Rust y el administrador de paquetes Cargo , y una instancia de servidor MySQL.
Diesel es un ORM que soporta PostgreSQL, MySQL, SQLite. ORM significa mapeo relacional de objetos. Los ORM ayudan a los programadores orientados a objetos a abstraer los detalles de las bases de datos relacionales.
Los ORM se envían con generadores de consultas, por lo que no tiene que preocuparse por escribir consultas SQL sin formato. Con los ORM, puede comunicarse con bases de datos relacionales como si estuvieran orientadas a objetos.
Para los desarrolladores menos experimentados, el uso de ORM podría ser mejor porque los ORM crean consultas SQL optimizadas. Los ORM también lo hacen menos propenso a los ataques de inyección SQL.
A diferencia de Diesel, SQLx no es un ORM. SQLx es una caja asíncrona de Rust SQL que presenta verificaciones de consultas SQL en tiempo de compilación. Es independiente tanto de la base de datos como del tiempo de ejecución.
SQLx admite la agrupación de conexiones, el desarrollo multiplataforma, la agrupación anidada, las notificaciones asincrónicas, la seguridad de la capa de transporte y otras características interesantes. Al usar SQLx, debe crear las consultas SQL y las migraciones usted mismo.
Habiendo arañado la superficie, exploremos cómo interactuar con bases de datos relacionales con Diesel y SQLx.
Los siguientes pasos demuestran cómo configurar un proyecto de Rust con Cargo que usa Diesel ORM.
Su primer paso es inicializar el proyecto ejecutando el siguiente comando:
cargo new -- lib classroom_diesel
cd classroom_diesel
En el código anterior, configuramos el proyecto y lo llamamos classroom_diesel
. El nuevo directorio del proyecto debería verse así:
./
│
├── src/
│ └── lib.rs
│
├── .gitignore
└── Cargo.toml
También necesitamos actualizar el Cargo.toml
archivo con las dependencias que necesitamos en el proyecto, así:
[dependencies]
diesel = { version = "1.4.4", features = ["mysql"] }
dotenv = "0.15.0"
La dotenv
dependencia nos ayuda a administrar las variables de entorno en el proyecto.
Diesel usa una herramienta CLI separada . Es un binario independiente; no necesitamos agregarlo como una dependencia en el cargo.toml
archivo. Simplemente instálelo con el siguiente comando:
cargo install diesel_cli
Necesitamos establecer una DATABASE_URL
variable en nuestro entorno. Así es como Diesel sabe a qué base de datos MySQL conectarse:
echo DATABASE_URL=mysql://<username>:<password>@localhost/<database> > .env
Edite la cadena de conexión para que coincida con las credenciales de su base de datos local.
El directorio de su proyecto ahora se verá así:
./
│
├── src/
│ └── lib.rs
│
├── .env
├── .gitignore
└── Cargo.toml
Ahora ejecuta el siguiente comando:
diesel setup
Este comando nos ayudará a configurar la base de datos y crear un directorio de migraciones vacío para administrar el esquema de la base de datos.
Las migraciones ayudan al ORM a realizar un seguimiento de las operaciones de la base de datos, como agregar un campo o eliminar una tabla. Puede pensar en ellos como un sistema de control de versiones para su base de datos.
Primero, creemos algunas migraciones para la aplicación del salón de clases usando Diesel CLI. Idealmente, deberíamos tener una tabla que contenga datos sobre los estudiantes del salón de clases.
Necesitamos crear archivos de migración vacíos, luego llenarlos con SQL para crear una tabla.
diesel migration generate create_students
Su árbol de archivos se verá similar a esto:
./
│
├── migrations/
│ │
│ ├── 2022-07-04-062521_create_students/
│ │ ├── down.sql
│ │ └── up.sql
│ │
│ └── .gitkeep
│
├── src/
│ └── lib.rs
│
├── .env
├── .gitignore
├── Cargo.toml
└── diesel.toml
El up.sql
archivo es para crear una migración, mientras que el down.sql
archivo es para revertirla.
Actualice el up.sql
archivo con el SQL para la migración:
sql
CREATE TABLE students (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
firstname VARCHAR(255) NOT NULL,
lastname TEXT NOT NULL,
age INTEGER NOT NULL
);
Modifique el down.sql
archivo con SQL que puede revertir la migración:
sql
DROP TABLE students;
Después de crear las up
migraciones down
, necesitamos ejecutar el SQL en la base de datos:
diesel migration run
Podemos comenzar a escribir Rust para realizar consultas en la tabla.
Escribamos código para establecer una conexión con el servidor MySQL utilizando la cadena de conexión establecida en el .env
archivo.
#[macro_use]
extern crate diesel;
extern crate dotenv;
pub mod models;
pub mod schema;
use diesel::prelude::*;
use dotenv::dotenv;
use std::env;
pub fn create_connection() -> MysqlConnection {
dotenv().ok();
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
MysqlConnection::establish(&database_url)
.unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
}
A continuación, debemos escribir un modelo para la Students
tabla. Los modelos son donde tiene lugar el mapeo relacional de objetos. El modelo generará el código necesario para convertir una fila o filas de la Students
tabla en una Student
estructura en Rust .
cd ./src
touch model.rs
En el nuevo model.rs
archivo que acabamos de crear, agregue lo siguiente:
use super::schema::students;
#[derive(Queryable)]
pub struct Student {
pub id: i32,
pub firstname: String,
pub lastname: String,
pub age: i32,
}
#[derive(Insertable)]
#[table_name = "students"]
pub struct NewStudent<'a> {
pub firstname: &'a str,
pub lastname: &'a str,
pub age: &'a i32,
}
Con este modelo, la información de la Students
tabla se asignará a la estructura correspondiente Student
en Rust. La src
carpeta ahora debería verse así:
src/
├── lib.rs
├── models.rs
└── schema.rs
Ahora, podemos escribir un script para agregar un estudiante:
cd src mkdir bin cd bin touch create_students.rs
En el create_students.rs
archivo, podemos invocar los modelos y funciones escritos anteriormente para crear un nuevo estudiante:
extern crate classroom_diesel;
extern crate diesel;
use self::classroom_diesel::*;
fn main() {
let connection = create_connection();
let firstname = "John";
let lastname = "Doe";
let age: i32 = 64;
let student = create_post(&connection, firstname, lastname, &age);
println!(
"Saved student {} with id {}",
student.firstname, student.id
);
}
La estructura del proyecto ahora se verá similar a esto:
./
│
├── migrations/
│ │
│ ├── 2022-07-04-062521_create_students/
│ │ ├── down.sql
│ │ └── up.sql
│ │
│ └── .gitkeep
│
├── src/
│ │
│ ├── bin/
│ │ └── create_students.rs
│ │
│ ├── lib.rs
│ ├── models.rs
│ └── schema.rs
│
├── .env
├── .gitignore
├── Cargo.lock
├── Cargo.toml
└── diesel.toml
Ejecute el nuevo script usando el siguiente comando:
cargo run --bin create_students
Como puede ver en la imagen a continuación, el nuevo archivo de estudiante John
se ha guardado con una extensión id
de 1
. Podemos usar esto id
para consultar las bases de datos de Rust, que veremos en la siguiente sección.
En la sección anterior, revisamos cómo escribir en la base de datos en Rust usando Diesel ORM. También es esencial comprender cómo funciona la consulta o la lectura.
Escribamos un script para consultar a un estudiante cuyo id
es 1
. Comience creando un query_students.rs
archivo:
cd bin
touch query_students.rs
Luego, en el query_students.rs
archivo que acabamos de crear, agregue lo siguiente:
extern crate classroom_diesel;
extern crate diesel;
use self::models::*;
use classroom_diesel::*;
use diesel::prelude::*;
fn main() {
use self::schema::students::dsl::*;
let connection = create_connection();
let result = students
.filter(id.eq(1))
.load::<Student>(&connection)
.expect("Error loading students");
println!(
"Student: {} {} {} years",
result[0].firstname, result[0].lastname, result[0].age
);
}
Ejecute el script:
cargo run --bin query_students
Como puede ver en la imagen a continuación, el resultado es una línea impresa que contiene el nombre, el apellido y la edad del archivo del estudiante que consultamos en la base de datos:
Ahora que sabemos cómo crear un proyecto que use Diesel ORM para interactuar con bases de datos en Rust, echemos un vistazo a cómo crear un proyecto que use SQLx en su lugar.
Comience ejecutando el siguiente comando:
cargo new classroom_sqlx --bin
Luego, agregue las dependencias requeridas al cargo.toml
archivo:
[dependencies]
sqlx = { version = "0.5", features = [ "runtime-async-std-native-tls", "mysql" ] }
async-std = { version = "1", features = [ "attributes" ] }
Eso es todo lo que necesita con respecto a la configuración. Sencillo, ¿verdad?
Para usar SQLx para interactuar con bases de datos en Rust, todo lo que tenemos que hacer es escribir algunas consultas SQL y código Rust. En la sección Diesel ORM, creamos y leímos un registro de estudiante; en esta sección, escribiremos consultas para actualizar y eliminar un registro.
Primero, necesitamos escribir algo de código Rust para conectar SQLx al servidor MySQL:
//main.rs
use sqlx::mysql::MySqlPoolOptions;
#[async_std::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(7)
.connect("mysql://root:@localhost/classroom_diesel")
.await?;
Ok(())
}
SQLx admite consultas SQL preparadas y no preparadas. Las consultas SQL preparadas son reacias a la inyección de SQL.
Veamos cómo actualizar el nombre y apellido de un registro con una clave principal de 1:
use sqlx::mysql::MySqlPoolOptions;
#[async_std::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(5)
.connect("mysql://root:@localhost/classroom_diesel")
.await?;
sqlx::query("UPDATE students SET firstname=?, lastname=? WHERE id=?")
.bind("Richard")
.bind("Roe")
.bind(1)
.execute(&pool)
.await?;
Ok(())
}
Ejecute el script con el siguiente comando:
cargo run
Eliminar el registro también sigue un patrón similar; la única diferencia es la consulta SQL:
use sqlx::mysql::MySqlPoolOptions;
#[async_std::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(5)
.connect("mysql://root:@localhost/classroom_diesel")
.await?;
sqlx::query("DELETE FROM students WHERE id=?")
.bind(1)
.execute(&pool)
.await?;
Ok(())
}
Ejecute el script con el siguiente comando:
cargo run
Ahora puede interactuar con bases de datos en Rust utilizando Diesel o SQLx.
Los ORM como Diesel son adecuados; lo ayudan a generar parte del SQL que necesita. La mayoría de las veces, adecuado es todo lo que necesita en sus aplicaciones.
Sin embargo, puede tomar más "magia", en otras palabras, su tiempo y esfuerzo, en aplicaciones más extensas para que los ORM funcionen correctamente y generen consultas SQL de alto rendimiento.
Si surge la necesidad de crear consultas más complicadas con requisitos de alto volumen y baja latencia, puede ser mejor usar bibliotecas como SQLx para ejecutar consultas SQL sin formato.
Fuente: https://blog.logrocket.com/interacting-databases-rust-diesel-vs-sqlx/
1660477560
このチュートリアルでは、Rust でリレーショナル データベースを操作するときに使用される 2 つのライブラリ、Diesel と SQLx について説明します。
この記事では、学生と一緒に簡単な教室データベースを使用して、各アプローチを示します。Diesel ORM と SQLx を使用して CRUD 操作を実行します。
このチュートリアルを進めるには、Rust の実用的な知識と、Rust、 Rust のビルド システムおよびパッケージ マネージャーである Cargo、および MySQL サーバー インスタンスにアクセスして使用する能力が必要です。
Diesel は、PostgreSQL、MySQL、SQLite をサポートする ORM です。ORM は、オブジェクト リレーショナル マッピングの略です。ORM は、オブジェクト指向プログラマーがリレーショナル データベースの詳細を抽象化するのに役立ちます。
ORM にはクエリ ビルダーが同梱されているため、未加工の SQL クエリの記述について心配する必要はありません。ORM を使用すると、オブジェクト指向であるかのようにリレーショナル データベースと通信できます。
ORM は最適化された SQL クエリを作成するため、経験の浅い開発者にとっては、ORM を使用する方がよい場合があります。また、ORM を使用すると、SQL インジェクション攻撃を受けにくくなります。
Diesel とは異なり、SQLx は ORM ではありません。SQLx は、コンパイル時の SQL クエリ チェックを特徴とする非同期 Rust SQL クレートです。データベースとランタイムの両方に依存しません。
SQLx は、接続プーリング、クロスプラットフォーム開発、ネストされたプーリング、非同期通知、トランスポート層セキュリティ、およびその他の優れた機能をサポートしています。SQLx を使用する場合、SQL クエリと移行を自分で作成する必要があります。
表面をなぞったところで、Diesel と SQLx を使用してリレーショナル データベースを操作する方法を見ていきましょう。
次の手順は、Diesel ORM を使用する Cargo で Rust プロジェクトをセットアップする方法を示しています。
最初のステップは、次のコマンドを実行してプロジェクトを初期化することです。
cargo new -- lib classroom_diesel
cd classroom_diesel
上記のコードでは、プロジェクトをセットアップして名前を付けましたclassroom_diesel
。新しいプロジェクト ディレクトリは次のようになります。
./
│
├── src/
│ └── lib.rs
│
├── .gitignore
└── Cargo.toml
Cargo.toml
次のように、プロジェクトで必要な依存関係でファイルを更新する必要もあります。
[dependencies]
diesel = { version = "1.4.4", features = ["mysql"] }
dotenv = "0.15.0"
依存関係は、プロジェクトで環境変数を管理するのdotenv
に役立ちます。
Diesel は別の CLI ツールを使用します。これはスタンドアロンのバイナリです。ファイルに依存関係として追加する必要はありませんcargo.toml
。以下のコマンドで簡単にインストールできます。
cargo install diesel_cli
DATABASE_URL
環境に変数を設定する必要があります。これは、どの MySQL データベースに接続するかを Diesel が認識する方法です。
echo DATABASE_URL=mysql://<username>:<password>@localhost/<database> > .env
ローカル データベースの資格情報と一致するように接続文字列を編集します。
プロジェクト ディレクトリは次のようになります。
./
│
├── src/
│ └── lib.rs
│
├── .env
├── .gitignore
└── Cargo.toml
次のコマンドを実行します。
diesel setup
このコマンドは、データベースをセットアップし、データベース スキーマを管理するための空の移行ディレクトリを作成するのに役立ちます。
移行は、ORM がフィールドの追加やテーブルの削除などのデータベース操作を追跡するのに役立ちます。データベースのバージョン管理システムと考えることができます。
まず、Diesel CLI を使用してクラスルーム アプリケーションの移行をいくつか作成しましょう。理想的には、教室の生徒に関するデータを含むテーブルが必要です。
空の移行ファイルを作成し、それらに SQL を入力してテーブルを作成する必要があります。
diesel migration generate create_students
ファイル ツリーは次のようになります。
./
│
├── migrations/
│ │
│ ├── 2022-07-04-062521_create_students/
│ │ ├── down.sql
│ │ └── up.sql
│ │
│ └── .gitkeep
│
├── src/
│ └── lib.rs
│
├── .env
├── .gitignore
├── Cargo.toml
└── diesel.toml
up.sql
ファイルは移行を作成するためのもので、ファイルdown.sql
はそれを元に戻すためのものです。
up.sql
移行用の SQL でファイルを更新します。
sql
CREATE TABLE students (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
firstname VARCHAR(255) NOT NULL,
lastname TEXT NOT NULL,
age INTEGER NOT NULL
);
down.sql
移行を元に戻すことができる SQL でファイルを変更します。
sql
DROP TABLE students;
up
とdown
移行を作成したら、データベースで SQL を実行する必要があります。
diesel migration run
Rust を書き始めて、テーブルに対してクエリを実行できます。
.env
ファイルに設定された接続文字列を使用して、MySQL サーバーへの接続を確立するコードを書きましょう。
#[macro_use]
extern crate diesel;
extern crate dotenv;
pub mod models;
pub mod schema;
use diesel::prelude::*;
use dotenv::dotenv;
use std::env;
pub fn create_connection() -> MysqlConnection {
dotenv().ok();
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
MysqlConnection::establish(&database_url)
.unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
}
次に、Students
テーブルのモデルを作成する必要があります。モデルは、オブジェクト リレーショナル マッピングが行われる場所です。Students
モデルは、テーブルの 1 つまたは複数の行をStudent
Rust の構造体に変換するために必要なコードを生成します。
cd ./src
touch model.rs
作成したばかりの新しいmodel.rs
ファイルに、次を追加します。
use super::schema::students;
#[derive(Queryable)]
pub struct Student {
pub id: i32,
pub firstname: String,
pub lastname: String,
pub age: i32,
}
#[derive(Insertable)]
#[table_name = "students"]
pub struct NewStudent<'a> {
pub firstname: &'a str,
pub lastname: &'a str,
pub age: &'a i32,
}
このモデルでは、テーブルからの情報が RustStudents
の対応する構造体にマップされます。Student
フォルダは次のsrc
ようになります。
src/
├── lib.rs
├── models.rs
└── schema.rs
これで、生徒を追加するスクリプトを作成できます。
cd src mkdir bin cd bin touch create_students.rs
このcreate_students.rs
ファイルでは、以前に作成したモデルと関数を呼び出して、新しい生徒を作成できます。
extern crate classroom_diesel;
extern crate diesel;
use self::classroom_diesel::*;
fn main() {
let connection = create_connection();
let firstname = "John";
let lastname = "Doe";
let age: i32 = 64;
let student = create_post(&connection, firstname, lastname, &age);
println!(
"Saved student {} with id {}",
student.firstname, student.id
);
}
プロジェクトの構造は次のようになります。
./
│
├── migrations/
│ │
│ ├── 2022-07-04-062521_create_students/
│ │ ├── down.sql
│ │ └── up.sql
│ │
│ └── .gitkeep
│
├── src/
│ │
│ ├── bin/
│ │ └── create_students.rs
│ │
│ ├── lib.rs
│ ├── models.rs
│ └── schema.rs
│
├── .env
├── .gitignore
├── Cargo.lock
├── Cargo.toml
└── diesel.toml
次のコマンドを使用して、新しいスクリプトを実行します。
cargo run --bin create_students
下の画像でわかるように、 の新しい学生ファイルJohn
は. これを使用して Rust データベースにクエリを実行できます。これについては、次のセクションで説明します。id1id
前のセクションでは、Diesel ORM を使用して Rust でデータベースに書き込む方法を確認しました。また、クエリまたは読み取りがどのように機能するかを理解することも不可欠です。
id
が である学生にクエリを実行するスクリプトを作成しましょう1
。query_students.rs
ファイルの作成から始めます。
cd bin
touch query_students.rs
次に、query_students.rs
作成したばかりのファイルに次を追加します。
extern crate classroom_diesel;
extern crate diesel;
use self::models::*;
use classroom_diesel::*;
use diesel::prelude::*;
fn main() {
use self::schema::students::dsl::*;
let connection = create_connection();
let result = students
.filter(id.eq(1))
.load::<Student>(&connection)
.expect("Error loading students");
println!(
"Student: {} {} {} years",
result[0].firstname, result[0].lastname, result[0].age
);
}
スクリプトを実行します。
cargo run --bin query_students
下の画像でわかるように、結果は、データベースからクエリした学生ファイルの名、姓、および年齢を含む出力行です。
Diesel ORM を使用して Rust のデータベースと対話するプロジェクトを作成する方法がわかったので、代わりに SQLx を使用するプロジェクトを作成する方法を見てみましょう。
以下のコマンドを実行して開始します。
cargo new classroom_sqlx --bin
次に、必要な依存関係をcargo.toml
ファイルに追加します。
[dependencies]
sqlx = { version = "0.5", features = [ "runtime-async-std-native-tls", "mysql" ] }
async-std = { version = "1", features = [ "attributes" ] }
セットアップに関して必要なのはこれだけです。シンプルですね。
SQLx を使用して Rust のデータベースと対話するには、いくつかの SQL クエリと Rust コードを記述するだけです。Diesel ORM セクションでは、生徒の記録を作成して読み取りました。このセクションでは、レコードを更新および削除するためのクエリを記述します。
まず、SQLx を MySQL サーバーに接続するための Rust コードを書く必要があります。
//main.rs
use sqlx::mysql::MySqlPoolOptions;
#[async_std::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(7)
.connect("mysql://root:@localhost/classroom_diesel")
.await?;
Ok(())
}
SQLx は、準備された SQL クエリと準備されていない SQL クエリの両方をサポートしています。準備された SQL クエリは、SQL インジェクションを嫌います。
主キーが 1 のレコードの姓名を更新する方法を見てみましょう。
use sqlx::mysql::MySqlPoolOptions;
#[async_std::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(5)
.connect("mysql://root:@localhost/classroom_diesel")
.await?;
sqlx::query("UPDATE students SET firstname=?, lastname=? WHERE id=?")
.bind("Richard")
.bind("Roe")
.bind(1)
.execute(&pool)
.await?;
Ok(())
}
以下のコマンドでスクリプトを実行します。
cargo run
レコードの削除も同様のパターンを取ります。唯一の違いは SQL クエリです。
use sqlx::mysql::MySqlPoolOptions;
#[async_std::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(5)
.connect("mysql://root:@localhost/classroom_diesel")
.await?;
sqlx::query("DELETE FROM students WHERE id=?")
.bind(1)
.execute(&pool)
.await?;
Ok(())
}
以下のコマンドでスクリプトを実行します。
cargo run
これで、Diesel または SQLx のいずれかを使用して、Rust のデータベースと対話できます。
Diesel のような ORM で十分です。これらは、必要な SQL の一部を生成するのに役立ちます。ほとんどの場合、アプリケーションで必要なのは十分です。
ただし、より大規模なアプリケーションで ORM を正しく機能させ、パフォーマンスの高い SQL クエリを生成するには、より多くの「魔法」、つまり時間と労力が必要になる場合があります。
大量かつ低レイテンシの要件を持つより複雑なクエリを作成する必要が生じた場合は、SQLx などのライブラリを使用して生の SQL クエリを実行する方がよい場合があります。
ソース: https://blog.logrocket.com/interacting-databases-rust-diesel-vs-sqlx/
1660477440
Trong hướng dẫn này, chúng ta sẽ khám phá hai thư viện được sử dụng khi tương tác với cơ sở dữ liệu quan hệ trong Rust: Diesel và SQLx.
Bài viết này sẽ sử dụng một cơ sở dữ liệu lớp học đơn giản với học sinh để chứng minh từng cách tiếp cận. Chúng tôi sẽ thực hiện các hoạt động CRUD bằng Diesel ORM và SQLx.
Để làm theo hướng dẫn này, bạn sẽ cần có kiến thức làm việc về Rust cùng với khả năng truy cập và sử dụng Rust, hệ thống xây dựng của Rust và trình quản lý gói Cargo , và một phiên bản máy chủ MySQL.
Diesel là một ORM hỗ trợ PostgreSQL, MySQL, SQLite. ORM là viết tắt của ánh xạ quan hệ đối tượng. ORM giúp các lập trình viên hướng đối tượng tóm tắt các chi tiết của cơ sở dữ liệu quan hệ.
ORM được vận chuyển cùng với các trình tạo truy vấn, vì vậy bạn không phải lo lắng về việc viết các truy vấn SQL thô. Sử dụng ORM, bạn có thể giao tiếp với cơ sở dữ liệu quan hệ như thể chúng là hướng đối tượng.
Đối với các nhà phát triển ít kinh nghiệm, sử dụng ORM có thể tốt hơn vì ORM tạo ra các truy vấn SQL được tối ưu hóa. ORM cũng giúp bạn ít bị tấn công SQL injection hơn.
Không giống như Diesel, SQLx không phải là ORM. SQLx là thùng SQL Rust không đồng bộ có tính năng kiểm tra truy vấn SQL thời gian biên dịch. Nó vừa là cơ sở dữ liệu - vừa là bất khả tri thời gian chạy.
SQLx hỗ trợ gộp kết nối, phát triển đa nền tảng, gộp lồng nhau, thông báo không đồng bộ, bảo mật lớp truyền tải và các tính năng thú vị khác. Khi sử dụng SQLx, bạn phải tự tạo các truy vấn SQL và di chuyển.
Sau khi hoàn thành bề mặt, chúng ta hãy khám phá cách tương tác với cơ sở dữ liệu quan hệ với Diesel và SQLx.
Các bước sau đây trình bày cách thiết lập dự án Rust với Cargo sử dụng Diesel ORM.
Bước đầu tiên của bạn là khởi tạo dự án bằng cách chạy lệnh sau:
cargo new -- lib classroom_diesel
cd classroom_diesel
Trong đoạn mã trên, chúng tôi thiết lập dự án và đặt tên cho nó classroom_diesel
. Thư mục dự án mới sẽ giống như sau:
./
│
├── src/
│ └── lib.rs
│
├── .gitignore
└── Cargo.toml
Chúng tôi cũng cần cập nhật Cargo.toml
tệp với các phụ thuộc chúng tôi cần trong dự án, như sau:
[dependencies]
diesel = { version = "1.4.4", features = ["mysql"] }
dotenv = "0.15.0"
Sự dotenv
phụ thuộc giúp chúng ta quản lý các biến môi trường trong dự án.
Diesel sử dụng một công cụ CLI riêng biệt . Nó là một nhị phân độc lập; chúng tôi không cần phải thêm nó như một phụ thuộc trong cargo.toml
tệp. Chỉ cần cài đặt nó bằng lệnh dưới đây:
cargo install diesel_cli
Chúng ta cần thiết lập một DATABASE_URL
biến trong môi trường của chúng ta. Đây là cách Diesel biết cơ sở dữ liệu MySQL nào cần kết nối:
echo DATABASE_URL=mysql://<username>:<password>@localhost/<database> > .env
Chỉnh sửa chuỗi kết nối để khớp với thông tin đăng nhập cơ sở dữ liệu cục bộ của bạn.
Thư mục dự án của bạn bây giờ sẽ giống như sau:
./
│
├── src/
│ └── lib.rs
│
├── .env
├── .gitignore
└── Cargo.toml
Bây giờ hãy chạy lệnh sau:
diesel setup
Lệnh này sẽ giúp chúng ta thiết lập cơ sở dữ liệu và tạo một thư mục di chuyển trống để quản lý lược đồ cơ sở dữ liệu.
Di chuyển giúp ORM theo dõi các hoạt động của cơ sở dữ liệu, chẳng hạn như thêm trường hoặc xóa bảng. Bạn có thể coi chúng như một hệ thống kiểm soát phiên bản cho cơ sở dữ liệu của mình.
Đầu tiên, hãy tạo một số chuyển đổi cho ứng dụng lớp học bằng Diesel CLI. Tốt nhất, chúng ta nên có một bảng chứa dữ liệu về học sinh trong lớp.
Chúng ta cần tạo các tệp di chuyển trống, sau đó điền chúng bằng SQL để tạo bảng.
diesel migration generate create_students
Cây tệp của bạn sẽ trông giống như sau:
./
│
├── migrations/
│ │
│ ├── 2022-07-04-062521_create_students/
│ │ ├── down.sql
│ │ └── up.sql
│ │
│ └── .gitkeep
│
├── src/
│ └── lib.rs
│
├── .env
├── .gitignore
├── Cargo.toml
└── diesel.toml
Tệp up.sql
là để tạo quá trình di chuyển, trong khi down.sql
tệp dùng để đảo ngược nó.
Cập nhật up.sql
tệp bằng SQL để di chuyển:
sql
CREATE TABLE students (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
firstname VARCHAR(255) NOT NULL,
lastname TEXT NOT NULL,
age INTEGER NOT NULL
);
Sửa đổi down.sql
tệp bằng SQL có thể đảo ngược quá trình di chuyển:
sql
DROP TABLE students;
Sau khi tạo up
và down
di chuyển, chúng ta cần thực thi SQL trên cơ sở dữ liệu:
diesel migration run
Chúng ta có thể bắt đầu viết Rust để thực hiện các truy vấn trên bảng.
Hãy viết mã để thiết lập kết nối đến máy chủ MySQL bằng cách sử dụng chuỗi kết nối được đặt trong .env
tệp.
#[macro_use]
extern crate diesel;
extern crate dotenv;
pub mod models;
pub mod schema;
use diesel::prelude::*;
use dotenv::dotenv;
use std::env;
pub fn create_connection() -> MysqlConnection {
dotenv().ok();
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
MysqlConnection::establish(&database_url)
.unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
}
Tiếp theo, chúng ta phải viết một mô hình cho Students
bảng. Mô hình là nơi diễn ra ánh xạ quan hệ đối tượng. Mô hình sẽ tạo ra mã cần thiết để chuyển đổi một hàng hoặc các hàng trên Students
bảng thành một Student
cấu trúc trong Rust .
cd ./src
touch model.rs
Trong model.rs
tệp mới mà chúng tôi vừa tạo, hãy thêm thông tin sau:
use super::schema::students;
#[derive(Queryable)]
pub struct Student {
pub id: i32,
pub firstname: String,
pub lastname: String,
pub age: i32,
}
#[derive(Insertable)]
#[table_name = "students"]
pub struct NewStudent<'a> {
pub firstname: &'a str,
pub lastname: &'a str,
pub age: &'a i32,
}
Với mô hình này, thông tin từ Students
bảng sẽ ánh xạ tới Student
cấu trúc tương ứng trong Rust. Thư src
mục bây giờ sẽ trông như thế này:
src/
├── lib.rs
├── models.rs
└── schema.rs
Bây giờ, chúng ta có thể viết một tập lệnh để thêm một sinh viên:
cd src mkdir bin cd bin touch create_students.rs
Trong create_students.rs
tệp, chúng ta có thể gọi các mô hình và hàm đã viết trước đó để tạo một sinh viên mới:
extern crate classroom_diesel;
extern crate diesel;
use self::classroom_diesel::*;
fn main() {
let connection = create_connection();
let firstname = "John";
let lastname = "Doe";
let age: i32 = 64;
let student = create_post(&connection, firstname, lastname, &age);
println!(
"Saved student {} with id {}",
student.firstname, student.id
);
}
Cấu trúc của dự án bây giờ sẽ giống như sau:
./
│
├── migrations/
│ │
│ ├── 2022-07-04-062521_create_students/
│ │ ├── down.sql
│ │ └── up.sql
│ │
│ └── .gitkeep
│
├── src/
│ │
│ ├── bin/
│ │ └── create_students.rs
│ │
│ ├── lib.rs
│ ├── models.rs
│ └── schema.rs
│
├── .env
├── .gitignore
├── Cargo.lock
├── Cargo.toml
└── diesel.toml
Thực thi tập lệnh mới bằng lệnh sau:
cargo run --bin create_students
Như bạn có thể thấy trong hình ảnh bên dưới, tệp sinh viên mới cho John
đã được lưu id
với 1
. Chúng ta có thể sử dụng điều này id
để truy vấn cơ sở dữ liệu Rust, chúng ta sẽ xem xét trong phần tiếp theo.
Trong phần trước, chúng ta đã xem xét cách ghi vào cơ sở dữ liệu trong Rust bằng Diesel ORM. Nó cũng rất cần thiết để hiểu cách hoạt động của truy vấn hoặc đọc.
Hãy viết một kịch bản để truy vấn một sinh viên id
có 1
. Bắt đầu bằng cách tạo một query_students.rs
tệp:
cd bin
touch query_students.rs
Sau đó, trong query_students.rs
tệp chúng tôi vừa tạo, thêm thông tin sau:
extern crate classroom_diesel;
extern crate diesel;
use self::models::*;
use classroom_diesel::*;
use diesel::prelude::*;
fn main() {
use self::schema::students::dsl::*;
let connection = create_connection();
let result = students
.filter(id.eq(1))
.load::<Student>(&connection)
.expect("Error loading students");
println!(
"Student: {} {} {} years",
result[0].firstname, result[0].lastname, result[0].age
);
}
Thực thi tập lệnh:
cargo run --bin query_students
Như bạn có thể thấy trong hình dưới đây, kết quả là một dòng in chứa tên, họ và tuổi của tệp sinh viên mà chúng tôi đã truy vấn từ cơ sở dữ liệu:
Bây giờ chúng ta đã biết cách tạo một dự án sử dụng Diesel ORM để tương tác với cơ sở dữ liệu trong Rust, chúng ta hãy xem cách tạo một dự án sử dụng SQLx.
Bắt đầu bằng cách chạy lệnh dưới đây:
cargo new classroom_sqlx --bin
Sau đó, thêm các phụ thuộc bắt buộc vào cargo.toml
tệp:
[dependencies]
sqlx = { version = "0.5", features = [ "runtime-async-std-native-tls", "mysql" ] }
async-std = { version = "1", features = [ "attributes" ] }
Đó là tất cả những gì bạn cần liên quan đến việc thiết lập. Đơn giản, phải không?
Để sử dụng SQLx để tương tác với cơ sở dữ liệu trong Rust, tất cả những gì chúng ta phải làm là viết một số truy vấn SQL và mã Rust. Trong phần Diesel ORM, chúng tôi đã tạo và đọc hồ sơ học sinh; trong phần này, chúng tôi sẽ viết các truy vấn để cập nhật và xóa một bản ghi.
Đầu tiên, chúng ta cần viết một số mã Rust để kết nối SQLx với máy chủ MySQL:
//main.rs
use sqlx::mysql::MySqlPoolOptions;
#[async_std::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(7)
.connect("mysql://root:@localhost/classroom_diesel")
.await?;
Ok(())
}
SQLx hỗ trợ cả truy vấn SQL chuẩn bị và chưa chuẩn bị. Các truy vấn SQL chuẩn bị không thích với SQL injection.
Hãy xem cách cập nhật họ và tên của bản ghi có khóa chính là 1:
use sqlx::mysql::MySqlPoolOptions;
#[async_std::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(5)
.connect("mysql://root:@localhost/classroom_diesel")
.await?;
sqlx::query("UPDATE students SET firstname=?, lastname=? WHERE id=?")
.bind("Richard")
.bind("Roe")
.bind(1)
.execute(&pool)
.await?;
Ok(())
}
Thực thi tập lệnh bằng lệnh dưới đây:
cargo run
Xóa bản ghi cũng có một mô hình tương tự; sự khác biệt duy nhất là truy vấn SQL:
use sqlx::mysql::MySqlPoolOptions;
#[async_std::main]
async fn main() -> Result<(), sqlx::Error> {
let pool = MySqlPoolOptions::new()
.max_connections(5)
.connect("mysql://root:@localhost/classroom_diesel")
.await?;
sqlx::query("DELETE FROM students WHERE id=?")
.bind(1)
.execute(&pool)
.await?;
Ok(())
}
Thực thi tập lệnh bằng lệnh dưới đây:
cargo run
Giờ đây, bạn có thể tương tác với cơ sở dữ liệu trong Rust bằng cách sử dụng Diesel hoặc SQLx.
ORM như Diesel là phù hợp; chúng giúp bạn tạo ra một số SQL mà bạn cần. Hầu hết thời gian, đầy đủ là tất cả những gì bạn cần trong các ứng dụng của mình.
Tuy nhiên, có thể cần nhiều “ma thuật” hơn - nói cách khác là thời gian và nỗ lực của bạn - trong các ứng dụng mở rộng hơn để các ORM hoạt động chính xác và tạo ra các truy vấn SQL hiệu quả.
Nếu phát sinh nhu cầu tạo các truy vấn phức tạp hơn với yêu cầu về khối lượng lớn và độ trễ thấp, có thể tốt hơn là sử dụng các thư viện như SQLx để thực thi các truy vấn SQL thô.
Nguồn: https://blog.logrocket.com/interactive-databases-rust-diesel-vs-sqlx/
1660450140
ShareDB is a realtime database backend based on Operational Transformation (OT) of JSON documents. It is the realtime backend for the DerbyJS web application framework.
For help, questions, discussion and announcements, join the ShareJS mailing list or read the documentation.
Please report any bugs you find to the issue tracker.
The documentation is stored as Markdown files, but sometimes it can be useful to run these locally. The docs are served using Jekyll, and require Ruby >2.4.0 and Bundler:
gem install jekyll bundler
The docs can be built locally and served with live reload:
npm run docs:install
npm run docs:start
https://share.github.io/sharedb/
Author: Share
Source Code: https://github.com/share/sharedb
License: View license
1660438800
In this tutorial, we’ll explore two libraries used when interacting with relational databases in Rust: Diesel and SQLx.
This article will use a simple classroom database with students to demonstrate each approach. We’ll perform CRUD operations using Diesel ORM and SQLx.
See more at: https://blog.logrocket.com/interacting-databases-rust-diesel-vs-sqlx/
1660332960
Install-Package StringDB
StringDB is a key/value pair store with a friendly API to use as little RAM and space as possible.
Verify the claims for yourself:
Enumerate over a database and it's values, the fastest, by enumerating over it optimally
using var db = new DatabaseBuilder()
.UseIODatabase(StringDBVersion.Latest, "database.db", out var optimalTokenSource)
.WithBuffer(1000)
.WithTranform(StringTransformation.Default, StringTransformation.Default);
foreach (var (key, value) in db.EnumerateOptimally(optimalTokenSource))
{
// do something with the key and value
}
Use fluent extensions to create a database:
using IDatabase<string, string> db = new DatabaseBuilder()
.UseIODatabase(StringDBVersion.Latest, "database.db")
.WithBuffer(1000)
.WithTransform(StringTransformation.Default, StringTransformation.Default);
using IDatabase<int, string> memDb = new DatabaseBuilder()
.UseMemoryDatabase<int, string>();
Use the IDatabase interface to interface with databases
void InsertGreeting(IDatabase<string, string> database, string user)
{
database.Insert(user, $"Greetings, {user}!");
}
And inherit BaseDatabase to create your own IDatabases with minimal effort
public class TestDatabase : BaseDatabase<int, string>
{
private class LazyValue : ILazyLoader<string>
{
private readonly string _value;
public LazyValue(int value) => _value = value.ToString();
public string Load() => _value;
public void Dispose() {}
}
public override void Dispose() {}
protected override void InsertRange(KeyValuePair<int, string>[] items)
{
foreach(var item in items)
{
Console.WriteLine($"{item.Key}: {item.Value}");
}
}
protected override IEnumerable<KeyValuePair<int, ILazyLoader<string>>> Evaluate()
{
for(var i = 0; i < int.MaxValue)
{
yield return KeyValuePair.Create(i, new LazyValue(i));
}
}
}
StringDB is tiny. Use tiny amounts of RAM, and tiny amounts of space.
Inserts | Size (in KB, 1000 bytes) | Absolute Minimum Size Possible | StringDB Overhead Percentage |
---|---|---|---|
1 | 1.172 KB | 1.152 KB | 1.706485% |
50 | 58.208 KB | 57.6 KB | 1.04453% |
100 | 116.408 KB | 115.2 KB | 1.037729% |
This chart shows the size of a StringDB file after multiple single inserts. Every key is 128 bytes long, and every value is 1024 bytes long. By doing single inserts, file size is dramatically affected due to the additional overhead for the index chain.
Elements in Insert Range | Size (in KB, 1000 bytes) | Absolute Minimum Size Possible | StringDB Overhead Percentage |
---|---|---|---|
1 | 1.172 KB | 1.152 KB | 1.706485% |
50 | 57.963 KB | 57.6 KB | 0.626262% |
100 | 115.913 KB | 115.2 KB | 0.615117% |
This chart shows the size of a StringDB file after a single insert range with the amount of items specified.
Official addon support will be maintained for these libraries.
Don't be afraid to make an issue about anything and everything!
It's an honour to have you use this library, and feedback is needed to make this the greatest it can be.
Need immediate assistence? Join the discord!
Author: SirJosh3917
Source code: https://github.com/SirJosh3917/StringDB
License: MIT license
#dotnet #aps.net #csharp #database
1660331580
The rpostgis
package provides an interface between R and PostGIS
-enabled PostgreSQL
databases to transparently transfer spatial data. Both vector (points, lines, polygons) and raster data are supported in read and write modes. Also provides convenience functions to execute common procedures in PostgreSQL
/PostGIS
.
You can install the latest released version from CRAN:
install.packages("rpostgis")
You can then use update.packages()
to update to the latest CRAN version.
A stable version of the package is always available on the project's GitHub page, and may be ahead of the CRAN version. To install it, use the remotes
:
remotes::install_github("mablab/rpostgis")
For the latest (possibly unstable) development version, use:
remotes::install_github("mablab/rpostgis", ref = "dev")
rpostgis
relies on a working connection provided by the RPostgreSQL
package to a PostgreSQL database, e.g.:
conn <- RPostgreSQL::dbConnect("PostgreSQL", host = "localhost",
dbname = "<DB_NAME>", user = "<USER>", password = "<PASSWORD>")
Note: as of
rpostgis 1.4.3
theRPostgres::Postgres()
driver is also allowed for connection objects; however, this should be considered experimental and is not recommended for most use cases.
Once the connection is established, the first step is to check if the database has PostGIS
already installed (and install it if it's not the case):
pgPostGIS(conn)
If the function returns TRUE
, the database is ready and functional. You can check the geometries and rasters present in the database with:
pgListGeom(conn, geog = TRUE)
pgListRast(conn)
To terminate the session, close and clear the connection with:
RPostgreSQL::dbDisconnect(conn)
Full documentation with the complete list of functions of the package can be found on rpostgis
homepage.
Author: mablab
Source Code: https://github.com/mablab/rpostgis
1660325340
.NET Transactional Document DB and Event Store on PostgreSQL
The Marten library provides .NET developers with the ability to use the proven PostgreSQL database engine and its fantastic JSON support as a fully fledged document database. The Marten team believes that a document database has far reaching benefits for developer productivity over relational databases with or without an ORM tool.
Marten also provides .NET developers with an ACID-compliant event store with user-defined projections against event streams.
Access docs here and v3.x docs here.
Before getting started you will need the following in your environment:
1. .NET Core SDK 5.0+ and the .NET Core 3.1 Runtime
Available here
2. PostgreSQL 9.6 or above database with PLV8
The fastest possible way to develop with Marten is to run PostgreSQL in a Docker container. Assuming that you have Docker running on your local box, type dotnet run --framework net6.0 -- init-db
at the command line to spin up a Postgresql database with PLv8 enabled and configured in the database. The default Marten test configuration tries to find this database if no PostgreSQL database connection string is explicitly configured following the steps below:
You need to enable the PLV8 extension inside of PostgreSQL for running JavaScript stored procedures for the nascent projection support.
Ensure the following:
postgres
rolemarten_testing_database
is set to the connection string for the database you want to use as a testbed. (See the Npgsql documentation for more information about PostgreSQL connection strings ).Help with PSQL/PLV8
Once you have the codebase and the connection string file, run the build command or use the dotnet CLI to restore and build the solution.
You are now ready to contribute to Marten.
See more in Contribution Guidelines.
Description | Windows Commandline | PowerShell | Linux Shell | DotNet CLI |
---|---|---|---|---|
Run restore, build and test | build.cmd | build.ps1 | build.sh | dotnet build src\Marten.sln |
Run all tests including mocha tests | build.cmd test | build.ps1 test | build.sh test | dotnet run -p build/build.csproj -- test |
Run just mocha tests | build.cmd mocha | build.ps1 mocha | build.sh mocha | dotnet run -p build/build.csproj -- mocha |
Run StoryTeller tests | build.cmd storyteller | build.ps1 storyteller | build.sh storyteller | dotnet run -p build/build.csproj -- storyteller |
Open StoryTeller editor | build.cmd open_st | build.ps1 open_st | build.sh open_st | dotnet run -p build/build.csproj -- open_st |
Run docs website locally | build.cmd docs | build.ps1 docs | build.ps1 docs | dotnet run -p build/build.csproj -- docs |
Publish docs | build.cmd publish-docs | build.ps1 publish-docs | build.sh publish-docs | dotnet run -p build/build.csproj -- publish-docs |
Run benchmarks | build.cmd benchmarks | build.ps1 benchmarks | build.sh benchmarks | dotnet run -p build/build.csproj -- benchmarks |
Note: You should have a running Postgres instance while running unit tests or StoryTeller tests.
The tests for the main library are now broken into three testing projects:
CoreTests
-- basic services like retries, schema management basicsDocumentDbTests
-- anything specific to the document database features of MartenEventSourcingTests
-- anything specific to the event sourcing features of MartenTo aid in integration testing, Marten.Testing has a couple reusable base classes that can be use to make integration testing through Postgresql be more efficient and allow the xUnit.Net tests to run in parallel for better throughput.
IntegrationContext
-- if most of the tests will use an out of the box configuration (i.e., no fluent interface configuration of any document types), use this base type. Warning though, this context type will not clean out the main public
database schema between runs, but will delete any existing dataDestructiveIntegrationContext
-- similar to IntegrationContext
, but will wipe out any and all Postgresql schema objects in the public
schema between tests. Use this sparingly please.OneOffConfigurationsContext
-- if a test suite will need to frequently re-configure the DocumentStore
, this context is appropriate. You do not need to decorate any of these test classes with the [Collection]
attribute. This fixture will use an isolated schema using the name of the test fixture type as the schema nameBugIntegrationContext
-- the test harnesses for bugs tend to require custom DocumentStore
configuration, and this context is a specialization of OneOffConfigurationsContext
for the bugs schema.StoreFixture
and StoreContext
are helpful if a series of tests use the same custom DocumentStore
configuration. You'd need to write a subclass of StoreFixture
, then use StoreContext<YourNewStoreFixture>
as the base class to share the DocumentStore
between test runs with xUnit.Net's shared context (IClassFixture<T>
)Refer to the build commands section to look up the commands to run Mocha tests. There is also npm run tdd
to run the mocha specifications in a watched mode with growl turned on.
Note: remember to run
npm install
Refer to build commands section to look up the commands to open the StoryTeller editor or run the StoryTeller specs.
All the documentation is written in Markdown and the docs are published as a static site hosted in Netlify. v4.x and v3.x use different documentation tools hence are detailed below in separate sub-sections.
VitePress is used as documentation tool. Along with this, MarkdownSnippets is used for adding code snippets to docs from source code and Algolia DocSearch is used for searching the docs via the search box.
The documentation content is the Markdown files in the /docs
directory directly under the project root. To run the docs locally use npm run docs
with auto-refresh on any changes.
To add code samples/snippets from the tests in docs, follow the steps below:
Use C# named regions to mark a code block as described in the sample below
#region sample_my_snippet
// code sample/snippet
// ...
#endregion
All code snippet identifier starts with sample_
as a convention to clearly identify that the region block corresponds to a sample code/snippet used in docs. Recommend to use snake case for the identifiers with words in lower case.
Use the below to include the code snippet in a docs page
<!-- snippet: sample_my_snippet --> <!-- endSnippet -->
Note that when you run the docs locally, the above placeholder block in the Markdown file will get updated inline with the actual code snippet from the source code. Please commit the changes with the auto-generated inline code snippet as-is after you preview the docs page. This helps with easier change tracking when you send PR's.
Few gotchas:
stdocs is used as documentation tool. The documentation content is the markdown files in the /documentation
directory directly under the project root. Any updates to v3.x docs will need to done in 3.14 branch. To run the documentation website locally with auto-refresh, refer to the build commands section above.
If you wish to insert code samples/snippet to a documentation page from the tests, wrap the code you wish to insert with // SAMPLE: name-of-sample
and // ENDSAMPLE
. Then to insert that code to the documentation, add <[sample:name-of-sample]>
.
Note: content is published to the
gh-pages
branch of this repository. Refer to build commands section to lookup the command for publishing docs.
Author: JasperFx
Source code: https://github.com/JasperFx/marten
License: MIT license
#dotnet #aps.net #csharp #database
1660321872
IN this article, we are going to learn how we can manage the filegroup of SQL Database in SQL Server. The SQL Server has four filegroups.
See more at: https://www.sqlshack.com/managing-file-groups-of-sql-databases/
#sql #database
1660317916
This repository contains source code for the RavenDB document database. With a RavenDB database you can set up a NoSQL data architecture or add a NoSQL layer to your current relational database.
Request your license.
Download the latest version of RavenDB.
Install and set up your database.
RavenDB Bootcamp is a free, self-directed learning course. In just three units you will learn how to use RavenDB to create fully-functional, real-world programs with NoSQL Databases. If you are unfamiliar with NoSQL, it’s okay. We will provide you with all the information you need.
We keep adding new features to improve your RavenDB experience. Check out our latest improvements, updated weekly.
Access full documentation for RavenDB. Like our database, it is easy to use.
If you have any questions, or need further assistance, you can contact us directly.
Please check where to report an issue in our contribution guidelines.
If you have any questions please visit our discussions page or check Google community group archive. The solutions for the most common challenges are available. You are welcome to join!
Please check how to submit a Pull Request in our contribution guidelines.
First please review and set up prerequisites.
Running locally:
<path/to/ravendb>/Server/Raven.Server
Registering as service in Windows using rvn
utility available in the package Server directory:
<path\to\ravendb>\rvn.exe windows-service register --service-name RavenDB4
<path/to/ravendb>/Server/Raven.Server --ServerUrl=http://localhost:8080
Open a web browser and enter http://localhost:8080
Click on Databases
in the menu on the left-hand side, and then create a new database named SampleDataDB
Click on Settings
and then on Create Sample Data
in the left menu. Now Click on Create
Install .NET Core SDK. See : Downloads and PowerShell
Open a terminal and type:
mkdir HelloWorld
cd HelloWorld
dotnet new console
dotnet add package RavenDB.Client --version 5.4.0-*
using System;
using Raven.Client.Documents;
namespace HelloWorld
{
class Shippers
{
public string Name;
public string Phone;
}
class Program
{
static void Main(string[] args)
{
using (var store = new DocumentStore
{
Urls = new string[] {"http://localhost:8080"},
Database = "SampleDataDB"
})
{
store.Initialize();
using (var session = store.OpenSession())
{
var shipper = session.Load<Shippers>("shippers/1-A");
Console.WriteLine("Shipper #1 : " + shipper.Name + ", Phone: " + shipper.Phone);
}
}
}
}
}
dotnet restore
dotnet build
dotnet run
Enjoy :)
Author: ravendb
Source code: https://github.com/ravendb/ravendb
License: View license
#dotnet #aps.net #csharp #database
1660314600
Dans cet article, nous allons apprendre comment gérer le groupe de fichiers de SQL Database dans SQL Server. Le serveur SQL a quatre groupes de fichiers.
Le groupe de fichiers contient un ou plusieurs fichiers de données. Cet article explique comment nous pouvons gérer les Nous allons comprendre les cas d'utilisation suivants.
Pour illustrer les scénarios ci-dessus, j'ai installé SQL Server 2019 sur mon ordinateur portable et restauré un exemple de base de données stackoverflow2010 . Vous pouvez télécharger la base de données Stackoverflow2010 à partir d' ici . J'ai également créé un groupe de fichiers nommé FG_POSTS dans une base de données. Vous pouvez afficher la liste des groupes de fichiers et la liste des groupes de fichiers associés aux fichiers de données en exécutant la requête suivante.
SELECT [databasefile].NAME AS [FileName],
[filegroup].NAME AS [File_Group_Name],
[filegroup].type_desc,
physical_name [Data File Location],
size / 128 AS [Size_in_MB],
state_desc [State of FILE],
growth [Data file growth]
FROM sys.database_files [databasefile]
INNER JOIN sys.filegroups [filegroup]
ON [databasefile].data_space_id = [filegroup].data_space_id
Production
Maintenant, comprenons tous les cas d'utilisation.
Nous pouvons utiliser l'instruction ALTER DATABASE ADD FILE TO FILGRAOUP . La syntaxe est la suivante :
ALTER DATABASE <db_name> ADD FILE (NAME= <logical_file_name>, FILENAME =<file_location>, SIZE=<File_size>, FILEGROWTH= <datafile_growth>)
To FILEGROUP <file_group_name>
Dans la syntaxe,
Par exemple, nous voulons ajouter un fichier de données au groupe de fichiers FG_POSTS avec les options suivantes
La requête pour ajouter un fichier de données suit.
ALTER DATABASE [Stackoverflow2010] ADD FILE ( NAME = N'fg_posts_data', FILENAME = N'D:\FG_Posts\fg_posts_data.ndf' , SIZE = 10MB , FILEGROWTH = 5MB )
TO FILEGROUP [FG_POSTS]
GO
Une fois la commande exécutée, ouvrez avec succès le D:\FG_Posts pour afficher le fichier de données.
Comme vous pouvez le voir, le fichier a été créé. Vous pouvez également exécuter la requête suivante pour afficher les groupes de fichiers.
SELECT [databasefile].NAME AS [FileName],
[filegroup].NAME AS [File_Group_Name],
[filegroup].type_desc,
physical_name [Data File Location],
size / 128 AS [Size_in_MB],
state_desc [State of FILE],
growth [Data file growth]
FROM sys.database_files [databasefile]
INNER JOIN sys.filegroups [filegroup]
ON [databasefile].data_space_id = [filegroup].data_space_id
Sortie de la requête
Comme vous pouvez le voir, le fichier de données nommé fg_posts_data a été créé.
Maintenant, comprenons comment nous pouvons renommer le groupe de fichiers existant.
Vous pouvez utiliser l'instruction ALTER DATABASE MODIFY FILEGROUP. Voici la syntaxe :
ALTER DATABASE <db_name> MODIFY FILEGROUP FILEGROUP <file_group_name> NAME= <file_group_new_name>
Dans la syntaxe,
Supposons que vous souhaitiez renommer le groupe de fichiers nommé FG_Posts en FG_POSTS_1 . La requête pour renommer le groupe de fichiers est la suivante :
ALTER DATABASE [Stackoverflow2010] MODIFY FILEGROUP FG_POSTS NAME= FG_POSTS_1
Une fois la commande exécutée avec succès, exécutez la requête suivante pour vérifier que les modifications ont été appliquées ou non.
Une fois la commande exécutée avec succès, exécutez la requête suivante pour vérifier que les modifications ont été appliquées ou non.
SELECT [databasefile].NAME AS [FileName],
[filegroup].NAME AS [File_Group_Name],
[filegroup].type_desc,
physical_name [Data File Location],
size / 128 AS [Size_in_MB],
state_desc [State of FILE],
growth [Data file growth]
FROM sys.database_files [databasefile]
INNER JOIN sys.filegroups [filegroup]
ON [databasefile].data_space_id = [filegroup].data_space_id
Production
Comme vous pouvez le voir, le groupe de fichiers a été renommé avec succès.
Voyons maintenant comment marquer un groupe de fichiers secondaire comme groupe de fichiers par défaut.
Pour changer le groupe de fichiers par défaut, nous pouvons utiliser l'instruction ALTER DATABASE MODIFY FILEGROUP. Voici la syntaxe :
ALTER DATABASE <db_name> MODIFY FILEGROUP <file_group_name> DEFAULT
Dans la syntaxe,
Supposons que vous souhaitiez définir FG_POSTS_1 comme groupe de fichiers par défaut. Pour ce faire, exécutez la requête suivante.
ALTER DATABASE [Stackoverflow2010] MODIFY FILEGROUP [FG_POSTS_1] DEFAULT
Une fois la commande exécutée avec succès, exécutez la requête suivante pour afficher le groupe de fichiers par défaut d'une base de données nommée Stackoverflow2010 .
SELECT [databasefile].NAME AS [FileName],
[filegroup].NAME AS [File_Group_Name],
[filegroup].type_desc,
physical_name [Data File Location],
Case when is_default =1 then 'Default filegroup' else 'non-default filegroup' end [Is default Filegroup],
size / 128 AS [Size_in_MB],
state_desc [State of FILE],
growth [Data file growth]
FROM sys.database_files [databasefile]
INNER JOIN sys.filegroups [filegroup]
ON [databasefile].data_space_id = [filegroup].data_space_id
Sortie de la requête
Comme vous pouvez le voir, le FG_POSTS_1 est un groupe de fichiers par défaut.
Maintenant, créons une table nommée tblStackoverflow_Users. Le script pour créer la table est le suivant :
USE [Stackoverflow2010]
GO
CREATE TABLE [dbo].[tblStackoverflow_Users](
[Id] [int] IDENTITY(1,1) NOT NULL,
[AboutMe] [nvarchar](max) NULL,
[Age] [int] NULL,
[CreationDate] [datetime] NOT NULL,
[DisplayName] [nvarchar](40) NOT NULL,
[DownVotes] [int] NOT NULL,
[EmailHash] [nvarchar](40) NULL,
[LastAccessDate] [datetime] NOT NULL,
[Location] [nvarchar](100) NULL
CONSTRAINT [PK_tblStackoverflow_Users_Id] PRIMARY KEY CLUSTERED
(
[Id] ASC
))
GO
Voyons maintenant dans quel groupe de fichiers la table a été créée. Pour ce faire, exécutez la requête suivante :
use Stackoverflow2010
go
SELECT OBJECT_NAME(t.object_id) AS [Table Name], d.name AS [Filegroup Name] FROM sys.data_spaces d
JOIN sys.indexes i on i.data_space_id = d.data_space_id
JOIN sys.tables t on t.object_id = i.object_id
WHERE i.index_id<2
AND t.type = 'U'
AND OBJECT_NAME(t.object_id) ='tblStackoverflow_Users'
Production
Comme vous pouvez le voir, la table est créée dans le groupe de fichiers FG_POSTS_1 .
Dans cet article, nous avons appris comment gérer les groupes de fichiers dans SQL Database. Nous avons appris les scénarios suivants :
Lien : https://www.sqlshack.com/managing-file-groups-of-sql-databases/
#sql #database