Java DataBase Conectivity (JDBC) Curso de Linguagem Java José Antonio F. de Macêdo [email protected] JDBC JDBC (Java DataBase Conectivity): permite que aplicação Java (ou Applet) trabalhe com Bancos de Dados Relacionais é um conjunto de APIs (bibliotecas de classes) INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 2 JDBC API para executar comandos SQL: classes e interfaces escritas em Java permite envio de comandos SQL para QUALQUER SGBD Relacional com Java e API JDBC, alunos acessam BD em Intranet a partir de PCs, Macs ou workstations UNIX INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 3 Tipos de Drivers JDBC 1: JDBC-ODBC bridge mais ODBC driver JDBC acessa banco de dados via ODBC driver 2: Driver implementado com API nativa parcialmente escrita em Java Chamadas JDBC convertidas em código específico do banco de dados 3: Driver Java puro usando protocolo JDBC-Net JDBC usa protocolo de rede idenpendente to BD 4: Driver Java puro usando protocolo nativo: JDBC usa protocolo de rede usado pelo BD INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 4 JDBC Architecture Java Application JDBC API JDBC Driver Manager JDBC Driver API (T1) JDBCODBC Bridge ODBC Driver (T2) Java Portion Native Portion (T3) Java Client Server Component (T4) Java Driver to vendor's protocol Proprietary, vendor-specific database access protocol INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo JDBC Drivers Provided with Sun's JDK 5 JDBC Architecture (cont.) Application JDBC Driver Cógigo Java chama biblioteca JDBC JDBC carrega um driver Driver conversa com um banco de dados Podemos ter mais de um driver -> mais do que um banco de dados Ideal: podemos mudar o banco de dados sem termos que mudar o código da aplicação INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 6 Classes JDBC java.sql.* prove classes para serem usadas pelas aplicações <<Interface>> Statement <<Singleton>> DriverManager INF 1345 - Java Avançado <<Interface>> Connection <<Interface>> PreparedStatement <<Interface>> ResultSet <<Interface>> DatabaseMetaData <<Interface>> CallableStatement <<Interface>> ResultSetMetaData Copyright © 2003 Jose Antonio F. Macedo 7 Pacotes importantes import java.sql.*; //JDBC packages import java.math.*; import java.io.*; import oracle.jdbc.driver.*; // Driver Oracle INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 8 Sete passos básicos 1. 2. 3. 4. 5. 6. 7. Carregar Driver Definir URL de conexão Estabelecer conexão Criar objeto do tipo statement Executar uma consulta Processar resultado Fechar Conexão INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 9 1. Carregar Driver Temos que registrar o driver usando o seguinte comando java: Class.forName(“oracle.jdbc.driver.OracleDriver"); Chamando Class.forName, automaticamente Criamos uma instância do driver Registramos o driver no DriverManager INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 10 1. Carregar Driver - Outra opção Outra forma de carregar o driver é criar uma instancia do driver e registrá-la no DriverManager: Driver driver = new oracle.jdbc.OracleDriver(); DriverManager.registerDriver(driver); INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 11 1. Carregar Driver - Exemplo try { Class.forName(“com.sybase.jdbc.SybDriver”); Class.forName(“oracle.jdbc.driver.OracleDriver”); Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”); } catch (ClassNotFoundException e) { System.out.println(“Erro ao carregar Driver ”); } INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 12 The DriverManager DriverManager tenta carregar todos os drivers Usa o primeiro que funciona Quando um driver é carregado, ele registra junto ao DriverManager INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 13 2. Definir URL de conexão String OracleURL = “jdbc:oracle:[email protected]: 1521:meuBD”; String SybaseURL = “jdbc:sybase:tds:servidor.com:1 234:?SERVICENAME=meuBD”; String OdbcURL = “jdbc:odbc:nomeFonteDados”; INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 14 3. Estabelecer conexão String path = "jdbc:oracle:thin:"; String host = “tecbd.inf.puc-rio.br"; A senha é String port = "1521"; igual ao login String db = “tecbd"; String login = “maria"; String url = path + login + "/" + login + "@" + host +":" + port + ":" + db; Class.forName("oracle.jdbc.driver.OracleDriver"); Connection con = DriverManager.getConnection( INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo url ); 15 3. Estabelecer conexão – outra forma String OracleURL = “jdbc:oracle:[email protected]:1521:BD”; String login = “aluno”; String senha = “senhaAluno”; Connection conexao = DriverManager.getConnection ( OracleURL, login, senha ); INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 16 4. Criar objeto do tipo statement Statement createStatement() Retorna um novo objeto Statement PreparedStatement prepareStatement(String sql) Retorna um novo objeto PreparedStatement CallableStatement prepareCall(String sql) Retorna um novo objeto CallableStatement Qual a diferença ? Performance. INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 17 Consultando com Statement String queryStr = "SELECT * FROM Member " + "WHERE Lower(Name) = 'harry potter'"; Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(queryStr); • Statements são usados para executar consultas que são realizadas apenas uma vez. • O método executeQuery retorna um objeto ResultSet object o qual representa o resultado da consulta. INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 18 Alterando o BD com Statement String deleteStr = “DELETE FROM Member " + "WHERE Lower(Name) = ‘lord voldemort’"; Statement stmt = con.createStatement(); int delnum = stmt.executeUpdate(deleteStr); • executeUpdate é usado para manipulação de dados: insert, delete, update, create table, etc. (qualquer coisa que não seja consulta!) • executeUpdate retorna o número de linhas modificadas. INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 19 Sobre Prepared Statements Prepared Statements são usados por consultas que são realizadas muitas vezes. Eles são interpretados somente uma vez (pré-compilados). Usando setString(i, value), setInt(i, value), etc. o i-ésimo ponto de interrogação receberá o valor definido. INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 20 Consultando com PreparedStatement String queryStr = "SELECT * FROM Program " + "WHERE Name = ? and Cost < ?”; PreparedStatement pstmt = con.prepareStatement(queryStr); pstmt.setString(1, “Unfogging the Future”); pstmt.setInt(2, 1000); ResultSet rs = pstmt.executeQuery(); INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 21 Alterando o BD com PreparedStatement String deleteStr = “DELETE FROM Program " + "WHERE Name = ? and Cost < ?”; PreparedStatement pstmt = con.prepareStatement(deleteStr); pstmt.setString(1, “Unfogging the Future”); pstmt.setInt(2, 1000); int delnum = pstmt.executeUpdate(); INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 22 CallableStatement Usado para chamar Stored Procedures. Formato da string: { [? = ] call my_proc[(p1, p2)] } INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 23 CallableStatement Metodos registerOutParameters() setString(), setInt() close() INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 24 CallableStatement - Exemplo String qr = “{ call my_sp(?, 25, ?) }”; CallableStatement cs = conn.prepareCall(query); cs.setString(1, “John”); cs.registerOutParameter(2, Types.INT); cs.execute() cs.close() INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 25 Statements vs. PreparedStatements: Cuidado! É a mesma coisa ? O que eles fazem? 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); INF 1345+ - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 26 Statements vs. PreparedStatements: Cuidado! Isto sempre vai funcionar ? Statement stmt = con.createStatement( ); ResultSet rs = stmt.executeQuery(“select * from R where A=‘ ” + val + “ ’ ”); • Moral: Quando estiver lendo dados digitados pelo usuário, sempre use PreparedStatement INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 27 Statements vs. PreparedStatements: Cuidado! Isto vai funcionar? PreparedStatement pstmt = con.prepareStatement(“select * from ?”); pstmt.setString(1, myFavoriteTableString); INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 28 ResultSet A ResultSet prove acesso aos dados de uma tabela gerados pela execução de uma consulta. Somente um ResultSet por Statement pode ser aberto a cada vez. As linhas da tabela são recuperadas em seqüencia. Um ResultSet mantém um cursor apontando para a linha corrente. O método 'next' move o cursor para a próxima linha. INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 29 Métodos ResultSet boolean next() Aponta para a próxima linha A primeira chama de next() ativa a primeira linha Retorna falso se não existirem mais linhas void close() fecha ResultSet Permite que voce reuse o Statement que o criou Chamado automaticamente pela maioria dos métodos do Statement INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 30 ResultSet Methods Type getType(int columnIndex) Retorna o tipo de uma dada coluna, dada sua posição Colunas são indexadas começando por 1 (não 0) Type getType(String columnName) Retorna o tipo de uma dada coluna, dado seu nome Menos eficiente int findColumn(String columnName) Retorna o índice de uma determinada coluna dado seu nome INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 31 ResultSet Methods String getString(int columnIndex) boolean getBoolean(int columnIndex) byte getByte(int columnIndex) short getShort(int columnIndex) int getInt(int columnIndex) long getLong(int columnIndex) float getFloat(int columnIndex) double getDouble(int columnIndex) Date getDate(int columnIndex) Time getTime(int columnIndex) Timestamp getTimestamp(int columnIndex) INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 32 ResultSet Methods String getString(String columnName) boolean getBoolean(String columnName) byte getByte(String columnName) short getShort(String columnName) int getInt(String columnName) long getLong(String columnName) float getFloat(String columnName) double getDouble(String columnName) Date getDate(String columnName) Time getTime(String columnName) Timestamp getTimestamp(String columnName) INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 33 isNull Em SQL, NULL significa que o atributo é vazio Não é a mesma coisa que 0 or “” Em JDBC, voce deve explicitamente verificar se um atributo é nulo usando o seguinte método ResultSet.isNull(coluna) INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 34 Imprimindo a saída de uma consulta: Imprimindo cabeçalhos: ResultSetMetaData rsmd = rs.getMetaData(); int numcols = rsmd.getColumnCount(); for (int i = 1 ; i <= numcols; i++) { if (i > 1) System.out.print(","); System.out.print(rsmd.getColumnLabel(i)); } INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 35 Imprimindo a saída de uma consulta: while (rs.next()) { for (int i = 1 ; i <= numcols; i++) { if (i > 1) System.out.print(","); System.out.print(rs.getString(i)); } System.out.println(""); } • Para pegar o dado da i-ésima coluna: rs.getString(i) • Para pegar o dado da coluna Abc: rs.getString(“Abc”) INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 36 Usando a interface MetaData ResultSet: ResultSetMetaData getMetaData() ResultSetMetaData prove vários métodos para descoberta de informação sobre a estrutura de um ResultSet: getColumnClassName(int col): retorna o nome da classe java associada ao tipo da coluna; ex. Java.lang.Integer, etc. getColumnCount(): retorna o número de colunada de um ResultSet getColumnDisplaySize(int col): retorna o o tamanho de caracteres de uma coluna getColumnName(int col): retorna o nome da coluna int getColumnType(int col): retorna o tipo de um valor armazenado em uma coluna (java.sql.Types); ex. Value 12 = JDBC VARCHAR, etc. getPrecision(int col): para colunas numéricas retorna a precisão e para outras retorna o número de bytes da coluna INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 37 Mapeando tipos Java em tipos SQL SQL type Java Type CHAR, VARCHAR, LONGVARCHAR String NUMERIC, DECIMAL java.math.BigDecimal BIT boolean TINYINT byte SMALLINT short INTEGER int BIGINT long REAL float FLOAT, DOUBLE double BINARY, VARBINARY, LONGVARBINARY byte[] DATE java.sql.Date TIME java.sql.Time TIMESTAMP java.sql.Timestamp INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 38 Tratamento de Tempo Tempo em SQL não são padronizados Java define três classes para ajudar neste tratamento java.sql.Date year, month, day java.sql.Time hours, minutes, seconds java.sql.Timestamp year, month, day, hours, minutes, seconds, nanoseconds INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 39 Fechando conexões, statements, … Lembre-se de fechar Connections, Statements, PreparedStatements e ResultSets con.close(); stmt.close(); pstmt.close(); rs.close() INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 40 Lidando com exceções Uma exceção pode englobar outras exceções. catch (SQLException e) { while (e != null) { System.out.println(e.getSQLState()); System.out.println(e.getMessage()); System.out.println(e.getErrorCode()); e = e.getNextException(); } } INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 41 JDBC 2.0 API JDBC 2.0 API Parte do JDK 1.2 A implementação JDBC deve suportar as funcionalidades do JDBC 2.0 INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 43 Novas Funcionalidades Scrollable ResultSet Atualizações diretas pelo programa Consultas Batch Suporte ao tipos de dados da norma SQL3 INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 44 Scrollable ResulSet Statement stmt = conn.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); ResultSet rs = stmt.executeQuery("select * from emp"); INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 45 Scrollable ResulSet (cont.) TYPE_FORWARD_ONLY Permite percorrer o resultset apenas do primeiro para o último registro. TYPE_SCROLL_SENSITIVE Permite percorrer o resultset em qualquer direção e o resultset será sensitivo às modificações realizadas por outras transações. TYPE_SCROLL_INSENSITIVE Permite percorrer o resultset em qualquer direção e o resultset NÃO será sensitivo às modificações realizadas por outras transações. CONCUR_READ_ONLY Resultset não pode ser atualizado (default) CONCUR_UPDATABLE Resultset pode ser atualizado INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 46 ResultSet Methods next() previous() afterLast() isAfterLast() beforeFirst() isBeforeFirst() first() isFirst() INF 1345 - Java Avançado last() isLast() absolute(1) absolute(-3) relative(3) relative(-3) getRow() Copyright © 2003 Jose Antonio F. Macedo 47 Programa para atualização Statement stmt = con.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE ); ResultSet rs = stmt.executeQuery("select * from emp"); INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 48 Atualizando Linha // move cursor para linha 5 rs . absolute(5) // Atualiza primeiro atributo com rs . updateString(1, “Joao”); valor “João” rs . updateInt(“Idade”, 50); // Atualiza atributo Idade com valor 50 rs . updateRow(); // Atualiza banco de dados rs . cancelRowUpdates() // Cancela atualizações (rollback) INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 49 Inserindo Linha rs . moveToInsertRow(); // move cursor para nova linha rs . updateString(“Nome”, “Maria”); // atualiza a coluna NOME com o valor Maria rs . updateInt(2, 60); // atualiza segunda coluna com valor 60 // Insere no ResultSet & Banco rs . insertRow() rs . moveToCurrentRow() INF 1345 - Java Avançado // Move o cursor para coluna que foi inserida Copyright © 2003 Jose Antonio F. Macedo 50 Apagando Linha rs . last() rs . deleteRow() INF 1345 - Java Avançado // move cursor para última linha // apaga a linha apontada pelo cursor Copyright © 2003 Jose Antonio F. Macedo 51 Atualizações Batch Statement st = conn . createStatement(); int[] retArr; conn . setAutoCommit(false); st .addBatch( “insert into T1 values (“Jo”, 40)”); st .addBatch( “insert into T1 values (“Mo”, 45)”); retArr = st . executeBatch() INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 52 SQL3 Datatypes Blob (Binary Large Objects) Clob (Character Large Object) Array Struct create type myType ( i int , j int) INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 53 LOBs: Large OBjects Dois tipos: CLOB: Character large object (armazena caracteres) BLOB: Binary large object (armazena bytes) Os dados das colunas do tipo CLOB/BLOB são armazenados em separdos dos dados comuns. Um ponteiro é usado para referenciar a área onde são armazenados esses dados. INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 54 Lendo um CLOB create table userComments( user varchar(50), comment CLOB) ); Podemos usar getAsciiStream() a qual retorna um InputStream ResultSet rs = stmt.executeQuery(“select comment from userComments”); while (rs.next) { Clob c = rs.getClob(“comment”); Reader reader = c.getCharacterStream(); doSomething(reader) } INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 55 Inserindo um CLOB PreparedStatement pstmt = con.prepareStatement(“insert into userComments values(‘sara’, ?)”); Reader reader = new FileReader(fileName); pstmt.setCharacterStream(1, reader, Integer.MAX_VALUE); pstmt.executeUpdate(); Podemos usar setAsciiStream() a qual recebe InputStream INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 56 Inserindo um CLOB – outro exemplo File file = new File("myimage.gif"); FileInputStream fis = new FileInputStream(file); PreparedStatement ps = conn.prepareStatement("insert into images values (?,?)"); ps.setString(1,file.getName()); ps.setBinaryStream(2,fis,file.length()); ps.executeUpdate(); ps.close(); fis.close(); INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 57 Recuperando um BLOB PreparedStatement ps = con.prepareStatement("select oid from images where name=?"); ps.setString(1,"myimage.gif"); ResultSet rs = ps.executeQuery(); if(rs!=null) { while(rs.next()) { InputStream is = rs.getBinaryInputStream(1); } rs.close(); } ps.close(); INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 58 Transações Transaction = mais de um comando SQL porém todos devem ter sucesso ou nenhum terá sucesso Se um comando falha, todas as modificações deve sem desfeitas Não pode ser deixado o BD em estado incosistente COMMIT = complete transaction ROLLBACK = abort INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 59 Exemplo Vamos supor que estamos realizando uma operação de transferência entre contas 13 para a conta 72: PreparedStatement pstmt = con.prepareStatement(“update BankAccount set amount = amount + ? where accountId = ?”); pstmt.setInt(1,-100); pstmt.setInt(2, 13); pstmt.executeUpdate(); O que acontece quando pstmt.setInt(1, 100); a atualização falha ? pstmt.setInt(2, 72); pstmt.executeUpdate(); INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 60 Gerenciamento de Transação As transações não são explicitamente abertas ou fechadas A conexão possui um estado denominado AutoCommit Se AutoCommit é true, então todo comando será efetuado automaticamente como se estivesse em uma transação separada Se AutoCommit é false, então todo comando participa de uma só transação Default: true INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 61 AutoCommit Connection.setAutoCommit(boolean val) Se AutoCommit é definido para false, voce deve explicitar os comandos de commit ou rollback da transação usando Connection.commit() ou Connection.rollback() Quando estiver trabalhando com LOBs, voce deve usar definir AutoCommit para false, enquanto recupera os dados Nota: comando DDL dentro de uma transação podem ser ignorados ou podem causar um commit. O comportamento vai depender do BD usado. INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 62 Exemplo consertado 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(); Copyright © 2003 Jose Antonio F. Macedo } INF 1345 - Java Avançado 63 Transações - Resumo conn.setAutoCommit(false); .... Comandos SQL pertencentes a transação ... con.commit(); con.setAutoCommit(true); INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 64 Transações - Exemplo con.setAutoCommit(false); PreparedStatement updateSales = con.prepareStatement( "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ?"); updateSales.setInt(1, 50); updateSales.setString(2, "Colombian"); updateSales.executeUpdate(); PreparedStatement updateTotal = con.prepareStatement( "UPDATE COFFEES SET TOTAL = TOTAL + ? WHERE COF_NAME LIKE ?"); updateTotal.setInt(1, 50); updateTotal.setString(2, "Colombian"); updateTotal.executeUpdate(); con.commit(); con.setAutoCommit(true); INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 65 Níveis de Isolamento Como as transações interagem ? JDBC suporta 4 “níveis de isolamento” Devemos usar o comando: Connection.setTransactionIsolation Oracle somente implementa: TRANSACTION_SERIALIZABLE TRANSACTION_READ_COMMITED INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 66 Níveis de Isolamento (cont.) TRANSACTION_SERIALIZABLE: transações são equivalentes a transações seriais TRANSACTION_READ_COMMITED: Uma transação pode ler dados de uma outra transação que comitou INF 1345 - Java Avançado Copyright © 2003 Jose Antonio F. Macedo 67