0Pricing
Clojure Functional Programming & JVM Backend Development · レッスン

CRUD操作の実行

Clojureからリレーショナルデータベースのデータを作成、読み取り、更新、削除する方法を習得します。

「CRUD操作の実行」はCoddyKit上の無料Clojure Functional Programming & JVM Backend Developmentレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはClojure Functional Programming & JVM Backend Development学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Clojure Functional Programming & JVM Backend Developmentコースには全4レッスンが含まれています。

このレッスンの一部はまだ翻訳されておらず、英語で表示されています。

What is CRUD?

When you build applications, you'll constantly interact with databases. The fundamental operations for managing data are often summarized by the acronym CRUD.

  • Create: Adding new data.
  • Read: Retrieving existing data.
  • Update: Modifying existing data.
  • Delete: Removing data.

In this lesson, we'll master how to perform these essential operations using Clojure's next.jdbc library.

Database Connection Setup

Before we perform CRUD operations, we need a database connection. We'll use next.jdbc with an in-memory SQLite database for our examples.

Remember from the previous lesson, we define a database specification (db-spec) and obtain a data source (ds) or a direct connection.

We'll create a simple users table for our examples.

Create: Inserting New Records

To add new data, we use the next.jdbc.sql/insert! function. It takes a connection, table name, and a map of column-value pairs.

Try running this example to create a users table and insert your first user:

(ns coddykit.core
  (:require [next.jdbc :as jdbc]
            [next.jdbc.sql :as sql]))

(defn -main
  "Insert a new user into the database."
  [& args]
  (let [db-spec {:dbtype "sqlite" :dbname ":memory:"}]
    (with-open [conn (jdbc/get-connection db-spec)]
      (jdbc/execute! conn ["DROP TABLE IF EXISTS users;"])
      (jdbc/execute! conn ["CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)"])

      (println "Inserting new user...")
      (let [new-user {:name "Alice" :email "alice@example.com"}
            result (sql/insert! conn :users new-user)]
        (println "Insert result:" result))

      (println "\nUsers in database:")
      (doseq [user (sql/select! conn ["SELECT * FROM users"])]
        (println user)))))

Create: Inserting Multiple Records

What if you need to add many records at once? The next.jdbc.sql/insert-multi! function is perfect for this. It takes a sequence of maps, each representing a row to insert.

It's more efficient than calling insert! repeatedly in a loop.

(ns coddykit.core
  (:require [next.jdbc :as jdbc]
            [next.jdbc.sql :as sql]))

(defn -main
  "Insert multiple users into the database."
  [& args]
  (let [db-spec {:dbtype "sqlite" :dbname ":memory:"}]
    (with-open [conn (jdbc/get-connection db-spec)]
      (jdbc/execute! conn ["DROP TABLE IF EXISTS users;"])
      (jdbc/execute! conn ["CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)"])

      (println "Inserting multiple users...")
      (let [new-users [{:name "Bob" :email "bob@example.com"}
                       {:name "Charlie" :email "charlie@example.com"}]
            result (sql/insert-multi! conn :users new-users)]
        (println "Insert result:" result))

      (println "\nUsers in database:")
      (doseq [user (sql/select! conn ["SELECT * FROM users"])]
        (println user)))))

Read: Fetching All Data

To retrieve all records from a table, use next.jdbc.sql/select-all!. It takes a connection and the table name (as a keyword or string).

The function returns a sequence of maps, where each map represents a row.

(ns coddykit.core
  (:require [next.jdbc :as jdbc]
            [next.jdbc.sql :as sql]))

(defn -main
  "Select all users from the database."
  [& args]
  (let [db-spec {:dbtype "sqlite" :dbname ":memory:"}]
    (with-open [conn (jdbc/get-connection db-spec)]
      (jdbc/execute! conn ["DROP TABLE IF EXISTS users;"])
      (jdbc/execute! conn ["CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)"])
      (sql/insert! conn :users {:name "Alice" :email "alice@example.com"})
      (sql/insert! conn :users {:name "Bob" :email "bob@example.com"})

      (println "Fetching all users...")
      (let [all-users (sql/select-all! conn :users)]
        (doseq [user all-users]
          (println user))))))

Read: Filtering Data with `WHERE`

Often, you only want specific records. Use next.jdbc.sql/select! with a WHERE clause to filter results. The WHERE clause is provided as a map.

For example, to find users with a specific name or email:

(ns coddykit.core
  (:require [next.jdbc :as jdbc]
            [next.jdbc.sql :as sql]))

(defn -main
  "Select users with a specific name."
  [& args]
  (let [db-spec {:dbtype "sqlite" :dbname ":memory:"}]
    (with-open [conn (jdbc/get-connection db-spec)]
      (jdbc/execute! conn ["DROP TABLE IF EXISTS users;"])
      (jdbc/execute! conn ["CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)"])
      (sql/insert! conn :users {:name "Alice" :email "alice@example.com"})
      (sql/insert! conn :users {:name "Bob" :email "bob@example.com"})
      (sql/insert! conn :users {:name "Alice" :email "alice2@example.com"})

      (println "Fetching users named Alice...")
      (let [alices (sql/select! conn :users {:name "Alice"})]
        (doseq [user alices]
          (println user))))))

Update: Modifying Existing Data

To change existing records, use next.jdbc.sql/update!. It takes a connection, table name, a map of columns to update, and a WHERE clause map to specify which records to modify.

