JDBC – Java Database Connectivity Representation and Management of Data on the Internet
Introduction to JDBC <ul><li>JDBC is used for accessing databases from Java applications </li></ul><ul><li>Information is ...
JDBC Architecture Java Application JDBC Oracle DB2 Postgres Oracle  Driver DB2 Driver Postgres  Driver These are Java clas...
JDBC Architecture (cont.) <ul><li>Java code calls JDBC library </li></ul><ul><li>JDBC loads a  driver   </li></ul><ul><li>...
Seven Steps <ul><li>Load the driver </li></ul><ul><li>Define the connection URL </li></ul><ul><li>Establish the connection...
Loading the Driver <ul><li>We can register the Driver indirectly using the Java statement: </li></ul><ul><li>  Class.forNa...
Another Option <ul><li>Another option is to create an instance of the driver and register it with the Driver Manager: </li...
An Example <ul><li>// A driver for imaginary1 </li></ul><ul><li>Class.forName( &quot;ORG.img.imgSQL1.imaginary1Driver&quot...
Connecting to the Database <ul><li>Every database is identified by a URL </li></ul><ul><li>Given a URL, DriverManager is a...
Connecting to the Database <ul><li>Connection con = DriverManager. </li></ul><ul><li>getConnection( &quot;jdbc.imaginaryDB...
The URLs in CS <ul><ul><ul><li>In CS, a URL has the following structure: </li></ul></ul></ul><ul><ul><ul><li>jdbc:oracle:t...
Interaction with the Database <ul><li>We use  Statement  objects in order to </li></ul><ul><ul><li>Extract data from the d...
Querying with Statement <ul><li>The executeQuery method returns a ResultSet object representing the query result. </li></u...
Changing DB with Statement String deleteStr =  “ DELETE FROM Member &quot;  + &quot;WHERE Lower(Name) = ‘harry potter’&quo...
About Prepared Statements <ul><li>Prepared Statements are used for queries that are executed many times </li></ul><ul><li>...
Querying with PreparedStatement String queryStr =  &quot;SELECT * FROM Items &quot;  + &quot;WHERE Name =  ?  and Cost <  ...
Changing DB with PreparedStatement String deleteStr =  “ DELETE FROM Items &quot;  + &quot;WHERE Name = ? and Cost > ?” ; ...
Statements vs. PreparedStatements: Be Careful! <ul><li>Are these the same? What do they do?  </li></ul>String val =  “abc”...
Statements vs. PreparedStatements: Be Careful! <ul><li>Will this work? </li></ul><ul><li>No!!!  A ‘?’ can only be used to ...
Timeout <ul><li>Use  setQueryTimeOut(int seconds)   of Statement to set a timeout for the driver to wait for a statement t...
ResultSet <ul><li>A ResultSet provides access to a table of data generated by executing a Statement </li></ul><ul><li>Only...
ResultSet Methods <ul><li>boolean next()  </li></ul><ul><ul><li>activates the next row </li></ul></ul><ul><ul><li>the firs...
ResultSet Methods <ul><li>Type  get Type (int columnIndex) </li></ul><ul><ul><li>returns the given field as the given type...
ResultSet Methods <ul><li>String getString(int columnIndex)  </li></ul><ul><li>boolean getBoolean(int columnIndex)  </li><...
ResultSet Methods <ul><li>String getString(String columnName)  </li></ul><ul><li>boolean getBoolean(String columnName)  </...
ResultSet Example <ul><li>Statement stmt = con.createStatement(); </li></ul><ul><li>ResultSet rs = stmt. </li></ul><ul><li...
Null Values <ul><li>In SQL, NULL means the field is empty </li></ul><ul><li>Not the same as 0 or “” </li></ul><ul><li>In J...
Null Values <ul><li>When inserting null values into placeholders of Prepared Statements: </li></ul><ul><ul><li>Use the met...
ResultSet Meta-Data  ResultSetMetaData rsmd = rs.getMetaData(); int numcols = rsmd.getColumnCount(); for (int i = 1 ; i <=...
Mapping Java Types to SQL Types <ul><li>SQL type    Java Type   </li></ul><ul><li>CHAR, VARCHAR, LONGVARCHAR   String </li...
More Information A detailed overview of type mapping and type conversion can be found at http://java.sun.com/j2se/1.3/docs...
Database Time <ul><li>Times in SQL are notoriously non-standard </li></ul><ul><li>Java defines three classes to help </li>...
Cleaning Up After Yourself <ul><li>Remember to close the Connections, Statements, PreparedStatements and ResultSets </li><...
Dealing With Exceptions <ul><li>An exception can have more exceptions in it. </li></ul>catch (SQLException e) { while (e !...
Advanced Topics
LOBs: Large OBjects <ul><li>Two types: </li></ul><ul><ul><li>CLOB:  Character large object (a lot of characters) </li></ul...
Retrieving a BLOB create table userImages( user varchar(50), image BLOB ); ResultSet rs =  stmt.executeQuery( “select imag...
Inserting a BLOB PreparedStatement pstmt =  con.prepareStatement( “insert into userImages values(‘snoopy’, ?)” ); File fil...
Transactions and JDBC <ul><li>Transaction = more than one statement which must all succeed (or all fail) together </li></u...
Example <ul><li>Suppose we want to transfer money from bank account 13 to account 72: </li></ul>PreparedStatement pstmt = ...
Transaction Management <ul><li>Transactions are  not  explicitly opened and closed </li></ul><ul><li>The connection has a ...
AutoCommit <ul><li>If you set AutoCommit to false, you must explicitly commit or rollback the transaction using Connection...
Fixed Example con.setAutoCommit(false); try { PreparedStatement pstmt =  con.prepareStatement( “update BankAccount    set ...
Isolation Levels <ul><li>How do different transactions interact? Do they see what another has written? </li></ul><ul><li>P...
Isolation Levels JDBC defines four  isolation modes :  Yes No No Repeatable Read No No No Serializable Yes Yes No Read Com...
Isolation Levels <ul><li>Set the transaction mode using setTransactionIsolation() of class Connection </li></ul><ul><li>Or...
Level: READ_COMMITED <ul><li>Transaction 1: </li></ul><ul><li>insert into A values(1) </li></ul><ul><li>insert into A valu...
Upcoming SlideShare
Loading in …5
×

ppt

918
-1

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
918
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
50
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • Lobs and DDL
  • ppt

    1. 1. JDBC – Java Database Connectivity Representation and Management of Data on the Internet
    2. 2. Introduction to JDBC <ul><li>JDBC is used for accessing databases from Java applications </li></ul><ul><li>Information is transferred from relations to objects and vice-versa </li></ul><ul><ul><li>databases optimized for searching/indexing </li></ul></ul><ul><ul><li>objects optimized for engineering/flexibility </li></ul></ul>
    3. 3. JDBC Architecture Java Application JDBC Oracle DB2 Postgres Oracle Driver DB2 Driver Postgres Driver These are Java classes Network We will use this one…
    4. 4. JDBC Architecture (cont.) <ul><li>Java code calls JDBC library </li></ul><ul><li>JDBC loads a driver </li></ul><ul><li>Driver talks to a particular database </li></ul><ul><li>Can have more than one driver -> more than one database </li></ul><ul><li>Ideal: can change database engines without changing any application code </li></ul>Application JDBC Driver
    5. 5. Seven Steps <ul><li>Load the driver </li></ul><ul><li>Define the connection URL </li></ul><ul><li>Establish the connection </li></ul><ul><li>Create a Statement object stmt </li></ul><ul><li>Execute a query using stmt </li></ul><ul><li>Process the result </li></ul><ul><li>Close the connection </li></ul>
    6. 6. Loading the Driver <ul><li>We can register the Driver indirectly using the Java statement: </li></ul><ul><li> Class.forName(“oracle.jdbc.driver.OracleDriver&quot;); </li></ul><ul><li>Calling Class.forName causes the Driver class to be loaded </li></ul><ul><li>When this class is loaded, it automatically </li></ul><ul><ul><li>creates an instance of itself </li></ul></ul><ul><ul><li>registers this instance with the DriverManager </li></ul></ul>
    7. 7. Another Option <ul><li>Another option is to create an instance of the driver and register it with the Driver Manager: </li></ul><ul><ul><li>Driver driver = new oracle.jdbc.OracleDriver(); </li></ul></ul><ul><ul><li>DriverManager.registerDriver(driver); </li></ul></ul>
    8. 8. An Example <ul><li>// A driver for imaginary1 </li></ul><ul><li>Class.forName( &quot;ORG.img.imgSQL1.imaginary1Driver&quot; ); </li></ul><ul><li>// A driver for imaginary2 </li></ul><ul><li>Driver driver = new ORG.img.imgSQL2.imaginary2Driver(); </li></ul><ul><li>DriverManager.registerDriver(driver); </li></ul><ul><li>//A driver for oracle </li></ul><ul><li>Class.forName( &quot;oracle.jdbc.driver.OracleDriver&quot; );      </li></ul>imaginary1 imaginary2 Registered Drivers Oracle
    9. 9. Connecting to the Database <ul><li>Every database is identified by a URL </li></ul><ul><li>Given a URL, DriverManager is asked to find the driver that can talk to the corresponding database </li></ul><ul><li>DriverManager tries all registered drivers, until a suitable one is found </li></ul>
    10. 10. Connecting to the Database <ul><li>Connection con = DriverManager. </li></ul><ul><li>getConnection( &quot;jdbc.imaginaryDB1&quot; ); </li></ul>imaginary1 imaginary2 Registered Drivers Oracle    acceptsURL( “jdbc.imaginaryDB1” )? Read more in DriverManager API
    11. 11. The URLs in CS <ul><ul><ul><li>In CS, a URL has the following structure: </li></ul></ul></ul><ul><ul><ul><li>jdbc:oracle:thin:name/password@sol4:1521:stud </li></ul></ul></ul><ul><ul><ul><li>For example: </li></ul></ul></ul><ul><ul><ul><li>jdbc:oracle:thin:snoopy/snoopy@sol4:1521:stud </li></ul></ul></ul><ul><ul><li>A complete example </li></ul></ul>Your login Also, your login The machine on which our DBMS runs The standard port given to Oracle on sol4
    12. 12. Interaction with the Database <ul><li>We use Statement objects in order to </li></ul><ul><ul><li>Extract data from the database </li></ul></ul><ul><ul><li>Update the database </li></ul></ul><ul><li>Three different interfaces are used: </li></ul><ul><ul><li>Statement , PreparedStatement , CallableStatement </li></ul></ul><ul><li>All are interfaces, thus cannot be instantiated </li></ul><ul><li>They are created by the Connection </li></ul>
    13. 13. Querying with Statement <ul><li>The executeQuery method returns a ResultSet object representing the query result. </li></ul><ul><ul><ul><li>Will be discussed later… </li></ul></ul></ul>String queryStr = &quot;SELECT * FROM Member &quot; + &quot;WHERE Lower(Name) = 'harry potter'&quot; ; Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(queryStr);
    14. 14. Changing DB with Statement String deleteStr = “ DELETE FROM Member &quot; + &quot;WHERE Lower(Name) = ‘harry potter’&quot; ; Statement stmt = con.createStatement(); int delnum = stmt.executeUpdate(deleteStr); <ul><li>executeUpdate is used for data manipulation: insert, delete, update, create table, etc. (anything other than querying!) </li></ul><ul><li>executeUpdate returns the number of rows modified </li></ul>
    15. 15. About Prepared Statements <ul><li>Prepared Statements are used for queries that are executed many times </li></ul><ul><li>They are parsed (compiled) by the DBMS only once </li></ul><ul><li>Column values can be set after compilation </li></ul><ul><li>Instead of values, use ‘ ? ’ </li></ul><ul><li>Hence, a Prepared Statement is statement that contains placeholders to be substituted later with actual values </li></ul>
    16. 16. Querying with PreparedStatement String queryStr = &quot;SELECT * FROM Items &quot; + &quot;WHERE Name = ? and Cost < ? ” ; PreparedStatement pstmt = con.prepareStatement(queryStr); pstmt.setString(1, “t-shirt” ); pstmt.setInt(2, 1000); ResultSet rs = pstmt.executeQuery();
    17. 17. Changing DB with PreparedStatement String deleteStr = “ DELETE FROM Items &quot; + &quot;WHERE Name = ? and Cost > ?” ; PreparedStatement pstmt = con.prepareStatement(deleteStr); pstmt.setString(1, “t-shirt” ); pstmt.setInt(2, 1000); int delnum = pstmt.executeUpdate();
    18. 18. Statements vs. PreparedStatements: Be Careful! <ul><li>Are these the same? What do they do? </li></ul>String val = “abc” ; PreparedStatement pstmt = con.prepareStatement( “select * from R where A=?” ); pstmt.setString(1, val); ResultSet rs = pstmt.executeQuery(); String val = “abc” ; Statement stmt = con.createStatement( ); ResultSet rs = stmt.executeQuery( “select * from R where A=” + val);
    19. 19. Statements vs. PreparedStatements: Be Careful! <ul><li>Will this work? </li></ul><ul><li>No!!! A ‘?’ can only be used to represent a column value </li></ul><ul><li>WHY? </li></ul>PreparedStatement pstmt = con.prepareStatement( “select * from ?” ); pstmt.setString(1, myFavoriteTableString);
    20. 20. Timeout <ul><li>Use setQueryTimeOut(int seconds) of Statement to set a timeout for the driver to wait for a statement to be completed </li></ul><ul><li>If the operation is not completed in the given time, an SQLException is thrown </li></ul><ul><li>What is it good for? </li></ul>
    21. 21. ResultSet <ul><li>A ResultSet provides access to a table of data generated by executing a Statement </li></ul><ul><li>Only one ResultSet per Statement can be open at once </li></ul><ul><li>The table rows are retrieved in sequence </li></ul><ul><ul><li>A ResultSet maintains a cursor pointing to its current row of data </li></ul></ul><ul><ul><li>The 'next' method moves the cursor to the next row </li></ul></ul>
    22. 22. ResultSet Methods <ul><li>boolean next() </li></ul><ul><ul><li>activates the next row </li></ul></ul><ul><ul><li>the first call to next() activates the first row </li></ul></ul><ul><ul><li>returns false if there are no more rows </li></ul></ul><ul><li>void close() </li></ul><ul><ul><li>disposes of the ResultSet </li></ul></ul><ul><ul><li>allows you to re-use the Statement that created it </li></ul></ul><ul><ul><li>automatically called by most Statement methods </li></ul></ul>
    23. 23. ResultSet Methods <ul><li>Type get Type (int columnIndex) </li></ul><ul><ul><li>returns the given field as the given type </li></ul></ul><ul><ul><li>fields indexed starting at 1 (not 0) </li></ul></ul><ul><li>Type get Type (String columnName) </li></ul><ul><ul><li>same, but uses name of field </li></ul></ul><ul><ul><li>less efficient </li></ul></ul><ul><li>int findColumn(String columnName) </li></ul><ul><ul><li>looks up column index given column name </li></ul></ul>
    24. 24. ResultSet Methods <ul><li>String getString(int columnIndex) </li></ul><ul><li>boolean getBoolean(int columnIndex) </li></ul><ul><li>byte getByte(int columnIndex) </li></ul><ul><li>short getShort(int columnIndex) </li></ul><ul><li>int getInt(int columnIndex) </li></ul><ul><li>long getLong(int columnIndex) </li></ul><ul><li>float getFloat(int columnIndex) </li></ul><ul><li>double getDouble(int columnIndex) </li></ul><ul><li>Date getDate(int columnIndex) </li></ul><ul><li>Time getTime(int columnIndex) </li></ul><ul><li>Timestamp getTimestamp(int columnIndex) </li></ul>
    25. 25. ResultSet Methods <ul><li>String getString(String columnName) </li></ul><ul><li>boolean getBoolean(String columnName) </li></ul><ul><li>byte getByte(String columnName) </li></ul><ul><li>short getShort(String columnName) </li></ul><ul><li>int getInt(String columnName) </li></ul><ul><li>long getLong(String columnName) </li></ul><ul><li>float getFloat(String columnName) </li></ul><ul><li>double getDouble(String columnName) </li></ul><ul><li>Date getDate(String columnName) </li></ul><ul><li>Time getTime(String columnName) </li></ul><ul><li>Timestamp getTimestamp(String columnName) </li></ul>
    26. 26. ResultSet Example <ul><li>Statement stmt = con.createStatement(); </li></ul><ul><li>ResultSet rs = stmt. </li></ul><ul><li> executeQuery( &quot;select name,age from Employees&quot; );     </li></ul><ul><li>// Print the result </li></ul><ul><li>while (rs.next()) {  System.out.print(rs.getString(1) +  ”:“ );  System.out.println(rs.getShort( “age” )+ ”“ ); </li></ul><ul><li>} </li></ul>
    27. 27. Null Values <ul><li>In SQL, NULL means the field is empty </li></ul><ul><li>Not the same as 0 or “” </li></ul><ul><li>In JDBC, you must explicitly ask if a field is null by calling ResultSet.isNull(column) </li></ul><ul><li>For example, getInt(column) will return 0 if the value is either 0 or null!! </li></ul>
    28. 28. Null Values <ul><li>When inserting null values into placeholders of Prepared Statements: </li></ul><ul><ul><li>Use the method setNull(index, sqlType) for primitive types (e.g. INTEGER, REAL); </li></ul></ul><ul><ul><li>You may also use the setXXX(index, null ) for object types (e.g. STRING, DATE). </li></ul></ul>
    29. 29. ResultSet Meta-Data ResultSetMetaData rsmd = rs.getMetaData(); int numcols = rsmd.getColumnCount(); for (int i = 1 ; i <= numcols; i++) { System.out.print(rsmd.getColumnLabel(i)+ ” “ ); } A ResultSetMetaData is an object that can be used to get information about the properties of the columns in a ResultSet object. An example: write the columns of the result set Many more methods in the ResultSetMetaData API
    30. 30. Mapping Java Types to SQL Types <ul><li>SQL type Java Type </li></ul><ul><li>CHAR, VARCHAR, LONGVARCHAR String </li></ul><ul><li>NUMERIC, DECIMAL java.math.BigDecimal </li></ul><ul><li>BIT boolean </li></ul><ul><li>TINYINT byte </li></ul><ul><li>SMALLINT short </li></ul><ul><li>INTEGER int </li></ul><ul><li>BIGINT long </li></ul><ul><li>REAL float </li></ul><ul><li>FLOAT, DOUBLE double </li></ul><ul><li>BINARY, VARBINARY, LONGVARBINARY byte[] </li></ul><ul><li>DATE java.sql.Date </li></ul><ul><li>TIME java.sql.Time </li></ul><ul><li>TIMESTAMP java.sql.Timestamp </li></ul>
    31. 31. More Information A detailed overview of type mapping and type conversion can be found at http://java.sun.com/j2se/1.3/docs/guide/jdbc/getstart/mapping.html
    32. 32. Database Time <ul><li>Times in SQL are notoriously non-standard </li></ul><ul><li>Java defines three classes to help </li></ul><ul><li>java.sql.Date </li></ul><ul><ul><li>year, month, day </li></ul></ul><ul><li>java.sql.Time </li></ul><ul><ul><li>hours, minutes, seconds </li></ul></ul><ul><li>java.sql.Timestamp </li></ul><ul><ul><li>year, month, day, hours, minutes, seconds, nanoseconds </li></ul></ul><ul><ul><li>usually use this one </li></ul></ul>
    33. 33. Cleaning Up After Yourself <ul><li>Remember to close the Connections, Statements, PreparedStatements and ResultSets </li></ul>con.close(); stmt.close(); pstmt.close(); rs.close()
    34. 34. Dealing With Exceptions <ul><li>An exception can have more exceptions in it. </li></ul>catch (SQLException e) { while (e != null) { System.out.println(e.getSQLState()); System.out.println(e.getMessage()); System.out.println(e.getErrorCode()); e = e.getNextException(); } }
    35. 35. Advanced Topics
    36. 36. LOBs: Large OBjects <ul><li>Two types: </li></ul><ul><ul><li>CLOB: Character large object (a lot of characters) </li></ul></ul><ul><ul><li>BLOB: Binary large object (a lot of bytes) </li></ul></ul><ul><li>Actual data is not stored in the table with the CLOB/BLOB column. Only a pointer to the data is stored there </li></ul><ul><li>I will show how to use a BLOB; CLOBs are similar </li></ul>
    37. 37. Retrieving a BLOB create table userImages( user varchar(50), image BLOB ); ResultSet rs = stmt.executeQuery( “select image from userImages” ); while (rs.next) { Blob b = rs.getBlob( “image” ); InputStream stream = b.getBinaryStream(); doSomething(stream); }
    38. 38. Inserting a BLOB PreparedStatement pstmt = con.prepareStatement( “insert into userImages values(‘snoopy’, ?)” ); File file = new File( “snoopy.jpg” ); InputStream fin = new FileInputStream(file); pstmt.setBinaryStream (1, fin, file.length()); pstmt.executeUpdate();
    39. 39. Transactions and JDBC <ul><li>Transaction = more than one statement which must all succeed (or all fail) together </li></ul><ul><li>If one fails, the system must reverse all previous actions </li></ul><ul><li>Also can’t leave DB in inconsistent state halfway through a transaction </li></ul><ul><li>COMMIT = complete transaction </li></ul><ul><li>ROLLBACK = abort </li></ul>
    40. 40. Example <ul><li>Suppose we want to transfer money from bank account 13 to account 72: </li></ul>PreparedStatement pstmt = con.prepareStatement(“update BankAccount set amount = amount + ? where accountId = ?”); pstmt.setInt(1,-100); pstmt.setInt(2, 13); pstmt.executeUpdate(); pstmt.setInt(1, 100); pstmt.setInt(2, 72); pstmt.executeUpdate(); What happens if this update fails?
    41. 41. Transaction Management <ul><li>Transactions are not explicitly opened and closed </li></ul><ul><li>The connection has a state called AutoCommit mode </li></ul><ul><li>if AutoCommit is true, then every statement is automatically committed </li></ul><ul><li>if AutoCommit is false, then every statement is added to an ongoing transaction </li></ul><ul><li>Default: true </li></ul>
    42. 42. AutoCommit <ul><li>If you set AutoCommit to false, you must explicitly commit or rollback the transaction using Connection.commit() and Connection.rollback() </li></ul><ul><li>In order to work with LOBs, you usually have to set AutoCommit to false, while retrieving the data </li></ul><ul><li>Note: DDL statements in a transaction may be ignored or may cause a commit to occur. The behavior is DBMS dependent </li></ul>setAutoCommit(boolean val)
    43. 43. Fixed Example con.setAutoCommit(false); try { PreparedStatement pstmt = con.prepareStatement( “update BankAccount set amount = amount + ? where accountId = ?” ); pstmt.setInt(1,-100); pstmt.setInt(2, 13); pstmt.executeUpdate(); pstmt.setInt(1, 100); pstmt.setInt(2, 72); pstmt.executeUpdate(); con.commit(); catch (Exception e) { con.rollback(); }
    44. 44. Isolation Levels <ul><li>How do different transactions interact? Do they see what another has written? </li></ul><ul><li>Possible problems: </li></ul><ul><ul><li>Dirty Reads: a transaction may read uncommitted data </li></ul></ul><ul><ul><li>Unrepeatable Reads: two different results are seen when reading a tuple twice in the same transaction </li></ul></ul><ul><ul><li>Phantom Reads: tuples are added to a table between two readings of this table in a single transaction </li></ul></ul>
    45. 45. Isolation Levels JDBC defines four isolation modes : Yes No No Repeatable Read No No No Serializable Yes Yes No Read Commited Yes Yes Yes Read Uncommited Phantom Read Unrepeatable Read Dirty Read Level
    46. 46. Isolation Levels <ul><li>Set the transaction mode using setTransactionIsolation() of class Connection </li></ul><ul><li>Oracle only implements: </li></ul><ul><ul><li>TRANSACTION_SERIALIZABLE </li></ul></ul><ul><ul><ul><li>An exception may be thrown if serializability isn’t possible </li></ul></ul></ul><ul><ul><li>TRANSACTION_READ_COMMITED </li></ul></ul><ul><ul><ul><li>This is the default </li></ul></ul></ul>
    47. 47. Level: READ_COMMITED <ul><li>Transaction 1: </li></ul><ul><li>insert into A values(1) </li></ul><ul><li>insert into A values(2) </li></ul><ul><li>commit </li></ul><ul><li>Transaction 2: </li></ul><ul><li>select * from A </li></ul><ul><li>select * from A </li></ul>Table: A 1 2 Question: Is it possible for a transaction to see 1 in A, but not 2? Question: Is it possible for the 2 queries to give different answers for level SERIALIZABLE?
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×