【问题标题】:LazyInitializationException - ManyToOne contains Eager, cannot add to OneToManyLazyInitializationException - ManyToOne 包含 Eager,无法添加到 OneToMany
【发布时间】:2019-01-25 08:57:53
【问题描述】:

我会给你看同样的代码然后我会问一个问题。

AccountService.java

@Service
public class AccountService implements IAccountService, StandardizeService<Account>{

  @Autowired
  private AccountRepository accountRepository;

  @Autowired
  private AccessRoleRepository accessRoleRepository;

  @Autowired
  private ActivationCodeRepository activationCodeRepository;

  @Autowired
  private ActivationCodeService activationCodeService;

  @Override
  public Account addNew(Account account){

    if(!validateAccount(account))
      return null;

    if(!accountRepository.findByUsernameOrEmail(account.getUsername(), account.getEmail()).isEmpty())
      return null;

    account.setEnabled(false);
    account.setAccessRole(accessRoleRepository.getAccessRoleById(3));
    account.setCreationTime(new Timestamp(new Date().getTime()));
    account.setPassword(this.hashPassword(account.getPassword()));

    Account newAccount = accountRepository.save(account);
    if(newAccount == null)
      return null;

    ActivationCode activationCode = activationCodeService.addNew(newAccount, 1);
    if(activationCode == null)
      return null;

    newAccount.setActivationCodes(activationCodeRepository.getActivationCodeById(activationCode.getId()));

    return newAccount;
  }
//other methods

ActivationCodeRepository.java

public interface ActivationCodeRepository extends CrudRepository<ActivationCode, Long> {

  List<ActivationCode> getActivationCodeById(int id);
}

Account.java

@Entity
@Table(name = "accounts")
@NoArgsConstructor
@Data
@AllArgsConstructor
public class Account {

  @Id
  @Column(name = "id_account")
  @GeneratedValue(strategy = GenerationType.AUTO)
  @NotNull
  private int id;

  @Column(name = "username")
  @NotNull
  @Length(min = 6, max = 15)
  private String username;

  @Column(name = "email")
  @NotNull
  @Length(min = 6, max = 100)
  private String email;

  @Column(name = "password")
  @NotNull
  @Length(min = 8, max = 100)
  private String password;

  @Column(name = "register_no")
  @NotNull
  private Integer register_no;

  @ManyToOne(fetch = FetchType.EAGER, optional = false)
  @JoinColumn(name = "id_access_role")
  @OnDelete(action = OnDeleteAction.NO_ACTION)
  @NotNull
  private AccessRole accessRole;

  @Column(name = "enabled")
  @NotNull
  private boolean enabled;

  @Column(name = "firstname")
  @NotNull
  @Length(min = 2, max = 30)
  private String firstname;

  @Column(name = "lastname")
  @NotNull
  @Length(min = 2, max = 30)
  private String lastname;

  @Column(name = "creation_time", updatable = false)
  @NotNull
  private Timestamp creationTime;

  @OneToMany(mappedBy = "account")
  private List<ActivationCode> activationCodes;

  @OneToMany(mappedBy = "account")
  private List<GroupMember> groupMembers;

}

AccessRole.java

@Table(name = "access_roles")
@Entity
@NoArgsConstructor
@Data
@AllArgsConstructor
public class AccessRole {

  @Id
  @Column(name = "id_access_role")
  @GeneratedValue(strategy = GenerationType.AUTO)
  @NotNull
  private int id;

  @Column(name = "role")
  @NotNull
  private String role;

  @JsonIgnore
  @OneToMany(mappedBy = "accessRole")
  private List<Account> accounts;

  @JsonIgnore
  @OneToMany(mappedBy = "accessRole")
  private List<GroupMember> groupMembers;
}

ActivationCode.java

@Table(name = "activation_codes")
@Entity
@NoArgsConstructor
@Data
@AllArgsConstructor
public class ActivationCode {

  @Id
  @Column(name = "id_activation_code")
  @GeneratedValue(strategy = GenerationType.AUTO)
  @NotNull
  private int id;

  @ManyToOne(fetch = FetchType.EAGER, optional = false)
  @JoinColumn(name = "id_account")
  @OnDelete(action = OnDeleteAction.CASCADE)
  @NotNull
  private Account account;

  @Column(name = "type")
  @NotNull
  private int type;
  //1 - for activation account (enabled -> true)

  @Column(name = "code")
  @NotNull
  private String code;
}

我尝试过使用 AccountService 中的 addNew 方法。新帐户已添加,但我遇到了问题:

newAccount.setActivationCodes(activationCodeRepository.getActivationCodeById(activationCode.getId()));

控制台显示错误:

org.hibernate.LazyInitializationException: 延迟初始化失败 角色集合:com.goode.business.AccessRole.accounts,可以 不初始化代理 - 没有会话

这个错误并不完全将我引导到我在上面向你展示的那一行,但这一行没有执行。

错误是关于获取 Lazy (AccessRole.accounts)。我尝试将其更改为:

AccessRole.java

  @JsonIgnore
  @OneToMany(fetch = FetchType.EAGER, mappedBy = "accessRole")
  private List<Account> accounts;

但现在控制台显示循环错误:

org.springframework.web.util.NestedServletException:处理程序调度 失败的;嵌套异常是 java.lang.StackOverflowError

原因:

在 com.goode.business.AccessRole.toString(AccessRole.java:21) 在 java.base/java.lang.String.valueOf(String.java:2788) 在 java.base/java.lang.StringBuilder.append(StringBuilder.java:135) 在 com.goode.business.Account.toString(Account.java:26) 在 java.base/java.lang.String.valueOf(String.java:2788)

您能给我一些建议,我该如何修复它?

【问题讨论】:

  • 查看toStringAccessRoleAccount 方法——怀疑是那些导致StackOverflowError 的方法。
  • 是的,它是:com.goode.business.AccessRole.toString(AccessRole.java:21) at java.base/java.lang.String.valueOf(String.java:2788) at java.base/java.lang.StringBuilder.append(StringBuilder.java:135) 在 com.goode.business.Account.toString(Account.java:26) 在 java.base/java.lang.String.valueOf(String. java:2788)
  • 您需要从AccessRoletoString 中删除accounts 或从AccounttoString 中删除accessRole 之一。这将帮助您解决堆栈溢出问题。

标签: java hibernate spring-data-jpa


【解决方案1】:

@Data 注解告诉我你正在使用 Lombok 来生成 getter-setter 和 toString。我们应该从 toString 中排除复杂对象或任何集合的字段,因为 Lombok 生成的 toString 方法将调用当前对象的所有属性/字段的 toString 等等..

在要从 toString 中排除的属性上使用 @ToString.Exclude。在您的情况下,对 AccessRole.java 中的帐户和 groupMembers 使用 exclude。

有关详细信息,请参阅 https://projectlombok.org/features/ToString。

【讨论】:

  • 完美运行!谢谢
猜你喜欢
  • 2013-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-09
  • 1970-01-01
  • 2016-11-14
  • 1970-01-01
相关资源
最近更新 更多