Interacting with Relational Databases in Rust: A Comparison of Diesel and SQLx
Rust is a systems programming language that prioritizes safety, performance, and concurrency. When it comes to interacting with relational databases, Rust provides several libraries to choose from. In this article, we’ll explore two popular libraries: Diesel and SQLx. We’ll create a simple classroom database with students to demonstrate each approach, performing CRUD (Create, Read, Update, Delete) operations using both libraries.
What is Diesel?
Diesel is an Object-Relational Mapping (ORM) library that supports PostgreSQL, MySQL, and SQLite. ORMs help abstract the details of relational databases, allowing developers to interact with databases using object-oriented programming. Diesel provides a query builder, making it easier to write SQL queries and reducing the risk of SQL injection attacks.
What is SQLx?
SQLx is a Rust SQL library that provides a low-level interface for interacting with databases. Unlike Diesel, SQLx is not an ORM; instead, it focuses on providing a simple and efficient way to execute SQL queries. SQLx supports connection pooling, cross-platform development, and asynchronous notifications, making it a great choice for high-performance applications.
Getting Started with Diesel
To get started with Diesel, we’ll create a new project and add the required dependencies. We’ll then set up our database connection and create a migration to define our database schema.
“`bash
Create a new project
cargo new classroom_diesel
Add dependencies to Cargo.toml
[dependencies]
diesel = { version = “1.4.4”, features = [“mysql”] }
dotenv = “0.15.0”
“`
Next, we’ll create a model for our Students table and use Diesel’s query builder to perform CRUD operations.
“`rust
// models.rs
use diesel::prelude::*;
[derive(Debug, Queryable)]
pub struct Student {
pub id: i32,
pub firstname: String,
pub lastname: String,
pub age: i32,
}
// main.rs
use diesel::prelude::*;
use dotenv::dotenv;
use std::env;
fn main() {
// Load environment variables
dotenv().ok();
// Establish a database connection
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let conn = PgConnection::establish(&database_url).unwrap();
// Create a new student
let new_student = Student {
id: 1,
first_name: "John".to_string(),
last_name: "Doe".to_string(),
age: 25,
};
diesel::insert_into(students::table)
.values(new_student)
.execute(&conn)
.unwrap();
}
“`
Getting Started with SQLx
To get started with SQLx, we’ll create a new project and add the required dependencies. We’ll then establish a database connection and use SQLx’s query API to perform CRUD operations.
“`bash
Create a new project
cargo new classroom_sqlx
Add dependencies to Cargo.toml
[dependencies]
sqlx = { version = “0.5.11”, features = [“mysql”] }
dotenv = “0.15.0”
“`
Next, we’ll use SQLx’s query API to perform CRUD operations.
“`rust
// main.rs
use sqlx::mysql::{MySqlPool, MySqlRow};
use dotenv::dotenv;
use std::env;
[async_std::main]
async fn main() -> sqlx::Result<()> {
// Load environment variables
dotenv().ok();
// Establish a database connection
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let pool = MySqlPool::connect(&database_url).await?;
// Create a new student
let new_student = (
1,
"John".to_string(),
"Doe".to_string(),
25,
);
sqlx::query!("INSERT INTO students (id, first_name, last_name, age) VALUES (?, ?, ?, ?)")
.bind(new_student)
.execute(&pool)
.await?;
}
“`
Conclusion
In conclusion, both Diesel and SQLx provide a way to interact with relational databases in Rust. Diesel provides an ORM interface, making it easier to work with databases using object-oriented programming. SQLx provides a low-level interface, giving developers more control over their database interactions. The choice between Diesel and SQLx ultimately depends on the specific needs of your application.