本文介绍了@OneToMany JPA注释导致不必要的sql更新,不会级联的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将我的应用程序从基于xml的映射迁移到基于JPA注解的映射。但是这只会在一个简单的情况下失败。例如,我有以下3个实体:

  @Entitiy 
public class UserAccount {

@OneToMany(cascade = CascadeType.ALL,orphanRemoval = true)
@JoinColumn(name =user_account_id,nullable = false,
insertable = true,updatable = false)
@ NotNull
私人设置< Authority>当局;

@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name =USER_ID,nullable = false)

... get和setter


@Entity
公共类授权{

@Column
私有字符串权限;

... get和setter
}

@实体
公共类用户{
...一些属性
}

如果我创建一个新的UserAccount实例并尝试保存它,我得到一个异常,因为权限实例没有保存,这意味着它不像它应该做的那样级联。

  org.springframework.dao .InvalidDataAccessApiUsageException:
org.hibernate.TransientObjectException:对象引用一个未保存的瞬态
实例 - 在冲洗前保存瞬态实例:Authority ...

发生这种情况是因为hibernate尝试更新权限行(以前没有插入):

<$ p $ h




Hibernate:
插入user_accounts ...

Hibernate:
更新权限设置user_account_id =?其中id =?

我使用以下服务保存UserAccount实例。

  @Service 
public class UserAccountService {

@Resource
private UserAccountRepository userAccountRepository;

@Transactional(propagation = Propagation.REQUIRED,readOnly = false)
public void save(UserAccount userAccount){

userAccountRepository.save(userAccount);





奇怪的是,用户实例将被保存,所以OneToOne映射级联(如果我删除了UserAccount.authorities属性)。但是,这与基于xml的映射(并且没有JPA)一起工作。我最终调用了一个单独的方法来存储Authoriy实例。

  @Service 
public class UserAccountService {

@Resource
private UserAccountRepository userAccountRepository;
@Resource
private AuthorityRepository authorityRepository;

@Transactional(propagation = Propagation.REQUIRED,readOnly = false)
public void save(UserAccount userAccount){

userAccountRepository.save(userAccount);
authorityRepository.save(userAccount.getAuthoritiesSet());
}

}

这意味着,我手动级联。但是,查看执行的SQL语句,我可以看到,hibernate插入了权限实例,之后,它更新此行以设置UserAccount引用:



<$ p $ b $ Hibernate:
插入用户...

Hibernate:
插入user_accounts ...

Hibernate :
插入权限(权限)值(?)

Hibernate:
更新权限集user_account_id =?其中id =?

对于我来说这是一个性能问题,因为有很多权限,我不想拥有20次插入,之后20次更新。但我无法删除更新,并告诉hibernate将user_account_id与权限一起设置。



因为我还有许多其他有OneToMany关系的对象,所以我我对解决这个问题非常感兴趣,并感谢您的帮助和想法。

Hibernate:4.3.4.Final,
spring data jpa:1.5.1.RELEASE



祝好,
Daniel

解决方案

我与ManyToOne映射有类似的问题。
通过向版本字段添加默认值解决了问题。

  @Version 
@Column(name = VERSION)
private Integer version = 1;


I am migrating my app from xml based mapping to JPA annotation based mapping. But this fails only in a simple case. For example, I've the following 3 entities:

@Entitiy
public class UserAccount {

     @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
     @JoinColumn(name = "user_account_id", nullable = false, 
                 insertable = true, updatable = false)
     @NotNull
     private Set<Authority> authorities;

     @OneToOne(cascade = CascadeType.ALL)
     @JoinColumn(name="USER_ID", nullable = false)

     ... get and setter
}

@Entity
public class Authority {

    @Column
    private String authority;

    ... get and setter
}

@Entity
public class User {
    ... some properties
}

If I create a new UserAccount instance and try to save it, I got an exception, because the Authority instance wasn't saved, which means, it doesn't cascade as it supposed to do.

org.springframework.dao.InvalidDataAccessApiUsageException: 
org.hibernate.TransientObjectException: object references an unsaved transient 
instance - save the transient instance before flushing: Authority ...

This happens, because hibernate tries to update the authority row (which wasn't inserted before):

Hibernate: 
    insert into users ...

Hibernate: 
    insert into user_accounts ...

Hibernate: 
    update authorities set user_account_id=? where id=?

I used the following service to save the UserAccount instance.

@Service
public class UserAccountService {

    @Resource
    private UserAccountRepository userAccountRepository;

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
    public void save(UserAccount userAccount) {

       userAccountRepository.save(userAccount);
    }

}

The strange thing is, that the User instance will be saved, so the OneToOne mapping cascades (if I remove the UserAccount.authorities property). But this worked with the xml based mapping (and without JPA). I ended up in calling a separate method to store the Authoriy instances.

@Service
public class UserAccountService {

    @Resource
    private UserAccountRepository userAccountRepository;
    @Resource
    private AuthorityRepository authorityRepository;

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
    public void save(UserAccount userAccount) {

        userAccountRepository.save(userAccount);
        authorityRepository.save(userAccount.getAuthoritiesSet());
    }

} 

Which means, I cascade manually... However, looking into the executed SQL statements, I can see, that hibernate inserts the authority instance and after that, it updates this row to set the UserAccount reference:

Hibernate: 
    insert into users ...

Hibernate: 
    insert into user_accounts ...

Hibernate: 
    insert into authorities (authority) values (?)

Hibernate: 
    update authorities set user_account_id=? where id=?

And for me this is a performance issue, because there are many authorities and I do not want to have 20 inserts and after that 20 updates. But I was not able to "remove" the updates and tell hibernate to set the user_account_id together with the authority.

Because I've many other objects having OneToMany relations, I am very interested in resolving this problem and appreciate your help and thoughts.

Hibernate: 4.3.4.Final,spring data jpa: 1.5.1.RELEASE

Best regards,Daniel

解决方案

I had very similar issue with ManyToOne mapping.Solved problem by adding default value to version field.

@Version
@Column(name = "VERSION")
private Integer version = 1;

这篇关于@OneToMany JPA注释导致不必要的sql更新,不会级联的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-14 04:52