# ट्रांज़ैक्शन और bulkInsert के साथ बड़े पैमाने पर कैसे लिखें

> हजारों पंक्तियाँ तेज़ी से डालें — ट्रांज़ैक्शन, reset() के साथ पुनः उपयोग किया गया statement, या नेटिव bulkInsert।

Source: https://crossfly.dev/hi/docs/cookbook/data/transacao-e-bulk — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# ट्रांज़ैक्शन और bulkInsert के साथ बड़े पैमाने पर कैसे लिखें

**उद्देश्य.** उच्च प्रदर्शन के साथ कई पंक्तियाँ डालना/अपडेट करना। ट्रांज़ैक्शन के बिना, प्रत्येक INSERT डिस्क पर एक commit बन जाता है (धीमा)। तीन स्तर हैं: (1) सबकुछ `transaction(...)` में लपेटना, (2) `reset()` के साथ एक `SqliteStmt` पुनः उपयोग करना, (3) `bulkInsert` उपयोग करना, जो bind/step/reset लूप को नेटिव कोड में करता है (सबसे तेज़)।

## उपयोग किए गए APIs
- `SqliteDb.transaction(Runnable body)` — `body` को `BEGIN`/`COMMIT` के भीतर चलाता है; यदि `body` एक `RuntimeException` फेंके तो **स्वचालित `ROLLBACK`** करता है (और पुनः फेंकता है)। परमाणुता के लिए अनुशंसित तरीका।
- `SqliteDb.begin()` / `commit()` / `rollback()` — ट्रांज़ैक्शन का मैनुअल नियंत्रण (`exec("BEGIN"/"COMMIT"/"ROLLBACK")` के समतुल्य)। rollback न भूलने के लिए `transaction(...)` को प्राथमिकता दें।
- `SqliteDb.prepare(String sql)` — एक पुनः उपयोग योग्य `SqliteStmt` तैयार करता है (एक बार कंपाइल करता है)। **आपको इसे बंद करना चाहिए** (`try-with-resources`)।
- `SqliteStmt.bindInt/bindLong/bindDouble/bindString/bindBlob/bindNull(idx, v)` और `bindAll(Object...)` — bind **1-based**; `this` लौटाते हैं (fluent)। `step()` निष्पादित करता है; `reset()` अगले निष्पादन के लिए तैयार करता है (binds बनाए रखता है; यदि शून्य करना चाहें तो `clearBindings()` उपयोग करें)।
- `SqliteDb.bulkInsert(String sql, List<Object[]> rows)` — `sql` को एक बार तैयार करता है और प्रत्येक `Object[]` के लिए **एक ही ट्रांज़ैक्शन के भीतर**, नेटिव लूप में निष्पादित करता है। संसाधित पंक्तियों की संख्या लौटाता है। प्रत्येक `Object[]` में प्रत्येक `?` पैरामीटर के लिए एक तत्व होता है; स्वीकृत प्रकार: `Long/Integer`, `Double/Float`, `String`, `byte[]`, `null`। **कॉलम के प्रकार पहली पंक्ति से अनुमानित किए जाते हैं** — पंक्तियों को समरूप रखें। उपनाम: `bulkUpdate`, `bulkDelete`।

> **statement को पुनः उपयोग क्यों करें?** `prepare` SQL को कंपाइल करता है; प्रत्येक पंक्ति पर `prepare` दोहराने से पुनः कंपाइल होता है। `reset()` के साथ पुनः उपयोग करने से एक बार कंपाइल होता है और केवल पुनः bind होता है — बड़े लूप में बहुत तेज़।

## पूरा उदाहरण (कॉपी करें, पेस्ट करें और चलाएँ)

```java
package com.exemplo;

import java.util.*;                          // List, ArrayList

import dev.crossfly.ui.*;                     // Window
import dev.crossfly.ui.layout.*;             // VerticalLayout
import dev.crossfly.sqlite.*;                // SqliteDb, SqliteStmt

/** चलाने योग्य मुख्य स्क्रीन। launcher (classname) की ओर संकेत करें और चलाएँ: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      try (SqliteDb db = SqliteDb.open("app.db"))
      {
         db.exec("CREATE TABLE IF NOT EXISTS t(a INTEGER, b TEXT)");

         // विकल्प A — लेन-देन + पुनः उपयोग किया गया statement (निष्पादनों के बीच reset)
         db.transaction(() ->
         {
            try (SqliteStmt st = db.prepare("INSERT INTO t(a, b) VALUES(?, ?)"))
            {
               for (int i = 0; i < 10_000; i++)
               {
                  st.bindInt(1, i)            // idx 1-based
                    .bindString(2, "row" + i)
                    .step();
                  st.reset();                 // अगली पंक्ति के लिए तैयार
               }
            }
         }); // स्वचालित commit; अपवाद होने पर स्वचालित rollback

         // विकल्प B — नेटिव bulkInsert (बड़े वॉल्यूम के लिए सबसे तेज़)
         List<Object[]> rows = new ArrayList<>();
         for (int i = 0; i < 10_000; i++)
            rows.add(new Object[]{ i, "row" + i });   // पहली पंक्ति से अनुमानित प्रकार
         int n = db.bulkInsert("INSERT INTO t(a, b) VALUES(?, ?)", rows);
         System.out.println(n + " linhas inseridas");
      }
   }
}
```

> नीचे दिया गया अंश **केवल मुख्य भाग** दिखाता है। इसे चलाने के लिए, इसे ऊपर दिए गए `MainWindow` कंकाल में रखें।

## न्यूनतम अंश
```java
// स्रोत में सत्यापित: transaction, prepare + bind (1-based) + step + reset, bulkInsert
import dev.crossfly.sqlite.*;
import java.util.*;

try (SqliteDb db = SqliteDb.open("app.db"))
{
   db.exec("CREATE TABLE IF NOT EXISTS t(a INTEGER, b TEXT)");

   // विकल्प A — लेन-देन + पुनः उपयोग किया गया statement (निष्पादनों के बीच reset)
   db.transaction(() ->
   {
      try (SqliteStmt st = db.prepare("INSERT INTO t(a, b) VALUES(?, ?)"))
      {
         for (int i = 0; i < 10_000; i++)
         {
            st.bindInt(1, i)            // idx 1-based
              .bindString(2, "row" + i)
              .step();
            st.reset();                 // अगली पंक्ति के लिए तैयार
         }
      }
   }); // स्वचालित commit; अपवाद होने पर स्वचालित rollback

   // विकल्प B — नेटिव bulkInsert (बड़े वॉल्यूम के लिए सबसे तेज़)
   List<Object[]> rows = new ArrayList<>();
   for (int i = 0; i < 10_000; i++)
      rows.add(new Object[]{ i, "row" + i });   // पहली पंक्ति से अनुमानित प्रकार
   int n = db.bulkInsert("INSERT INTO t(a, b) VALUES(?, ?)", rows);
   System.out.println(n + " linhas inseridas");
}
```

## और गहराई से जानें
- [बैकग्राउंड में काम](/docs/data-and-services/background-work) · [प्रदर्शन और बड़ी सूचियाँ](/docs/best-practices/performance-e-listas-grandes)
- संबंधित रेसिपी: [पैरामीटरयुक्त CRUD](/docs/cookbook/data/crud) · [paint thread के बाहर उपयोग](/docs/cookbook/data/banco-fora-da-paint-thread)
