繁体   English   中英

Spring Data JPA多对多保存

[英]Spring Data JPA many to many save

我正在使用Spring MVC + Hibernate + Spring Data JPA。

我与Person和SecurityRole之间有很多关系。 我想使用spring data jpa save方法添加一个新人。 当我尝试保存时,出现以下错误:

SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/hub] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: Could not execute JDBC batch update; SQL [insert into roles (RLE_ROLE, RLE_ID) values (?, ?)]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update] with root cause
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '1' for key 'PRIMARY'
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
    at com.mysql.jdbc.Util.getInstance(Util.java:386)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1039)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3597)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3529)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1990)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2151)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2625)
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2119)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2415)
    at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1976)
    at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1449)
    at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723)
    at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
    at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:114)
    at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:109)
    at org.hibernate.jdbc.AbstractBatcher.prepareBatchStatement(AbstractBatcher.java:244)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2411)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2874)
    at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
    at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:76)
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:521)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:291)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:122)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
    at com.sun.proxy.$Proxy59.save(Unknown Source)
    at com.motodoc.hub.service.SecurityUserServiceImpl.addNewUser(SecurityUserServiceImpl.java:64)
    at com.motodoc.hub.controller.UserController.save(UserController.java:150)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)

似乎save方法正在尝试添加新的SecurityRole,并且由于SecurityRole已存在且具有相同的主键,因此会出现错误。

因此,我的问题是,当给定一个已经存在于数据库中的SecurityRole时,我如何保存一个新人员,而只更新Person和映射表而忽略了SecurityRole?

您的帮助将不胜感激。

以下所有相关代码...

人实体类:

@Entity
@Table(name="persons")
public class Person implements UserDetails {

    @Id
    @Column(name="PRS_ID")
    private int id;

    @NotEmpty
    @Column(name="PRS_USERNAME")
    private String username;

    @NotEmpty
    @Column(name="PRS_PASSWORD")
    private String password;

    @NotEmpty
    @Column(name="PRS_FIRST_NAME")
    private String firstName;

    @Column(name="PRS_MIDDLE_NAME")
    private String middleName;

    @NotEmpty
    @Column(name="PRS_LAST_NAME")
    private String lastName;

    @OneToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
    @JoinTable(name = "USER_ROLES", joinColumns = { 
            @JoinColumn(name = "USR_PRS_ID") }, inverseJoinColumns = { 
            @JoinColumn(name = "RLE_ID") })
    private Set<SecurityRole> roles;

    @Transient
    private final String PERMISSION_PREFIX = "ROLE_PERM_";

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Set<GrantedAuthorityImpl> authorities = new HashSet<GrantedAuthorityImpl>();
        for (SecurityRole role : roles) {
            for (SecurityPermission permission : role.getPermissions()) {
                GrantedAuthorityImpl authority = new GrantedAuthorityImpl(PERMISSION_PREFIX + permission.getPermission());
                authorities.add(authority);
            }
        }
        return authorities;
    }

SecurityRole类:

@Entity
@Table(name="roles")
public class SecurityRole implements Serializable {

    @Id
    @Column(name="RLE_ID")
    private int id;

    @NotEmpty
    @Column(name="RLE_ROLE")
    private String role;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinTable(name = "ROLE_PERMISSIONS", joinColumns = { 
            @JoinColumn(name = "RLE_ID") }, inverseJoinColumns = { 
            @JoinColumn(name = "PRM_ID") })
    private Set<SecurityPermission> permissions;
}

服务等级

public class SecurityUserServiceImpl implements ISecurityUserService {

    @Autowired
    private IPersonDao personDao;

    @Autowired
    private IRoleDao roleDao;

    @Autowired
    private BCryptPasswordEncoder encoder;

    @Override
    public void addNewUser(AddUserForm addUserForm) {

        Person newPerson = addUserForm.getPerson();

        //encode password
        String encodedPassword = encoder.encode(newPerson.getPassword());

        //set the encoded password as the password
        newPerson.setPassword(encodedPassword);

        Set<SecurityRole> securityRoles = new HashSet<SecurityRole>();

        //get Role
        securityRoles.add(roleDao.findById(addUserForm.getRoleId()));

        newPerson.setRoles(securityRoles);

        //now save
        personDao.save(newPerson);
    }
}

IPersonDao界面:

public interface IPersonDao extends JpaRepository<Person, Long>, QueryDslPredicateExecutor<Person> {

    @SuppressWarnings("unchecked")
    public Person save(Person person);

}

IRoleDao界面:

public interface IRoleDao extends JpaRepository<SecurityRole, Long>, QueryDslPredicateExecutor<SecurityRole> {

    public List<SecurityRole> findAll();

    public SecurityRole findById(int id);

}

Persistence.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
    <persistence-unit name="hibernatePersistenceUnit" transaction-type="RESOURCE_LOCAL">
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="update" />
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
        </properties>
        <!-- <mapping-file>META-INF/orm.xml</mapping-file>  -->
    </persistence-unit>
</persistence>

就像OP在他的评论中指出的那样,他的问题是他使用@OneToMany而不是@ManyToMany。

当我遇到类似的异常时,我的问题是我不打算使用@ManyToMany注释来持久化该成员,但是我使用了cascade = CascadeType.ALL,这意味着它将尝试持久化它。 另外,我没有该字段ID的生成策略。 我从ManyToMany批注中删除了层叠属性,它解决了我的问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM