জাভা: মাইএসকিউএলে রেডিয়ার স্টেটমেন্টের মাধ্যমে একাধিক সারি intoোকান


88

আমি একবার জাভা ব্যবহার করে একটি মাইএসকিউএল টেবিলের একাধিক সারি সন্নিবেশ করতে চাই। সারিগুলির সংখ্যা গতিশীল। অতীতে আমি করছিলাম ...

for (String element : array) {
    myStatement.setString(1, element[0]);
    myStatement.setString(2, element[1]);

    myStatement.executeUpdate();
}

আমি মাইএসকিউএল-সমর্থিত সিনট্যাক্সটি ব্যবহার করতে এটি অনুকূল করতে চাই:

INSERT INTO table (col1, col2) VALUES ('val1', 'val2'), ('val1', 'val2')[, ...]

তবে একটি দিয়ে PreparedStatementআমি এটি করার কোনও উপায় জানি না কারণ কয়টি উপাদান arrayথাকবে তা আমি আগেই জানি না । যদি এটির সাথে এটি সম্ভব PreparedStatementনা হয় তবে আমি কীভাবে এটি করতে পারি (এবং এখনও অ্যারেতে থাকা মানগুলি থেকে বাঁচতে পারি)?

উত্তর:


178

আপনি PreparedStatement#addBatch()এটি দ্বারা একটি ব্যাচ তৈরি করতে এবং এটি দ্বারা চালিত করতে পারেন PreparedStatement#executeBatch()

এখানে একটি কিক অফ উদাহরণ:

public void save(List<Entity> entities) throws SQLException {
    try (
        Connection connection = database.getConnection();
        PreparedStatement statement = connection.prepareStatement(SQL_INSERT);
    ) {
        int i = 0;

        for (Entity entity : entities) {
            statement.setString(1, entity.getSomeProperty());
            // ...

            statement.addBatch();
            i++;

            if (i % 1000 == 0 || i == entities.size()) {
                statement.executeBatch(); // Execute every 1000 items.
            }
        }
    }
}

এটি প্রতি 1000 আইটেমটি কার্যকর করা হয় কারণ কিছু জেডিবিসি ড্রাইভার এবং / অথবা ডিবি ব্যাচের দৈর্ঘ্যে সীমাবদ্ধতা থাকতে পারে।

আরও দেখুন :


26
তোমার টিপে দ্রুত আপনি লেনদেন ... সঙ্গে অর্থাত মোড়ানো রাখলেন যাব connection.setAutoCommit(false);এবং connection.commit(); download.oracle.com/javase/tutorial/jdbc/basics/...
জশুয়া Martell

4
মনে হচ্ছে 999 টি আইটেম থাকলে আপনি খালি ব্যাচটি চালাতে পারেন।
djechlin

4
@ ইলেক্ট্রিকালবাহ এটি সাধারণভাবে কার্যকর করা হবে কারণi == entities.size()
যোহানেস এআই

প্রস্তুত বিবৃতি ব্যবহার করে ব্যাচ কাজগুলি একত্রে রাখার জন্য আরও একটি ভাল সম্পদ এখানে। ভাইরালপ্যাটেল.नेट
ড্যানি বুলিস

4
@ অ্যান্ড্রুপাওলো: প্রস্তুত স্টেটমেন্টের জন্য উপযুক্ত যে কোনও এসকিউএল INSERT। প্রাথমিক উদাহরণগুলির জন্য জেডিবিসি টিউটোরিয়াল লিঙ্কগুলি দেখুন। এটি কংক্রিট প্রশ্নের সাথে সম্পর্কিত নয়।
বালুস সি

32

