【问题标题】:JPA/Hibernate doing update in table without any commandJPA/Hibernate 在没有任何命令的情况下在表中进行更新
【发布时间】:2013-11-26 14:16:21
【问题描述】:

好吧,我使用 JSF + Hibernate/JPA,我有以下代码:

  public void loadAddressByZipCode(ActionEvent event){
    Address address = boDefault.findByNamedQuery(Address.FindByZipCode, 'zipCode', bean.getAddress().getZipCode());

    if (address == null){
      //This zip code not exists in db
   }else{
      bean.setAddress(address);
   }
  }

上述方法在XHTML页面的inputText组件中的每个“onBlur”中调用,这个inputText的属性值是这样的:“#{addressMB.bean.address.zipCode}”

因此,当用户(在 XHTML 页面中)键入新的邮政编码时,此值设置在“bean.getAddress().setZipCode()”中,我在数据库中搜索此值。但是调试我的应用程序时,我发现当我执行“bean.getAddress().getZipCode()”时,Hibernate 在我的数据库中启动了一个“更新地址集...”。我该如何防止这种情况以及为什么会发生这种情况?

编辑 1: 这是我真正实现的方法

public void carregarLogradouroByCep(AjaxBehaviorEvent event) {
        List listReturn = getBoPadrao().findByNamedQuery(
                Logradouro.FIND_BY_CEP,
                new NamedParams("cep", bean.getLogradouro().getCep()));

        if (listReturn.size() > 0) {
            Logradouro logradouro = (Logradouro) listReturn.get(0);
            bean.setLogradouro(logradouro);
        }else{
            bean.setLogradouro(new Logradouro());
        }
    }

这是我的带有 onblur 事件的组件:

<p:inputText value="#{enderecoMB.bean.logradouro.cep}" id="cep"
                        required="true" requiredMessage="O CEP é obrigatório">
                        <p:ajax event="blur"
                            listener="#{enderecoMB.carregarLogradouroByCep}"
                            update=":formManterEndereco:logradouro, :formManterEndereco:cidade, :formManterEndereco:estado, 
                        :formManterEndereco:bairro" />
                    </p:inputText>

我有一个“BasicDAOImpl”,可以在数据库中进行所有操作,所以尝试在我的 entityManager 中进行:

@PostConstruct
    private void init(){        
        entityManager.setFlushMode(FlushModeType.COMMIT);
    }

但是“自动更新”还在继续。

编辑 2:我的 FIND_BY_CEP 查询

"SELECT c FROM Endereco c JOIN FETCH c.tipoEndereco JOIN FETCH c.logradouro"

编辑 3:我的实体

Endereco.java

@Entity
@NamedQueries(value = { @NamedQuery(name = "Endereco.findAllCompleto", query = "SELECT c FROM Endereco c "
        + "JOIN FETCH c.tipoEndereco " + "JOIN FETCH c.logradouro") })
@Table(name = "endereco")
public class Endereco extends AbstractBean {



    /**
     * 
     */
    private static final long serialVersionUID = 5239354646908722819L;

    public Endereco(){
        logradouro = new Logradouro();
    }

    @Transient
    public static final String FIND_ALL_COMPLETO = "Endereco.findAllCompleto";

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "id_tipo_endereco")
    private TipoEndereco tipoEndereco;

    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST,CascadeType.MERGE})
    @JoinColumn(name = "id_logradouro")
    private Logradouro logradouro;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "id_pessoa")
    private Pessoa pessoa;

    @Column
    private String numero;

    @Column
    private String complemento;

    public Logradouro getLogradouro() {
        return logradouro;
    }

    public void setLogradouro(Logradouro logradouro) {
        this.logradouro = logradouro;
    }

    public TipoEndereco getTipoEndereco() {
        return tipoEndereco;
    }

    public void setTipoEndereco(TipoEndereco tipoEndereco) {
        this.tipoEndereco = tipoEndereco;
    }

    public String getNumero() {
        return numero;
    }

    public void setNumero(String numero) {
        this.numero = numero;
    }

    public String getComplemento() {
        return complemento;
    }

    public void setComplemento(String complemento) {
        this.complemento = complemento;
    }

    public Pessoa getPessoa() {
        return pessoa;
    }

    public void setPessoa(Pessoa pessoa) {
        this.pessoa = pessoa;
    }



}