Always be careful with your WHERE clause when updating!

(ns coddykit.core
  (:require [next.jdbc :as jdbc]
            [next.jdbc.sql :as sql]))

(defn -main
  "Update a user's email address."
  [& args]
  (let [db-spec {:dbtype "sqlite" :dbname ":memory:"}]
    (with-open [conn (jdbc/get-connection db-spec)]
      (jdbc/execute! conn ["DROP TABLE IF EXISTS users;"])
      (jdbc/execute! conn ["CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)"])
      (sql/insert! conn :users {:name "Alice" :email "alice@example.com"})

      (println "Original user:")
      (println (first (sql/select! conn :users {:name "Alice"})))

      (println "\nUpdating Alice's email...")
      (let [result (sql/update! conn :users {:email "alice.new@example.com"} {:name "Alice"})]
        (println "Update result:" result))

      (println "\nUpdated user:")
      (println (first (sql/select! conn :users {:name "Alice"})))))

Delete: Removing Data

To remove records from a table, use next.jdbc.sql/delete!. Similar to update!, it requires a connection, table name, and a WHERE clause map to specify which records to remove.

A missing or empty WHERE clause can delete ALL records, so use with extreme caution!

(ns coddykit.core
  (:require [next.jdbc :as jdbc]
            [next.jdbc.sql :as sql]))

(defn -main
  "Delete a user from the database."
  [& args]
  (let [db-spec {:dbtype "sqlite" :dbname ":memory:"}]
    (with-open [conn (jdbc/get-connection db-spec)]
      (jdbc/execute! conn ["DROP TABLE IF EXISTS users;"])
      (jdbc/execute! conn ["CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)"])
      (sql/insert! conn :users {:name "Alice" :email "alice@example.com"})
      (sql/insert! conn :users {:name "Bob" :email "bob@example.com"})

      (println "Users before delete:")
      (doseq [user (sql/select-all! conn :users)] (println user))

      (println "\nDeleting Bob...")
      (let [result (sql/delete! conn :users {:name "Bob"})]
        (println "Delete result:" result))

      (println "\nUsers after delete:")
      (doseq [user (sql/select-all! conn :users)] (println user)))))

Atomic Operations with Transactions

Sometimes you need multiple CRUD operations to succeed or fail as a single, atomic unit. This is where transactions come in.

If any operation within a transaction fails, all changes are rolled back, ensuring data consistency. Use next.jdbc/with-transaction for this.

(ns coddykit.core
  (:require [next.jdbc :as jdbc]
            [next.jdbc.sql :as sql]))

(defn -main
  "Demonstrate a database transaction."
  [& args]
  (let [db-spec {:dbtype "sqlite" :dbname ":memory:"}]
    (with-open [conn (jdbc/get-connection db-spec)]
      (jdbc/execute! conn ["DROP TABLE IF EXISTS accounts;"])
      (jdbc/execute! conn ["CREATE TABLE accounts (id INTEGER PRIMARY KEY, name TEXT, balance INTEGER)"])
      (sql/insert! conn :accounts {:name "Alice" :balance 100})
      (sql/insert! conn :accounts {:name "Bob" :balance 50})

      (println "Balances before transaction:")
      (doseq [acc (sql/select-all! conn :accounts)] (println acc))

      (println "\nAttempting to transfer $20 from Alice to Bob...")
      (try
        (jdbc/with-transaction [tx conn]
          (sql/update! tx :accounts {:balance [- :balance 20]} {:name "Alice"})
          (sql/update! tx :accounts {:balance [+ :balance 20]} {:name "Bob"})
          (println "Transfer successful!"))
        (catch Exception e
          (println "Transfer failed:" (.getMessage e))))

      (println "\nBalances after transaction:")
      (doseq [acc (sql/select-all! conn :accounts)] (println acc)))))

CRUD Quick Check

You've learned the core functions for interacting with databases. Let's test your understanding!

Recap: Mastering CRUD

Congratulations! You've mastered the essential CRUD operations for database interaction in Clojure using next.jdbc:

  • Create: insert! and insert-multi! to add data.
  • Read: select! and select-all! to retrieve data.
  • Update: update! to modify existing data.
  • Delete: delete! to remove data.

You also learned about using transactions with with-transaction for atomic operations, ensuring data integrity. These are the building blocks for almost any data-driven application!

よくある質問

「CRUD操作の実行」レッスンは無料ですか?

はい。「CRUD操作の実行」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Clojure Functional Programming & JVM Backend Developmentコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Clojure Functional Programming & JVM Backend Developmentコースには全4レッスンが含まれています。

「CRUD操作の実行」で何を学びますか?

Clojureからリレーショナルデータベースのデータを作成、読み取り、更新、削除する方法を習得します。 ブラウザで直接実行するハンズオンコードでClojure Functional Programming & JVM Backend Developmentを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Clojure Functional Programming & JVM Backend Developmentを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのClojure Functional Programming & JVM Backend Developmentは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「CRUD操作の実行」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このClojure Functional Programming & JVM Backend Developmentレッスンでコードを書いて実行できますか?

はい。すべてのClojure Functional Programming & JVM Backend Developmentレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. next.jdbcによるデータベース接続
  2. CRUD操作の実行
  3. データベースマイグレーションとスキーマ管理
  4. コネクションプーリングとトランザクション
← Clojure Functional Programming & JVM Backend Developmentに戻る