যখন মাইএসকিউএল ড্রাইভার ব্যবহার করা হয় তখন আপনাকে সংযোগের পরমকে rewriteBatchedStatementsসত্যে সেট করতে হবে ( jdbc:mysql://localhost:3306/TestDB?**rewriteBatchedStatements=true**)

কেবলমাত্র একবার টেবিলটি লক হয়ে গেলে এবং সূচকগুলি একবারে আপডেট করা হয় এই বিবৃতিতে বয়ানটি বাল্ক সন্নিলে পুনরায় লেখা হয়। সুতরাং এটি অনেক দ্রুত।

এই পরম ব্যতীত কেবল সুবিধাটি ক্লিনার সোর্স কোড।


এটি নির্মাণের জন্য পারফরমেন্সের জন্য মন্তব্য: স্টেটমেন্ট.এডব্যাচ (); যদি ((আমি + 1)% 1000 == 0)। স্টেটমেন্ট.এক্সেকিউট ব্যাচ (); // প্রতি 1000 আইটেম চালাও। }
মিশালএসভি

স্পষ্টতই মাইএসকিউএল ড্রাইভারের বাগ বাগ রয়েছে mmysql.com/bug.php?id=71528 এটি হাইবারনেট হাইবারনেট.এটিগ্রেশন
শৈলেন্দ্র

হ্যাঁ. এটি আপাতত সঠিক। কমপক্ষে 5.1.45মাইএসকিএল সংযোগকারী সংস্করণের জন্য।
v.ladynev

<artifactId> mysql-সংযোজক-জাভা </ b> << সংস্করণ 8.0.14 </version> সবেমাত্র এটি 8.0.14 এর সঠিক কিনা তা পরীক্ষা করে দেখেছে। যোগ না করে rewriteBatchedStatements=trueকোনও কার্যকারিতা লাভ হয় না।
ভিনসেন্ট ম্যাথেজ

8

আপনি যদি আপনার এসকিএল স্টেটমেন্টটি গতিশীলভাবে তৈরি করতে পারেন তবে নীচের কাজটি করতে পারেন:

String myArray[][] = { { "1-1", "1-2" }, { "2-1", "2-2" }, { "3-1", "3-2" } };

StringBuffer mySql = new StringBuffer("insert into MyTable (col1, col2) values (?, ?)");

for (int i = 0; i < myArray.length - 1; i++) {
    mySql.append(", (?, ?)");
}

myStatement = myConnection.prepareStatement(mySql.toString());

for (int i = 0; i < myArray.length; i++) {
    myStatement.setString(i, myArray[i][1]);
    myStatement.setString(i, myArray[i][2]);
}
myStatement.executeUpdate();

আমি বিশ্বাস করি গৃহীত উত্তরটি আরও ভাল !! আমি ব্যাচের আপডেট সম্পর্কে জানতাম না এবং যখন এই উত্তরটি লিখতে শুরু করি তখনও উত্তরটি জমা দেওয়া হয়নি !!! :)
আলী শাকিবা

এই পদ্ধতির গ্রহণযোগ্যদের চেয়ে অনেক দ্রুত। আমি এটি পরীক্ষা করি, তবে কেন খুঁজে পাচ্ছি না। @ জনস আপনি কি জানেন কেন?
julian0zzx

@ জুলিয়ান0জেএক্স নং, তবে সম্ভবত এটি একাধিকের পরিবর্তে একক স্কেল হিসাবে চালিত হতে পারে be কিন্তু আমি নিশ্চিত না.
আলী শাকিবা

3

আপনি যদি টেবিলটিতে স্বয়ংক্রিয় বৃদ্ধি পেয়ে থাকেন এবং এটিতে অ্যাক্সেস পাওয়ার প্রয়োজন হয় আপনি .. নীচের পদ্ধতিটি ব্যবহার করতে পারেন ... ব্যবহারের আগে পরীক্ষা করুন কারণ getGeneratedKeys () স্টেটমেন্টে ব্যবহার করুন কারণ এটি ব্যবহৃত ড্রাইভারের উপর নির্ভর করে। নীচের কোডটি মারিয়া ডিবি 10.0.12 এবং মারিয়া জেডিবিসি ড্রাইভার 1.2 তে পরীক্ষা করা হয়েছে

মনে রাখবেন যে ব্যাচের আকার বাড়ানো কেবলমাত্র একটি নির্দিষ্ট পরিমাণে পারফরম্যান্সের উন্নতি করে ... আমার সেটআপের জন্য 500 এর উপরে ব্যাচের আকার বাড়ানো আসলে কার্যকারিতা হ্রাস করে।

public Connection getConnection(boolean autoCommit) throws SQLException {
    Connection conn = dataSource.getConnection();
    conn.setAutoCommit(autoCommit);
    return conn;
}

