batchtest.java

来自「jtds的源码 是你学习java的好东西」· Java 代码 · 共 631 行 · 第 1/2 页

JAVA
631
字号
        stmt.executeUpdate("insert into #testLargeBatch (val) values (0)");

        PreparedStatement pstmt = con.prepareStatement(
                "update #testLargeBatch set val=? where val=?");
        for (int i = 0; i < n; i++) {
            pstmt.setInt(1, i + 1);
            pstmt.setInt(2, i);
            pstmt.addBatch();
        }
        int counts[] =pstmt.executeBatch();
//        System.out.println(pstmt.getWarnings());
        assertEquals(n, counts.length);
        for (int i = 0; i < n; i++) {
            assertEquals(1, counts[i]);
        }
        pstmt.close();

        ResultSet rs =
                stmt.executeQuery("select count(*) from #testLargeBatch");
        assertTrue(rs.next());
        assertEquals(1, rs.getInt(1));
        assertFalse(rs.next());
        rs.close();
        stmt.close();
    }

    /**
     * Test for bug [1180169] JDBC escapes not allowed with Sybase addBatch.
     */
    public void testBatchEsc() throws Exception {
        Statement stmt = con.createStatement();
        stmt.execute("CREATE TABLE #TESTBATCH (ts datetime)");
        stmt.addBatch("INSERT INTO #TESTBATCH VALUES ({ts '1999-01-01 23:50:00'})");
        int counts[] = stmt.executeBatch();
        assertEquals(1, counts[0]);
        stmt.close();
    }

    /**
     * Test for bug [1371295] SQL Server continues after duplicate key error.
     */
    public void testPrepStmtBatchDupKey() throws Exception {
        Statement stmt = con.createStatement();
        stmt.execute("create table #testbatch (id int, data varchar(255), PRIMARY KEY (id))");
        PreparedStatement pstmt = con.prepareStatement("INSERT INTO #testbatch VALUES (?, ?)");
        for (int i = 0; i < 5; i++) {
            if (i == 2) {
                pstmt.setInt(1, 1); // Will cause duplicate key batch will continue
            } else {
                pstmt.setInt(1, i);
            }
            pstmt.setString(2, "This is line " + i);
            pstmt.addBatch();
        }
        int x[];
        try {
            x = pstmt.executeBatch();
        } catch (BatchUpdateException e) {
            x = e.getUpdateCounts();
        }
        assertEquals(5, x.length);
        assertEquals(1, x[0]);
        assertEquals(1, x[1]);
        assertEquals(EXECUTE_FAILED, x[2]);
        assertEquals(1, x[3]);
        assertEquals(1, x[4]);
        // Now without errors
        stmt.execute("TRUNCATE TABLE #testbatch");
        for (int i = 0; i < 5; i++) {
            pstmt.setInt(1, i);
            pstmt.setString(2, "This is line " + i);
            pstmt.addBatch();
        }
        x = pstmt.executeBatch();
        assertEquals(5, x.length);
        assertEquals(1, x[0]);
        assertEquals(1, x[1]);
        assertEquals(1, x[2]);
        assertEquals(1, x[3]);
        assertEquals(1, x[4]);
    }

    /**
     * Test for bug [1371295] SQL Server continues after duplicate key error.
     */
    public void testBatchDupKey() throws Exception {
        Statement stmt = con.createStatement();
        stmt.execute("create table #testbatch (id int, data varchar(255), PRIMARY KEY (id))");
        for (int i = 0; i < 5; i++) {
            if (i == 2) {
                // This statement will generate an duplicate key error
                stmt.addBatch("INSERT INTO #testbatch VALUES (1, 'This is line " + i + "')");
            } else {
                stmt.addBatch("INSERT INTO #testbatch VALUES (" + i + ", 'This is line " + i + "')");
            }
        }
        int x[];
        try {
            x = stmt.executeBatch();
        } catch (BatchUpdateException e) {
            x = e.getUpdateCounts();
        }
        assertEquals(5, x.length);
        assertEquals(1, x[0]);
        assertEquals(1, x[1]);
        assertEquals(EXECUTE_FAILED, x[2]);
        assertEquals(1, x[3]);
        assertEquals(1, x[4]);
        // Now without errors
        stmt.execute("TRUNCATE TABLE #testbatch");
        for (int i = 0; i < 5; i++) {
            stmt.addBatch("INSERT INTO #testbatch VALUES (" + i + ", 'This is line " + i + "')");
        }
        x = stmt.executeBatch();
        assertEquals(5, x.length);
        assertEquals(1, x[0]);
        assertEquals(1, x[1]);
        assertEquals(1, x[2]);
        assertEquals(1, x[3]);
        assertEquals(1, x[4]);
    }
    
    /**
     * Test for PreparedStatement batch with no parameters.
     */
    public void testPrepStmtNoParams() throws Exception {
        Statement stmt = con.createStatement();
        stmt.execute("create table #testbatch (id numeric(10) identity, data varchar(255), PRIMARY KEY (id))");
        PreparedStatement pstmt = con.prepareStatement("INSERT INTO #testbatch (data) VALUES ('Same each time')");
        for (int i = 0; i < 5; i++) {
            pstmt.addBatch();
        }
        int x[];
        try {
            x = pstmt.executeBatch();
        } catch (BatchUpdateException e) {
            x = e.getUpdateCounts();
        }
        assertEquals(5, x.length);
        assertEquals(1, x[0]);
        assertEquals(1, x[1]);
        assertEquals(1, x[2]);
        assertEquals(1, x[3]);
        assertEquals(1, x[4]);
    }

    /**
     * Test for PreparedStatement batch with variable parameter types.
     */
    public void testPrepStmtVariableParams() throws Exception {
        Statement stmt = con.createStatement();
        stmt.execute("create table #testbatch (id int, data int, PRIMARY KEY (id))");
        PreparedStatement pstmt = con.prepareStatement("INSERT INTO #testbatch VALUES (?, convert(int, ?))");
        for (int i = 0; i < 5; i++) {
            pstmt.setInt(1, i);
            if (i == 2) {
                // This statement will require a string param instead of an int
                pstmt.setString(2, "123");
            } else {
                pstmt.setInt(2, 123);
            }
            pstmt.addBatch();
        }
        int x[];
        try {
            x = pstmt.executeBatch();
        } catch (BatchUpdateException e) {
            x = e.getUpdateCounts();
        }
        assertEquals(5, x.length);
        assertEquals(1, x[0]);
        assertEquals(1, x[1]);
        assertEquals(1, x[2]);
        assertEquals(1, x[3]);
        assertEquals(1, x[4]);
        ResultSet rs = stmt.executeQuery("SELECT * FROM #testbatch");
        assertNotNull(rs);
        int i = 0;
        while (rs.next()) {
            assertEquals(123, rs.getInt(2));
            i++;
        }
        assertEquals(5, i);
    }
    
    /**
     * Test batched callable statements where the call has no parameters.
     */
    public void testCallStmtNoParams() throws Exception {
        dropProcedure("jTDS_PROC");
        try {
            Statement stmt = con.createStatement();
            stmt.execute("create table #testbatch (id numeric(10) identity, data varchar(255))");
            stmt.execute("create proc jTDS_PROC  as " +
                    "INSERT INTO #testbatch (data) VALUES ('same each time')");
            CallableStatement cstmt = con.prepareCall("{call jTDS_PROC}");
            for (int i = 0; i < 5; i++) {
                cstmt.addBatch();
            }
            int x[];
            try {
                x = cstmt.executeBatch();
            } catch (BatchUpdateException e) {
                x = e.getUpdateCounts();
            }
            assertEquals(5, x.length);
            assertEquals(1, x[0]);
            assertEquals(1, x[1]);
            assertEquals(1, x[2]);
            assertEquals(1, x[3]);
            assertEquals(1, x[4]);
        } finally {
            dropProcedure("jTDS_PROC");
        }
    }


    /**
     * Helper thread used by <code>testConcurrentBatching()</code> to execute a batch within a transaction that is
     * then rolled back. Starting a couple of these threads concurrently should show whether there are any race
     * conditions WRT preparation and execution in the batching implementation.
     */
    private class ConcurrentBatchingHelper extends Thread {
        /** Connection on which to do the work. */
        private Connection con;
        /** Container to store any exceptions into. */
        private Vector exceptions;

        ConcurrentBatchingHelper(Connection con, Vector exceptions) {
            this.con = con;
            this.exceptions = exceptions;
        }

        public void run() {
            try {
                PreparedStatement pstmt = con.prepareStatement(
                        "insert into #testConcurrentBatch (v1, v2, v3, v4, v5, v6) values (?, ?, ?, ?, ?, ?)");
                for (int i = 0; i < 64; ++i) {
                    // Make sure we end up with 64 different prepares, use the binary representation of i to set each
                    // of the 6 parameters to either an int or a string.
                    int mask = i;
                    for (int j = 1; j <= 6; ++j, mask >>= 1) {
                        if ((mask & 1) != 0) {
                            pstmt.setInt(j, i);
                        } else {
                            pstmt.setString(j, String.valueOf(i));
                        }
                    }
                    pstmt.addBatch();
                }
                int x[];
                try {
                    x = pstmt.executeBatch();
                } catch (BatchUpdateException e) {
                    e.printStackTrace();
                    x = e.getUpdateCounts();
                }
                if (x.length != 64) {
                    throw new SQLException("Expected 64 update counts, got " + x.length);
                }
                for (int i = 0; i < x.length; ++i) {
                    if (x[i] != 1) {
                        throw new SQLException("Error at position " + i + ", got " + x[i] + " instead of 1");
                    }
                }
                // Rollback the transaction, exposing any race conditions.
                con.rollback();
                pstmt.close();
            } catch (SQLException ex) {
                ex.printStackTrace();
                exceptions.add(ex);
            }
        }
    }

    /**
     * Test batched prepared statement concurrency. Batch prepares must not disappear between the moment when they
     * were created and when they are executed.
     */
    public void testConcurrentBatching() throws Exception {
        // Create a connection with a batch size of 1. This should cause prepares and actual batch execution to become
        // interspersed (if correct synchronization is not in place) and greatly increase the chance of prepares
        // being rolled back before getting executed.
        Properties props = new Properties();
        props.setProperty(Messages.get(net.sourceforge.jtds.jdbc.Driver.BATCHSIZE), "1");
        props.setProperty(Messages.get(net.sourceforge.jtds.jdbc.Driver.PREPARESQL),
                          String.valueOf(TdsCore.TEMPORARY_STORED_PROCEDURES));
        Connection con = getConnection(props);
        
        try {
            Statement stmt = con.createStatement();
            stmt.execute("create table #testConcurrentBatch (v1 int, v2 int, v3 int, v4 int, v5 int, v6 int)");
            stmt.close();

            Vector exceptions = new Vector();
            con.setAutoCommit(false);

            Thread t1 = new ConcurrentBatchingHelper(con, exceptions);
            Thread t2 = new ConcurrentBatchingHelper(con, exceptions);
            t1.start();
            t2.start();
            t1.join();
            t2.join();

            assertEquals(0, exceptions.size());
        } finally {
            con.close();
        }
    }

    public static void main(String[] args) {
        junit.textui.TestRunner.run(BatchTest.class);
    }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?