Boa tarde Pessoal.
Eu tenho tido alguns problemas com o hibernate. Tenho percorrido os foruns para tentar sanar o problema, mas ainda não conseguir encontrar o que pode esta ocorrendo, e o que considero pior, eu não tenho idéia de onde o problema esta ocorrendo.
A questão é que não se trata de um problema propriamente dito, mas de um comportamento indesejado que prejudica o desempenho e que em certos momentos gera inconsistência.
O que ocorre na minha aplicação é que ao salvar um objeto, o hibernate deliberadamente realiza duas operações: o insert para o objeto (Transient) e depois o update sobre o mesmo objeto. O problema se agrava se eu, antes de ou criar um objeto novo ou editar um objeto, solicitar uma consulta no banco que retorne 10 registros por exemplo. Ao solicitar que o objeto seja salvo ou atualizado, o hibernate deliberadamente realiza a operação update ou insert sobre o objeto em questão, mas além disso ele atualiza(realiza o update) sobre todos os outros 10 objetos que foram solicitados na consulta.
Eu particularmente, considero esse comportamento indesejado, principalmente pelo fato de, como para essa aplicação específica, os clientes são “gordos” (aplicação de 2 níveis - Clientes “gordos” e um servidor de banco de dados, neste caso o PostgreSQL), se considerarmos que um cliente alterou um objeto e logo após um outro cliente alterou ou inseriu outro objeto, como o segundo cliente além de realizar a operação sobre o objeto que ele realmente precisa irá atualizar o restante dos objetos que ele consultou. Assim, pode acontecer que os dados que foram alterados pelo primeiro cliente não seja mantido, pois o segundo cliente atualizou os dados para aquele determinado registro, com informações desatualizadas.
Alguém já passou por isso? Tem alguma configuração para evitar esse comportamento? Qual a melhor estratégia para se trabalhar com sistemas desktop?
Grato pela atenção.
Informações adicionais:
Classe responsável pela criação das seções com o banco:
public class Persistente
{
private Session session = null;
private Transaction transaction = null;
private static Persistente objBanco = null;
private SessionFactory sessionFactory;
private Persistente() throws Exception
{
Configuration config = new Configuration();
/* Propriedades */
config.setProperty("hibernate.connection.driver_class", "org.postgresql.Driver");
config.setProperty("hibernate.connection.url", Properties.URL());
config.setProperty("hibernate.connection.username", "postgres");
config.setProperty("hibernate.connection.password", "");
config.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
config.setProperty("hibernate.show_sql", "true");
config.setProperty("hibernate.format_sql", "true");
/* Mapeamentos */
for(String mapeamento : Properties.MAPEAMENTO())
{
config.addResource(mapeamento);
}
sessionFactory = config.buildSessionFactory();
session = sessionFactory.openSession();
}
public static Persistente getInstance() throws Exception
{
if (objBanco == null)
{
objBanco = new Persistente();
}
return objBanco;
}
/**
* Método responsável por salvar objetos individuais no banco
*
* @param obj Objeto que será salvo no banco
*/
public void save(IObjetoSistema objeto) throws Exception
{
try
{
Session session = getSession();
transaction = session.beginTransaction();
session.saveOrUpdate(objeto);
transaction.commit();
}
catch(Exception he)
{
if (transaction != null)
{
transaction.rollback();
}
throw new Exception(Menssagens.errSalvar, he);
}
}
...
/**
* Método responsável por recuperar um objeto do banco
*
* @param obj Objeto que será recuperado
* @param id identificador do objeto
* @return Objeto com os dados pertencentes ao objeto
*/
public IObjetoSistema getObject(IObjetoSistema objeto, int identificador) throws Exception
{
try
{
Session session = getSession();
objeto = (IObjetoSistema)session.get(objeto.getClass(), new Integer(identificador));
}
catch(Exception he)
{
throw new Exception("Não foi possível obter objeto!", he);
}
return objeto;
}
/**
* Método responsável por recuperar uma coleção de objetos do banco.
*
* @param classe : Class - Classe da coleção de objetos.
* @param sql : String - critério de busca.
* @return lista : List<IObjetoSistema> - Lista com os objetos.
*/
public List<IObjetoSistema> getCollection(Class<?> classe, String sql) throws Exception
{
List<IObjetoSistema> lista = new ArrayList<IObjetoSistema>();
try
{
Session session = getSession();
Criteria criterio = session.createCriteria(classe);
criterio.add(Restrictions.sqlRestriction(sql));
lista = criterio.list();
}
catch(Exception e)
{
throw new Exception(Menssagens.naoFoiPossivelObterLista, e);
}
return lista;
}
...
private Session getSession()
{
if(!session.isOpen())
{
session = sessionFactory.openSession();
}
return session;
}
}
Objeto exemplo:
...
public class Fabricante extends ObjetoSistema
{
private static final long serialVersionUID = -2863134928338261287L;
private int codigo;
private String nome;
public int getCodigo()
{
return codigo;
}
public void setCodigo(int codigo)
{
this.codigo = codigo;
}
public String getNome()
{
return nome;
}
public void setNome(String nome)
{
this.nome = nome;
}
}
Mapeamento para a classe acima:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="business.cadastrosBasicos">
<class name="business.cadastrosBasicos.Fabricante">
<id name="codigo">
<generator class="sequence">
<param name="sequence">sequencia_fabricante</param>
</generator>
</id>
<property generated="never" lazy="false" length="100" name="nome"
not-null="true" type="string" unique="true"/>
<property column="codigo_usuario" generated="never" lazy="false"
name="codigoUsuario" not-null="true" type="integer"/>
<property column="data_cadastro" name="dataCadastro" type="timestamp"/>
</class>
</hibernate-mapping>
Se precisarem de mais alguma coisa, pode pedir:
Agradeço a atenção de todos.