Hi,

I did some tests of Derby with Update and shared locks, to check the
compatibility. To avoid deadlocks, these locks should be implemented
asymmetrically, as shown in
http://db.apache.org/derby/docs/10.1/devguide/rdevconcepts2462.html

As I read this matrix, once a transaction has an update lock
(intention to update), a shared lock should not be granted to another
transaction. My test, whoever, indicated that a shared lock was indeed
granted (connection2 in the repro) after an update lock was taken by
the first transaction. Is this a bug or am I missing something here?

Repro:
/*
 * Main.java
 *
 * Created on October 28, 2005, 2:28 PM
 *
 * To change this template, choose Tools | Options and locate the template under
 * the Source Creation and Management node. Right-click the template and choose
 *
 * Derby seems to allow *both* R + U, and U + R, which can lead to more 
deadlocks
 * cf. Gray, Reuter p 408, there should be asymmetry for these locks.
 */

package forupdatelockingtest;


import java.sql.*;

public class Main {
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

        Statement updateStatement = null;
        Statement selectStatement = null;
        Statement selectStatement2 = null;
        Statement ddlStatement = null;
        Connection con = null;
        Connection con2 = null;
        ResultSet rs = null;
        ResultSet rs2 = null;
        
        try {
           Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
           con = 
DriverManager.getConnection("jdbc:derby:testdb;create=true;territory=en_US");
            
           con.setAutoCommit(false);
           con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
           // Create table
           ddlStatement = con.createStatement();
           ddlStatement.execute("CREATE TABLE myTable (id int primary key, name 
varchar(50))");
        }
        catch (Exception e) {
           System.out.println(e);
           return;
        }

        try {
           // Insert data
           //
           PreparedStatement ps = con.prepareStatement("INSERT INTO myTable 
VALUES (?, ?)");
           for (int i=1; i<=10; i++) {
              ps.setInt(1, i);
              ps.setString(2, "Testing " + i);
              ps.executeUpdate();
           }
           ps.close();
           con.commit();
           // Get ResultSet
           //
           selectStatement = con.createStatement (ResultSet.TYPE_FORWARD_ONLY,
                                                  ResultSet.CONCUR_UPDATABLE);
           rs = selectStatement.executeQuery("select * from myTable for 
update");
           // Position on first row
           int i = 5;
           while (i >= 0 ) {
               rs.next();
               System.out.println(rs.getInt(1));
               i--;
           };
           System.out.println("trying to do getconnection2");
           con2 = DriverManager.getConnection("jdbc:derby:testdb");
           con2.setAutoCommit(false);
           con2.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
           System.out.println("trying to do createstatement2");
           selectStatement2 = con2.createStatement (ResultSet.TYPE_FORWARD_ONLY,
                                                   ResultSet.CONCUR_READ_ONLY); 
           System.out.println("trying to do executeQuery2");
           rs2 = selectStatement2.executeQuery("select * from myTable for 
update");
           
           System.out.println("trying to do next2");
           
           while (rs2.next() ) {
               System.out.println(rs2.getInt(1));
           };

        } catch (SQLException e) {
            String s = e.getSQLState();
            System.out.println(e.toString() + " state: " + s + " : code=" + 
e.getErrorCode());
        } catch (Exception e) {
           System.out.println(e.toString());
        } 
        finally {
           try {
              if (selectStatement != null) {
                 System.out.println("trying to do close stmt1");
                 selectStatement.close(); // closes rs, too
              }
              if (selectStatement2 != null) {
                 System.out.println("trying to do close stmt2");
                 selectStatement2.close(); // closes rs, too
              }
              // Drop table and close
              

              if (updateStatement != null) {
                 updateStatement.close();
              }
              con.commit();
              con2.commit();
              if (ddlStatement != null) {
                 System.out.println("trying to do drop table"); 
                 ddlStatement.execute("DROP TABLE myTable");
                 System.out.println("trying to do close ddlstmt");
                 ddlStatement.close();
              }
              
              System.out.println("trying to close con1");
              con.commit();
              con.close();
              
              con2.commit();
              con2.close();
              
           } catch (Exception e) {
              System.out.println(e.toString());
           }
        } 
    }
}

Thanks,
Dag

Reply via email to