Logradouro.java

@Entity
@NamedQueries(value = { @NamedQuery(name = "Logradouro.findByCep", query = "SELECT c FROM Logradouro c "
        + "JOIN FETCH c.bairro "
        + "JOIN FETCH c.cidade "
        + "WHERE c.cep = :cep "
        + "ORDER BY c.logradouro") })
@Table(name = "logradouro")
public class Logradouro extends AbstractBean {

    public Logradouro(){
        this.cidade = new Cidade();
        this.bairro = new Bairro();
    }

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    @Transient
    public static final String FIND_BY_CEP = "Logradouro.findByCep";

    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST,CascadeType.MERGE})
    @JoinColumn(name = "id_cidade")
    private Cidade cidade;

    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST,CascadeType.MERGE})
    @JoinColumn(name = "id_bairro")
    private Bairro bairro;

    @Column
    private String cep;

    @Column
    private String logradouro;

    public Cidade getCidade() {
        return cidade;
    }

    public void setCidade(Cidade cidade) {
        this.cidade = cidade;
    }

    public Bairro getBairro() {
        return bairro;
    }

    public void setBairro(Bairro bairro) {
        this.bairro = bairro;
    }

    public String getCep() {
        return cep;
    }

    public void setCep(String cep) {
        this.cep = cep;
    }

    public String getLogradouro() {
        return logradouro;
    }

    public void setLogradouro(String logradouro) {
        this.logradouro = logradouro;
    }
}

【问题讨论】:

  • @Makky,我发布了所有必要的代码
  • 向我们展示命名查询“FIND_BY_CEP”
  • 还要检查你的表中可能有触发器。
  • 我没有任何触发器。
  • 没有。当我制作“ bean.getLogradouro().getCep()”时,会触发更新的数据库

标签: java hibernate jsf jpa


【解决方案1】:

默认情况下,Hibernate 使用实体管理器自动处理您的实体。您的 bean 就是一个这样的实体,所以当 entitymanager 觉得是时候刷新到数据库时,它就会这样做。如果你想手动刷新,你会想看看这样的结构:

entityManager.setFlushMode(javax.persistence.FlushModeType.MANUAL);

【讨论】:

  • 我认为这不是一个好主意,让休眠模式自动执行“提交”,至少对于我的业务规则而言。我会试试这个“FlushModeType.COMMIT”并返回这里。
  • 我试过了(用更多信息编辑了我的帖子)但更新继续发生,但现在更新发生在“SELECT statement”之后。
【解决方案2】:

我认为你滥用了 Hibernate。 ORM 的主要思想是允许您编写代码,而忽略这个事实,即某些东西进入数据库。您的域模型必须在没有任何数据库的情况下完全可测试。 ORM 不是使用关系数据库进行管理的抽象,它是您的对象模型的抽象。如果您需要明确地执行inserts 和updates,您最好使用一些活动记录实现或查看像MyBatis 这样的轻量级映射器。

为什么要阻止数据库更新?属性变了是吧?因此,让 Hibernate 决定是否以及何时必须将其新值写入数据库。

【讨论】:

  • 问题是:在 JSF 中,我用一个名为“Logradouro”的 bean 映射了我的所有组件,该 bean 由邮政编码找到。当用户输入另一个邮政编码时,这个对象 LOGRADOURO 必须被替换并且不要更新。
  • 当我在 Query 对象中创建“getResultList()”时,就会发生更新。
  • 我怀疑将域实体直接绑定到表单是否是一种好习惯。每次用户按下“提交”或“保存”按钮时,最好映射到 DTO 并将数据从 DTO 复制到实体。也许以这种方式改变你的方法可以解决问题。
猜你喜欢
  • 2011-12-07
  • 2022-07-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-22
  • 1970-01-01
  • 2013-01-31
  • 2012-07-15
  • 2021-12-05
相关资源
最近更新 更多