A principal pesquisa deste artigo é o nível de Hibernate session_flush e isolamento. A introdução e exemplos específicos são os seguintes.
Vejamos alguns conceitos primeiro:
1. Leitura suja: A leitura suja também é chamada de leitura de dados inválidos. Isso significa que, durante o acesso ao banco de dados, a coisa T1 modifica um determinado valor e, em seguida, o T2 lê o valor. Depois disso, o T1 cancela a modificação do valor por algum motivo, o que faz com que os dados lidos por T2 sejam inválidos. A leitura suja significa que, quando uma coisa é acessar dados e modificar os dados, e essa modificação não foi enviada ao banco de dados, outra coisa também acessa esses dados e depois usa esses dados. Como esses dados ainda não são enviados, os dados lidos por outra coisa são dados sujos e as operações executadas com base nos dados sujos estão incorretos.
2. Leitura não repetida: por exemplo, quando eu estava lendo um post, os dados que encontrei foram Zhang San e Li Si. Então, depois de me refrescar, descobri que o Zhang San inicial se tornou Zhang Ba. Esta é a chamada leitura não repetível, porque os dados que li não foram repetidos.
3. Leitura de fantasia: Quando eu estava procurando os dados, comecei a encontrar 3 registros. Quando eu o refresci, descobri que os registros se tornaram 8. Esta é a leitura de fantasia.
4. Envie a leitura: você só pode ler após o envio. O Oracle padroniza isso. Não há leitura suja dessa maneira.
5. Repetibilidade: é obviamente o oposto da leitura não repetível. Pode evitar a leitura não repetível, mas isso não pode evitar a leitura fantasma.
6. serialização: esse método é muito rigoroso. Em termos leigos, quando estou fazendo algo, ninguém mais pode fazê -lo. É muito seguro, mas é extremamente ineficiente.
Abaixo, usamos exemplos práticos para entender a aplicação da folga do cache de hibernato.
O banco de dados de mapeamento de hibernato está relacionado à estratégia de geração de chaves primárias.
Exemplos de geração de chaves primárias no UUID:
public class User {private string uid; private string uname; data privada aniversário; public string getUid () {retorna uid;} public void setuid (string uid) {this.uid = uid;} public string getUname () {return uname;} public void setUname (string unsame) {this.Uname =; setbirthday (data de aniversário) {this.birthday = aniversário;}}User.hbm.xml:
<? xml versão = "1.0"?> <! Doctype hibernate-mapping public "-// Hibernate/hibernate mapeando dtd 3.0 // pt" "http://hibernate.sourceforge.net/hibernate package = "com.lixue.bean"> <!-O nome do nó da classe representa o nome da classe da entidade, e a tabela representa o nome da entidade mapeada para a tabela no banco de dados-> <! Nome = "user" tabela = "t_user"> <id = "uid"> <!-generate através de uuid- name = "Aniversário"/> </s class> </hibernate-mapping>
Método de teste:
/ ***Teste a estratégia de geração de chave primária UUID*/ public void testSave1 () {/*sessão definida e coisas*/ sessão session = null; Transação transação = nulo; tente { /*obter sessão e coisas* / session = hibernateUtils.getSession (); transação = session.begIntransaction (); /*Crie usuário*/ usuário do usuário = new User (); user.setUname ("xi jinping"); user.setBirthday (new Date ()); / *** Como a estratégia de geração de chaves primária do usuário é UUID, após a chamada salvar, apenas inclui o usuário no gerenciamento de sessões* A instrução Insert não será emitida, mas o ID foi gerado, e o status existencyBase no persistencecontext é falso*/ session.save (usuário); /** * Calling flush, Hibernate will clean up the cache (insert the objects in the temporary collection in session->insertions into the database, clearing the temporary collection) * At this time, the data cannot be seen in the database, but if the isolation level of the database is set to not submitted to read, * Then we can see the flushed data, and the existencesInDatabase status in PersistenceContext is true */ session.flush (); /** * Envie as coisas * Por padrão, a operação de confirmação executará o cache de limpeza de descarga, * para que os dados não possam ser revertidos após chamar Flush sem exibir * Commit * transaction.Commit (); } catch (Exceção e) {e.printStackTrace (); transaction.rollback (); } finalmente {hibernateutils.closhessession (sessão); }} Podemos depurar o programa através de pontos de interrupção:
1. Como a taxa lateral da geração de chaves primárias do usuário é UUID, depois de chamar o método SALVE (), o objeto do usuário só pode ser incluído no gerenciamento da sessão, e a instrução INSERT não será emitida, mas o ID foi gerado (NOTA: Duas lugares são muito importantes após a economia. Primeiro, há um elemento na sessão-> actionue-> insertio-> elementData MRAY. PersistEncecontext-> entityEntries-> map-> tabela-> Um determinado elemento da matriz-> Valor armazena o objeto. Como mostrado na imagem:
2 Após chamar o método Flush (), o valor armazenado temporário do ActionQueue na sessão será limpo e, em seguida. os dados. Depois de chamar o método Commit (), há dados no banco de dados.
Exemplo de geração de chaves primárias de maneira nativa:
classe pública user1 {private inteiro uid; string privada uname; data privada aniversário; public integer getUid () {return uid;} public void setuid (integer uid) {this.uid = uid;} public string getUname () {retorna uname;} public void setUname (string (string) {this. this.name; aniversário;} public void setbirthday (data de aniversário) {this.birthday = aniversário;}}User1.hbm.xml:
<? xml versão = "1.0"?> <! Doctype hibernate-mapping public "-// Hibernate/hibernate mapeando dtd 3.0 // pt" "http://hibernate.sourceforge.net/hibernate package = "com.lixue.bean"> <!-Nó da classe Node representa o nome da classe da entidade (lembre-se de modificar o nome da classe ao atribuir o arquivo de mapeamento, caso contrário, ocorrerá um bug), a tabela representa o nome da entidade mapeada para a tabela no banco de dados-> <class "user1" "tabela =" t_awer1 "> <DeRer1"> </id> <propriedade name = "uname"/> <propriedade name = "aniversário"/> </class> </hibernate-mapping>
Método de teste:
/ ***Teste a estratégia de geração de chave primária nativa*/ public void testSave2 () {/*sessão definida e coisas*/ sessão session = null; Transação transação = nulo; tente { /*obter sessão e coisas* / session = hibernateUtils.getSession (); transação = session.begIntransaction (); /*Crie usuário*/ user1 user = new user1 (); user.setUname ("li keqiang"); user.setBirthday (new Date ()); /** * Because the primary key generation strategy of User1 is native, after calling Session.save(), the insert statement will be executed, and the temporary collection object will be cleared* Return the ID generated by the database, included in the Session management, and modified the existencesInDatabase status in the Session to true, * If the isolation level of the database is set to not submitted to read, then we can see the saved data*/ session.Save (usuário); transaction.commit (); } catch (Exceção e) {e.printStackTrace (); transaction.rollback (); } finalmente {hibernateutils.closhessession (sessão); }} Depure o programa via ponto de interrupção:
1. Como a estratégia de geração de chaves primária é nativa, depois de chamar o método SAVE (), a instrução Insert será executada e os dados no objeto de coleta temporária serão limpos e o ID gerado pelo banco de dados será retornado.
2. Inclua o objeto no gerenciamento de sessões, modifique a propriedade ExistIndatabase no PersistEncEcontext para true (indica que existem dados correspondentes no banco de dados, mas não podem ser vistos por causa da área de isolamento).
Vamos testar outro método de hibernato, que é o despet (), que significa expulsar o objeto da sessão.
Para o programa que gera uma estratégia de chave primária UUID, aqui está um método de teste:
/ ***Teste a estratégia de geração de chave primária UUID*/ public void testSave3 () {/*sessão definida e coisas*/ sessão session = null; Transação transação = nulo; tente { /*obter sessão e coisas* / session = hibernateUtils.getSession (); transação = session.begIntransaction (); /*Crie usuário*/ usuário do usuário = new User (); user.setUname ("hu jintao"); user.setBirthday (new Date ()); /*** Como a estratégia principal de geração de chaves do usuário é UUID, depois de ligar para salvar, apenas incorporar o usuário no gerenciamento de sessão* não emitirá a instrução Insert, mas o ID foi gerado. O status existindateBase na sessão é false */ session.save (usuário); /*Despejo O objeto do usuário da sessão, isto é, expulso da propriedade EntityEntries do persistencecontext*/ session.evict (usuário); /** * Cannot successfully submit, because when Hibernate cleans up the cache, the user object is taken out from the session inserts temporary collection for insert * After the operation, the existencesInDatabase in the entityEntries property needs to be updated to true, and we call the evil method* Eviction the user from the entityEntries of the session, so the existencesInDatabase property cannot be found, and it cannot be updated, throwing an exception */ transaction.commit (); } catch (Exceção e) {e.printStackTrace (); transaction.rollback (); } finalmente {hibernateutils.closhessession (sessão); }} Depuração via ponto de interrupção:
1. Como a estratégia de geração de chaves primárias do UUID é usada, a instrução Insert não será enviada após chamar o método salv (). O objeto está incluído no gerenciamento da sessão. O ID foi gerado e não há dados correspondentes no banco de dados (ou seja, o valor do atributo existIndatabase é falso).
2. Depois de chamar o despet (), expela o objeto do usuário da sessão, ou seja, expulso da propriedade EntityEntries do PersistenceContext.
3. Quando chamo o método Commit () novamente, descobriremos que nossos dados não podem ser salvos porque, no início, nossa propriedade de indicação de existência era falsa, ou seja, não há dados correspondentes no banco de dados. Então, chamamos o mal () para excluir todas as propriedades do objeto no PersistenceContext (a propriedade existencendatabase também está incluída), mas os dados armazenados temporários no ActionQueue não foram excluídos. Quando chamamos o método Commit (), primeiro chamaremos implicitamente o método Flush (). A função desse método também já foi mencionada antes. Ele inserirá o objeto temporário no ActionQueue e, em seguida, definirá o valor da propriedade ExistIndatabase no PersistenceContext como true. Infelizmente, não há propriedades existentes no PersistenceContext, portanto, ocorrerá um erro, resultando na incapacidade de salvar.
Para fazer isso, melhoramos o procedimento acima:
/ ***Teste a estratégia de geração de chave primária UUID*/ public void testSave4 () {/*sessão definida e coisas*/ sessão session = null; Transação transação = nulo; tente { /*obter sessão e coisas* / session = hibernateUtils.getSession (); transação = session.begIntransaction (); /*Crie usuário*/ usuário do usuário = new User (); user.setUname ("hu jintao"); user.setBirthday (new Date ()); /*** Como a estratégia principal de geração de chaves do usuário é UUID, depois de ligar para salvar, apenas incorporar o usuário no gerenciamento de sessão* não emitirá a instrução Insert, mas o ID foi gerado. O status existenceIndateBase no PersistEncEContext é falso */ session.save (usuário); / ***Após o Flush, o Hibernate limpará o cache, salvará o objeto do usuário no banco de dados, limpará o objeto do usuário nas inserções na sessão*e definirá o status do existIndatabase no PersistenceContext para True*/ session.flush (); / * Despeja o objeto do usuário da sessão, ou seja, expulso da propriedade EntityEntries do PersistEncEContext */ session.evict (usuário); / *** Pode ser enviado com sucesso porque o hibernato não pode estar na coleção de inserções de sessão ao limpar o cache* O objeto do usuário foi encontrado (limpo quando o rubor foi chamado), para que a declaração de inserção não seja emitida, nem o status do existIndatabase na sessão não será atualizado*/ transaction.Commit (); } catch (Exceção e) {e.printStackTrace (); transaction.rollback (); } finalmente {hibernateutils.closhessession (sessão); }} NOTA: Após salvar, chamamos o método Flush () e, em seguida, chamamos o método evict () após o programa modificado.
Depuração via ponto de interrupção:
1. Como ainda é uma estratégia de geração UUID, depois de ligar para salvar, a instrução INSERT não será emitida, mas o objeto está incluído no gerenciamento da sessão. A propriedade ExistIndatabase em PersistenceContext é falsa.
2. Depois de ligar para salvar (), chamamos o método Flush () novamente. A função desse método é limpar o cache, ou seja, emitir uma instrução de inserção, inserir o objeto temporário nas inserções na sessão no banco de dados, depois limpar a coleção temporária e definir a propriedade ExistIndatabase no PersistencEContext para true.
3. Após chamar Flush (), o método EVET () é chamado. Sua função é limpar o objeto do usuário da sessão, ou seja, limpar a propriedade EntityEntries do PersistEncEContext.
4. Depois de chamar o método de despet (), o método Commit () chamará implicitamente o método Flush () primeiro. A função do Flush é limpar o cache, ou seja, inserir o objeto na coleta temporária da sessão de inserções no banco de dados, mas chamamos o método Flush () antes (Nota: Depois de chamar esse método, a coleção temporária será limpa); portanto, a coleção temporária não possui objetos, portanto a declaração de inserção não será emitida. Ele não atualizará o status existIndatabase no PersistenceContext. Enviar com sucesso.
Vamos considerar o uso do método de despet () na estratégia de geração de chaves primárias nativa:
/ ***Teste a estratégia de geração de chave primária nativa*/ public void testSave5 () {/*sessão definida e coisas*/ sessão session = null; Transação transação = nulo; tente { /*obter sessão e coisas* / session = hibernateUtils.getSession (); transação = session.begIntransaction (); /*Crie usuário*/ user1 user = new user1 (); user.setUname ("ma ying-jeou"); user.setBirthday (new Date ()); / *** Como a estratégia de geração de chaves primária do usuário1 é nativa, após a chamada session.Save (), a instrução Insert será executada,* retornará o ID gerado pelo banco de dados, incluído no gerenciamento da sessão, modificar o nível de indatabase de existência; o status do savinge não é submetido a ser submetido e limpar o conjunto temporário. /* Despeje o objeto do usuário da sessão, ou seja, expulso da propriedade EntityEntries do persistencEContext*/ session.evict (usuário); / *** Pode ser enviado com sucesso porque o Hibernate está na coleção de inserções de sessão ao limpar o cache* O objeto do usuário não pode ser encontrado; portanto, a instrução de inserção não será emitida, nem o status do existindatabase na sessão não será atualizado*/ transaction.Commit (); } catch (Exceção e) {e.printStackTrace (); transaction.rollback (); } finalmente {hibernateutils.closhessession (sessão); }} Através da depuração:
1. Como a estratégia de geração de chaves primária é nativa, depois de chamar o método SALVE, uma declaração de inserção será emitida imediatamente, retornando o ID gerado pelo banco de dados, incorporando o objeto no gerenciamento de sessões, modificando a propriedade de indicação de existência em persistencomertários para a coleta, que é a coleta correspondente no dados do dados e os objetos nos objetos do tempo que se tornarão o temporário. No entanto, devido ao nível de isolamento MySQL, não podemos ver os dados antes de cometê -los.
2. Após a chamada de salvamento, o objeto é chamado e o objeto é expulso da sessão, ou seja, ele é expulso das entityentries no PersistenceContext.
3. Depois de chamar o método de despet (), o método Commit () pode ser chamado com sucesso. O comprometimento pode ser salvo com sucesso, porque antes de ligar para o Commit (), o método Flush () será chamado implicitamente, ou seja, limpe o cache e procure objetos na coleção temporária para inserir no banco de dados. No entanto, você descobrirá que não há dados na coleção temporária, portanto a declaração de inserção não será emitida e a propriedade ExistenceIndatabase no PersistenceContext não será atualizada.
Nos casos acima, podemos ver que às vezes precisamos chamar o método Flush () para limpar o cache. Além disso, também encontramos um problema, ou seja, quando salvamos () os dados, não podemos ver os dados antes de enviá -los, ou seja, o nível de isolamento do banco de dados é limitado. Agora vamos falar sobre o nível de isolamento do MySQL:
1. Verifique o nível atual de isolamento do banco de dados MySQL:
selecione @@ tx_isolation;
Nota: A partir da figura, podemos ver que o nível de isolamento padrão do banco de dados MySQL é repetível, o que significa que não haverá leitura não repetível, ou seja, deve ser enviada antes de poder ser lida.
2. Modifique o nível atual de isolamento do MySQL (supondo que não seja enviado para ler, ou seja, pode ser lido sem compromisso):
set transaction isolation level read uncommited;
O exposto acima é toda a explicação detalhada do código de nível de Hibernate's session_flush e isolamento. Espero que seja útil para todos. Amigos interessados podem continuar se referindo a outros tópicos relacionados neste site. Se houver alguma falha, deixe uma mensagem para apontá -la. Obrigado amigos pelo seu apoio para este site!