java - 尝试将对象添加到列表并将其保存在 Spring Boot 上的 MySQL 中时出现 UnsupportedOperationException

标签 java mysql spring spring-boot set

我正在使用 Java Spring Boot 创建 API。 我正在尝试在两个实体之间创建一个桥接表:客户端和用户。一个客户端可以有多个用户。我的用户实体如下所示:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.hibernate.annotations.NaturalId;
import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.util.HashSet;
import java.util.Set;

@Entity
@Table(name = "users", uniqueConstraints = {
        @UniqueConstraint(columnNames = {
                "username"
        }),
        @UniqueConstraint(columnNames = {
                "email"
        })
})
public class User{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @NotBlank
    @Size(max = 40)
    @Column(name = "name")
    private String name;

    @NotBlank
    @Size(max = 15)
    @Column(name = "username")
    private String username;

    @NaturalId
    @NotBlank
    @Size(max = 40)
    @Email
    @Column(name = "email")
    private String email;

    @NotBlank
    @Size(max = 100)
    @Column(name = "password")
    private String password;

    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "user_roles",
            joinColumns = @JoinColumn(name = "user_id"),
            inverseJoinColumns = @JoinColumn(name = "role_id"))
    private Set<Role> roles = new HashSet<>();

//    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})


    public User() {

    }

    public User(String name, String username, String email, String password) {
        this.name = name;
        this.username = username;
        this.email = email;
        this.password = password;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Set<Role> getRoles() {
        return roles;
    }

    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }

}

在我创建桥接表的客户端实体中,我正在执行下一步:

    @Entity
@Table(name = "cliente")
public class Cliente {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;
    @Column(name = "empresa")
    private String empresa;
    @Column(name = "telefono")
    private Integer telefono;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(unique = true)
    private Licencia licencia;

    @OneToMany(cascade = CascadeType.ALL ,fetch = FetchType.EAGER)
    @JoinTable(name = "user_cliente",
            joinColumns = @JoinColumn(name = "cliente_id"),
            inverseJoinColumns = @JoinColumn(name = "user_id"))
    private List<User> users = new ArrayList<>();

    public Cliente(String empresa, Integer telefono) {
        this.empresa = empresa;
        this.telefono = telefono;
    }

    public Cliente() {
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getEmpresa() {
        return empresa;
    }

    public void setEmpresa(String empresa) {
        this.empresa = empresa;
    }

    public Integer getTelefono() {
        return telefono;
    }

    public void setTelefono(Integer telefono) {
        this.telefono = telefono;
    }

    public Licencia getLicencia() {
        return licencia;
    }

    public void setLicencia(Licencia licencia) {
        this.licencia = licencia;
    }

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }
}

这会使用 id 作为外键在 MySQL 中创建我的bridge_table。 现在,当我想将用户分配给客户端时,我正在执行下一步

User user = new User(userModel.getName(), userModel.getUsername(), userModel.getEmail(), userModel.getPassword());
Cliente cliente = clienteRepository.findById(6);
List<User> users = cliente.getUsers();
users.add(user);
cliente.setUsers(users);
clienteRepository.save(cliente);

在使用 clienteRepository.save() 方法保存 Client 对象时,它会抛出下一个异常:

java.lang.UnsupportedOperationException: null
    at java.base/java.util.Collections$1.remove(Collections.java:4712) ~[na:na]
    at java.base/java.util.AbstractCollection.clear(AbstractCollection.java:447) ~[na:na]
    at org.hibernate.collection.internal.PersistentSet.clear(PersistentSet.java:318) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.type.CollectionType.replaceElements(CollectionType.java:545) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.type.CollectionType.replace(CollectionType.java:721) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.type.TypeHelper.replace(TypeHelper.java:166) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.event.internal.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:393) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.event.internal.DefaultMergeEventListener.entityIsPersistent(DefaultMergeEventListener.java:203) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:176) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:923) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:893) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.engine.spi.CascadingActions$6.cascade(CascadingActions.java:261) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:490) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:415) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:216) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:523) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:455) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:418) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:216) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:149) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.event.internal.DefaultMergeEventListener.cascadeOnMerge(DefaultMergeEventListener.java:460) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.event.internal.DefaultMergeEventListener.entityIsPersistent(DefaultMergeEventListener.java:202) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:176) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:69) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:901) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:887) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:567) ~[na:na]
    at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:350) ~[spring-orm-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at com.sun.proxy.$Proxy116.merge(Unknown Source) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:567) ~[na:na]
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:308) ~[spring-orm-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at com.sun.proxy.$Proxy116.merge(Unknown Source) ~[na:na]
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:510) ~[spring-data-jpa-2.1.9.RELEASE.jar:2.1.9.RELEASE]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:567) ~[na:na]
    at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359) ~[spring-data-commons-2.1.9.RELEASE.jar:2.1.9.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200) ~[spring-data-commons-2.1.9.RELEASE.jar:2.1.9.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644) ~[spring-data-commons-2.1.9.RELEASE.jar:2.1.9.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608) ~[spring-data-commons-2.1.9.RELEASE.jar:2.1.9.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595) ~[spring-data-commons-2.1.9.RELEASE.jar:2.1.9.RELEASE]
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595) ~[spring-data-commons-2.1.9.RELEASE.jar:2.1.9.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59) ~[spring-data-commons-2.1.9.RELEASE.jar:2.1.9.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:295) ~[spring-tx-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) ~[spring-tx-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:138) ~[spring-data-jpa-2.1.9.RELEASE.jar:2.1.9.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) ~[spring-data-commons-2.1.9.RELEASE.jar:2.1.9.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at com.sun.proxy.$Proxy153.save(Unknown Source) ~[na:na]
    at com.pruebas.spring_jdbc.Controllers.UserController.newUser(UserController.java:92) ~[classes/:na]
    at com.pruebas.spring_jdbc.Controllers.UserController$$FastClassBySpringCGLIB$$55750dd8.invoke(<generated>) ~[classes/:na]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:119) ~[spring-context-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.1.8.RELEASE.jar:5.1.8.RELEASE]

为什么会发生这种情况?我在实体上创建桥接表的方式是否有问题,或者与列表或将其保存在 MySQL 中的方式有​​关?

最佳答案

这是因为使用 fetch = FetchType.LAZY 导致列表未完全初始化。您正在尝试将元素附加到未获取列表上的代理并保存。

您可以通过设置急切获取来解决这个问题:fetch = FetchType.EAGER 或使用事务。更干净的解决方案是使用例如 jpql 来获取它:

select c from Client c left join fetch c.users where id = :id

关于java - 尝试将对象添加到列表并将其保存在 Spring Boot 上的 MySQL 中时出现 UnsupportedOperationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58346810/

相关文章:

java - 获取 Java 中的通用列表 <?> 对象的值

mysql - Spring Boot Rest 服务在正常工作数小时后引发 JPA 连接错误

mysql - 通过 GROUP BY 选择,您可以按投影的 SUM 进行排序吗?

java - jpa pagingandsortingrepository save 跳过自动生成的值 1

java - RabbitListener 注释上的动态队列

java - 无法从组件访问 processMouseMotionEvent

java - 如何在 jxpath 中实现昂贵的查询?

java - 如何在分页中显示有限的页面链接?

python - Pymysql库不返回数据库中的纯数据

java - 如何在 Reactive Spring WEBFlux(Spring 5) 中读取上传的 json 文件内容