Insert em bancos relacionados [RESOLVIDO]

Olá galera, sei que está deve ser uma dúvida frequente, preciso realizar um insert em tabelas relacionadas ao mesmo tempo, para isso eu estou fazendo algo assim "insert into tabela(idrelacao,…) values((select max(id) from outratabela),…) com isto eu consigo pegar o ultimo id inserido, porém, isto não é totalmente seguro por que entre os insert pode ocorrer um insert com outra instancia do programa em meio tempo, ocasionando o ultimo id não ser o correto, andei lendo e descobri o getGeneratedKeys que deve funcionar uma beleza pra quem usa Statement, porém eu uso PreparedStatement que não suporta esse recurso, alguém poderia informar qual o mais correto nessa situação. Obrigado!

Depende do banco que você está utilizando, qual é?

Ve se te ajuda

PreparedStatement pstmt = ...;
pstmt.executeUpdate("INSERT...", Statement.RETURN_GENERATED_KEYS);
		
ResultSet generatedKeys = pstmt.getGeneratedKeys();

No MySQL você pode pegar o último id inserido depois que você insere seu registro:

PreparedStatement ps = conexao.prepareStatement("SELECT LAST_INSERT_ID()");

ResultSet rs = ps.executeQuery();

int id = 0;
if (rs.next()) {
    id = rs.getInt(1);
}

Já no Oracle, você usa as chamadas ‘Sequences’, aí você deve pegar o valor do id antes de inserir no banco, assim:

 PreparedStatement ps = conexao.prepareStatement("SELECT NOMESEQUENCIA.NEXTVAL FROM DUAL");

ResultSet rs = ps.executeQuery();

int id = 0;
if (rs.next()) {
    id = rs.getInt(1);
}

Porém ainda gostaria de testar da maneira que o rogelgarcia postou, me pareceu mais claro…

Espero ter ajudado, abraço.

rogelgarcia, tudo bem?

Como você faria para executar, da mesma maneira que você demonstrou, em um banco de dados que usa ‘Sequences’.

Gostaria de usar aqui no meu trabalho.

Abraço!

Com sequence… vc faz com duas queries…

Uma para pegar o proximo valor do sequence…

E outra pra fazer o insert mesmo… aí nao vai ter o problema do generatedKeys…

No insert vc usa o valor do sequence que voce conseguiu na primeira query

É do jeito que vc estava fazendo mesmo :smiley:

Valeu Rógel!

Abraço!

Às ordens.!!

Até mais

Desculpa a demora, então esqueci de mencionar, estou usando Access por enquanto apenas durante o desenvolvimento por questões pessoais, mas o projeto final vai ser com mysql, mas então, este comando SELECT LAST_INSERT_ID() não seria a mesma coisa de “SELECT MAX(ID) FROM TABELA” ? A menos que tenha como retornar junto ao insert o valor, por que senão ainda há o risco de pegar o ultimo id de forma errado se uma inserção ocorrer em meio tempo.

O ‘SELECT LAST_INSERT_ID()’, você executa depois da inserção.

Essa função do MySQL garante que o id retornado é o que você acabou de inserir.

Essa função não é a mesma coisa que o ‘SELECT MAX(ID) FROM TABELA’ não. Imagine que tenha vários usuários inserindo na mesma tabela, o ‘SELECT LAST_INSERT_ID()’ vai garantir o id que você acabou de inserir, já o ‘SELECT MAX(ID) FROM TABELA’ vai pegar o maior id e não o que você acabou de inserir.

Por exemplo se você iniciou a transação de inserção e outro usuário inseriu um registro durante sua transação, se você utilizar ‘SELECT MAX(ID) FROM TABELA’ você estará pegando o valor do maior índice e não o índice que você acabou de inserir, entendeu?

O ‘SELECT LAST_INSERT_ID()’ garante isso.

Dá uma olhada nesse link:

http://dev.mysql.com/doc/refman/4.1/en/getting-unique-id.html

Espero ter ajudado a esclarecer!

Abraço!

Acho que entendi, agora estou tentando encontrar algo semelhante ao LAST_INSERT_ID() no Access.

Tente utilizar…

‘SELECT @@identity

Nunca usei, vi isso aqui:

http://forum.imasters.uol.com.br/index.php?/topic/357776-funcao-last-insert-id-em-access/

Espero ter ajudado!

Abraço!

O Access não permite que você force o insert com a chave preenchida?

Se permitir, faz o “Select max” antes de inserir e preenche na query… dessa maneira não tem história de pegar a chave errada… no máximo você vai ter uma “ConstraintViolationException” na hora de mandar para o banco com uma chave duplicada…

Sinceramente não gosto nem um pouco dessa idéia de pegar o índice com ‘SELEC MAX(ID) TABELA’.

Fica parecendo gambiarra (nada contra quem usa).

nephestos , se funcionar o ‘SELECT @@identity’ no access você posta aí por favor.

Abraço!

Deu certo não, se tiverem outras soluções favor postar.

Tem uma solução que eu creio que praticamente iria funcionar 100%, se eu tivesse um outro campo na minha tabela e este campo fosse um campo único, tipo cpf, dai bastava eu da uma select (ID) from Tabela where cpf=valorcpfdofield. Creio que assim não teria erro, mas porém eu meio que ia forçar a existência de um campo unico.

Concordo com você, é gambiarra mesmo. O problema você mesmo explicou, o MAX(ID) pode não retornar o registro que você esperava.

nephestos, não aguentei a curiosidade e testei no MS Access 2003.

import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class Main {

    static Connection theConn;

    public static void main(String args[]) {
        try {
            theConn = MyConnection.getConnection();

            PreparedStatement ps = theConn.prepareStatement("INSERT INTO PESSOA (NOME) VALUES ('JOAO')");
            ps.executeUpdate();


            ps = theConn.prepareStatement("SELECT @@identity");
            ResultSet rs = ps.executeQuery();

            while (rs.next()) {
                System.out.println(rs.getInt(1));
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (theConn != null) {
                    theConn.close();
                }
            } catch (Exception e) {
            }
        }

    }
}

class MyConnection {

    public static Connection getConnection() throws Exception {
        Driver d = (Driver) Class.forName("sun.jdbc.odbc.JdbcOdbcDriver").newInstance();
        Connection c = DriverManager.getConnection("jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=d:/temp/teste.mdb");
        return c;
      
    }
}

Funcionou perfeitamente, dá uma revisada aí no seu código, ou também pode ser a versão o Access que não aceita ‘SELECT @@identity’ (isso já não sei te informar) hehe.

Espero ter ajudado!

Abraço!

Obrigado pelas respostas.

Estamos aí pra isso…

Deu certo?

Se deu certo, mude o nome do tópico adicionando [RESOLVIDO] no final.

Abraço!