private void testBatchInsert(int count, int maxBatchSize) {
    String querySql = "insert into batch_test(keyword) values(?)";
    try {
        Connection connection = getConnection(false);
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        boolean success = true;
        int[] executeResult = null;
        try {
            pstmt = connection.prepareStatement(querySql, Statement.RETURN_GENERATED_KEYS);
            for (int i = 0; i < count; i++) {
                pstmt.setString(1, UUID.randomUUID().toString());
                pstmt.addBatch();
                if ((i + 1) % maxBatchSize == 0 || (i + 1) == count) {
                    executeResult = pstmt.executeBatch();
                }
            }
            ResultSet ids = pstmt.getGeneratedKeys();
            for (int i = 0; i < executeResult.length; i++) {
                ids.next();
                if (executeResult[i] == 1) {
                    System.out.println("Execute Result: " + i + ", Update Count: " + executeResult[i] + ", id: "
                            + ids.getLong(1));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            success = false;
        } finally {
            if (rs != null) {
                rs.close();
            }
            if (pstmt != null) {
                pstmt.close();
            }
            if (connection != null) {
                if (success) {
                    connection.commit();
                } else {
                    connection.rollback();
                }
                connection.close();
            }
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

3

@ অলি শাকিবা আপনার কোডটিতে কিছু সংশোধন দরকার। ত্রুটি অংশ:

for (int i = 0; i < myArray.length; i++) {
     myStatement.setString(i, myArray[i][1]);
     myStatement.setString(i, myArray[i][2]);
}

আপডেট হওয়া কোড:

String myArray[][] = {
    {"1-1", "1-2"},
    {"2-1", "2-2"},
    {"3-1", "3-2"}
};

StringBuffer mySql = new StringBuffer("insert into MyTable (col1, col2) values (?, ?)");

for (int i = 0; i < myArray.length - 1; i++) {
    mySql.append(", (?, ?)");
}

mysql.append(";"); //also add the terminator at the end of sql statement
myStatement = myConnection.prepareStatement(mySql.toString());

for (int i = 0; i < myArray.length; i++) {
    myStatement.setString((2 * i) + 1, myArray[i][1]);
    myStatement.setString((2 * i) + 2, myArray[i][2]);
}

myStatement.executeUpdate();

পুরো উত্তরে এটি অনেক দ্রুত এবং উন্নততর পদ্ধতি। এটি গ্রহণযোগ্য উত্তর হওয়া উচিত
অরুণ শঙ্কর

4
গৃহীত উত্তরে উল্লিখিত হিসাবে, কিছু জেডিবিসি ড্রাইভার / ডাটাবেসের কোনও INSERT বিবৃতিতে অন্তর্ভুক্ত থাকা সারিগুলির সংখ্যার সীমা রয়েছে। উপরের উদাহরণের ক্ষেত্রে, যদি myArrayসেই সীমাটির চেয়ে বেশি দৈর্ঘ্য হয়, তবে আপনি একটি ব্যতিক্রম হিট করবেন। আমার ক্ষেত্রে, আমার এক হাজার সারি সীমা রয়েছে যা ব্যাচের মৃত্যুদণ্ড কার্যকর করার প্রয়োজনীয়তার বিষয়টি বোঝায়, কারণ আমি কোনও প্রদত্ত রানে আমি প্রায় 1000 টিরও বেশি সারি আপডেট করতে পারি। আপনি যদি সর্বাধিক অনুমোদিতের চেয়ে কম সন্নিবেশ করিয়ে থাকেন তবে এই ধরণের বিবৃতি তাত্ত্বিকভাবে সূক্ষ্মভাবে কাজ করা উচিত। কিছু মনে রাখবেন।
ড্যানি বুলিস

স্পষ্ট করার জন্য, উপরের উত্তরে জেডিবিসি ড্রাইভার / ডাটাবেসের সীমাবদ্ধতার কথা ব্যাচের দৈর্ঘ্যে উল্লেখ করা হয়েছে, তবে একটি সন্নিবেশ বিবৃতিতে অন্তর্ভুক্ত সারিগুলির সীমাতেও সীমাবদ্ধতা থাকতে পারে, যেমনটি আমি আমার ক্ষেত্রে দেখেছি।
ড্যানি বুলিস

0

ব্যাচের আপডেট জমা দেওয়ার জন্য আমরা জেডিবিসিতে একসাথে একাধিক আপডেট জমা দিতে পারি।

অক্ষম স্বতঃসংশোধনের সাথে ব্যস আপডেটের জন্য আমরা স্টেটমেন্ট, রেডিয়ার স্টেটমেন্ট এবং কলএলস্টেটমেন্ট অবজেক্টগুলি ব্যবহার করতে পারি

অ্যাডব্যাচ () এবং এক্সিকিউটব্যাচ () ফাংশনগুলি সমস্ত স্টেটমেন্ট অবজেক্টের সাথে BatchUpdate থাকতে পারে

এখানে অ্যাডব্যাচ () পদ্ধতিটি বর্তমান ব্যাচে স্টেটমেন্ট বা পরামিতিগুলির একটি সেট যুক্ত করে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.