Primeiro, três métodos de programação de inserção em lote JDBC são introduzidos para compará -los. O conteúdo específico é o seguinte
A inserção em lote JDBC é usada principalmente para importação e log de dados porque os logs geralmente são gravados no arquivo primeiro.
Eu usei o driver JDBC do MySQL 5.1.5 para testar mais três métodos usados
Método 1: Use PreparedStatement para adicionar lotes
tente {Class.ForName ("com.mysql.jdbc.driver"); Conn = DriverManager.getConnection (O_URL, nome de usuário, senha); Conn.SetAutocomit (false); String sql = "Insira adlogs (ip, site, yyyymmdd, hour, object_id) valores (?,?,?,? ,?)"; PreparedStatement Press = Conn.Preparestatement (SQL, ResultSet.Type_Scroll_sensitive, ResultSet.Concur_Read_only); for (int x = 0; x <tamanho; x ++) {prest.SetString (1, "192.168.1.1"); Prest.SetString (2, "localhost"); Prest.SetString (3, "20081009"); Prest.setInt (4, 8); Prest.SetString (5, "11111111"); prest.addbatch (); } prest.executeBatch (); Conn.Commit (); Conn.Close (); } catch (sqLexception ex) {Logger.getLogger (myLogger.class.getName ()). log (Level.severe, null, ex); } catch (classNotFoundException ex) {Logger.getLogger (myLogger.class.getName ()). log (Level.severe, null, ex); } Explique o significado dos dois parâmetros a seguir ao criar uma declaração:
O primeiro parâmetro especifica o tipo de resultado do resultado. As opções são:
Type_forward_only: tipo padrão. O acesso direto é permitido apenas uma vez e não será afetado pelas alterações feitas por outros usuários no banco de dados.
Type_scroll_insensitive: permite o movimento avançado ou para trás na lista e até um posicionamento específico, como passar para o quarto registro da lista ou mover dois registros para trás da posição atual. Não será afetado pelas alterações feitas por outros usuários no banco de dados.
Type_scroll_sensitive: como type_scroll_insensitive, o posicionamento é permitido nos registros. Esse tipo é afetado pelas alterações feitas por outros usuários. Se o usuário excluir um registro após a execução da consulta, esse registro desaparecerá do ResultSet. Da mesma forma, as alterações nos valores de dados serão refletidas no conjunto de resultados.
O segundo parâmetro define a concorrência do resultado do resultado, que determina se o conjunto de resultados pode ser atualizado. As opções são:
Concur_read_only: este é o valor padrão, especificado que não pode ser atualizado
ResultSet Concur_UpDatable: Especifica que o ResultSet pode ser atualizado
Método 2: Use a instrução para adicionar o método em lote
Conn.SetAutocomit (false); Instrução stmt = conn.createstatement (resultSet.type_scroll_sensitive, resultSet.concur_read_only); para (int x = 0; x <size; x ++) {stmt.addbatch ("inserir em adlogs (ip, site, yyyyymmdd, hour, object_id) valores ('192.168.1.3', 'localhost', '20081009', 8, '23123')"); } stmt.executeBatch (); Conn.Commit ();Método 3: Use a declaração diretamente
Conn.SetAutocomit (false); Instrução stmt = conn.createstatement (resultSet.type_scroll_sensitive, resultSet.concur_read_only); para (int x = 0; x <size; x ++) {stmt.execute ("inserir em adlogs (ip, site, yyyyymmdd, hora, object_id) valores ('192.168.1.3', 'localhost', '20081009', 8, '23123')"); } Conn.Commit (); O tempo médio de teste para inserir 100.000 dados de dados usando o método acima é:
Método 1: 17.844s
Método 2: 18.421s
Método 3: 16.359s
Pode -se observar que a inserção das instruções em lote JDBC não apenas não melhora o desempenho, mas é mais lenta do que quando nenhum lote é usado. Obviamente, isso pode estar relacionado ao método de implementação dos drivers específicos da JDBC. O anexo é o meu código de teste, que pode ser usado para ser executado no meu computador.
Ao executar a inserção em lote, o mais importante é cancelar automaticamente o envio, para que não importa se a sintaxe do lote do JDBC é ou não usada.
Conn.SetAutocomit (false)
Pessoalmente, acho que o primeiro método é o mais conveniente e prático.
Exemplo de explicação dos dados de inserção em lote JDBC :
Recentemente, quando eu estava trabalhando em um programa para importar dados do Excel em um banco de dados, estava me preparando para usar a inserção em lote JDBC devido à grande quantidade de dados. Portanto, o preparestatement.addbatch () é usado; Quando os dados de 1W são adicionados, a operação de inserção é realizada, preparadostatement.executeBatch () é usado. Eu pensei que isso seria rápido, mas levei mais de 30 minutos para inserir 65.536 dados, o que estava completamente além das minhas expectativas. Então, perguntei aos meus colegas como eles processaram esse tipo de importação de dados em larga escala. Descobri que eles também usaram o processamento de inserção em lote JDBC, mas, ao contrário de mim, eles usaram Con.SetAutocommit (false); Em seguida, preparou -se preparado. Então eu tentei de novo, o que é um milagre? Demorou apenas meia hora para importar esses dados e, depois de adicionar essas duas frases, levou apenas 15 segundos para concluí -los. Então, verifiquei o motivo e encontrei a seguinte explicação online:
* Ao importar dados para o InnoDB, verifique se o MySQL não possui o modo autocomit ativado porque isso
Requer um log de descarga para disco para cada inserção. Para desativar a autocomit durante sua operação de importação, cercá -la com
Defina declarações autocomit e cometer:
Defina autocoméritico = 0;
... declarações de importação SQL ...
COMPROMETER-SE;
A primeira vez, é precisamente porque não há setautocomit (false); Para cada instrução de inserção, um log será gerado para o disco. Portanto, embora a inserção do lote seja definida, seu efeito é como uma única inserção, resultando em uma inserção muito lenta.
Alguns dos códigos são os seguintes:
String sql = "inserir na tabela *****"; con. // inserir registros 1W uma vez se (i % 10000 == 0) {ps.executeBatch (); con.Commit (); }} // Insira menos de 1W dados PS.ExecuteBatch (); con.Commit ();O exposto acima é apenas um acompanhamento e, em seguida, "servir" é seguido por:
1. Dados de escrita em lote de teste
long start = system.currenttimemillis (); DaorEcord Daorecord = new DaorEcord (); List <t> list = new ArrayList <T> (); for (int i = 1; i <= 1000; i ++) {for (int j = 1; j <= 1000; j ++) {t t = new t (); t.seti (i); t.setJ (j); list.add (t); }} Daorecord.insertBatch (list); System.out.println ("demorado:" + (System.CurrentTimemillis ()-Start) + "MS"); 2. Teste de dados de gravação em lote
public void insertBatch (list <t> list) {string sql = "inserir em t (vá, de volta) valores (?,?)"; Dbhelper dbh = novo dbhelper (sql); Conexão conn = dbh.returnConn (); tente {Conn.SetAutocomit (false); // Observe que esta frase deve ser falsa, consulte a primeira referência preparada PS = Conn.Preparestatement (SQL); for (int i = 0; i <list.size (); i ++) {ps.setInt (1, list.get (i) .geti ()); ps.SetInt (2, list.get (i) .getj ()); ps.addbatch (); if (i % 10000 == 0) {ps.executeBatch (); Conn.Commit (); }} ps.executeBatch (); Conn.Commit (); Conn.Close (); } catch (sqLexception e) {// TODO Gerado automaticamente Catch Block E.PrintStackTrace (); }}Tabela de dados:
Resultados experimentais:
O exposto acima é tudo sobre este artigo, espero que seja útil para o aprendizado de todos.