Hibernate 抛出 SQLException “id 字段没有默认值”

Posted

技术标签:

【中文标题】Hibernate 抛出 SQLException “id 字段没有默认值”【英文标题】:Hibernate throws SQLException "id field does not have a default value" 【发布时间】:2015-04-28 19:24:21 【问题描述】:

在使用休眠的 spring mvc 应用程序中,当我尝试持久化实体时遇到以下错误:

java.sql.SQLException: Field 'thirdIds_huid' doesn't have a default value

数据库模式由 hbm2ddl 生成。如何更改休眠代码以使这些实体能够成功持久化?

这两个实体是AClassHClassAClass 的代码是::

import javax.persistence.*;

@Entity(name = "AClass")
@Table(name = "a_class")
public class AClass 

    private Long auid;  
    private HClass firstId;
    private List<HClass> secondIds;
    private List<HClass> thirdIds;

    @Id
    @Column(name = "auid")
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getAuid()return auid;
    public void setAuid(Long hid)auid = hid;

    @ManyToOne
    public HClass getFirstId()return firstId;
    public void setFirstId(HClass tid)firstId = tid;

    @OneToMany
    public List<HClass> getSecondIds()return secondIds;
    public void setSecondIds(List<HClass> tid)secondIds = tid;

    @OneToMany
    public List<HClass> getThirdIds()return thirdIds;
    public void setThirdIds(List<HClass> i)thirdIds = i;


HClass的代码是:

import javax.persistence.*;

@Entity(name = "HClass")
@Table(name = "h_class")
public class HClass 

    private Long huid;
    private String somefield;

    @Id
    @Column(name = "huid")
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getHuid()return huid;
    public void setHuid(Long hid)huid = hid;

    @Column(name = "somefield")
    public String getSomefield()return somefield;
    public void setSomefield(String rt)somefield = rt;


触发错误的控制器代码是:

@RequestMapping(value = "/TriggerTheError", method = RequestMethod.GET)
public String processFindForm( HttpServletRequest request, Map<String, Object> model)      
    AClass ac = new AClass();
    HClass hc = new HClass();
    hc.setSomefield("some value goes here");
    List<HClass> hcs = new ArrayList<HClass>();
    hcs.add(hc);
    ac.setSecondIds(hcs);

    HClass hc2 = new HClass();
    hc2.setSomefield("another value goes here");
    List<HClass> hcs2 = new ArrayList<HClass>();
    hcs2.add(hc2);
    ac.setThirdIds(hcs2);

    persistAClass(ac);
    return "ReproduceError";


public void persistAClass(AClass ac)

    if(ac.getThirdIds()!=null)
        if(ac.getThirdIds().size()==0)ac.setThirdIds(null);System.out.println("thirdids re-set to null.");
        if(ac.getThirdIds()!=null)
            System.out.println("thirdids!=null: size is: "+ac.getThirdIds().size());
            for(int dd = 0;dd<ac.getThirdIds().size();dd++)
                this.serviceLayer.saveHClass(ac.getThirdIds().get(dd));
            
        
    
    if(ac.getSecondIds()!=null)
        if(ac.getSecondIds().size()==0)ac.setSecondIds(null);System.out.println("secondids re-set to null.");
        if(ac.getSecondIds()!=null)
            System.out.println("secondsid!=null: size is:"+ac.getSecondIds().size());
            for(int kk = 0;kk < ac.getSecondIds().size();kk++)
                this.serviceLayer.saveHClass(ac.getSecondIds().get(kk));
            
        
    
    if(ac.getFirstId()!=null)
        System.out.println("firstid!=null: huid value is: "+ac.getFirstId().getHuid());
        this.serviceLayer.saveHClass(ac.getFirstId());
    

System.out.println("-------------------- data follows ------------------------------");
    for(int a=0;a<ac.getSecondIds().size();a++)
        System.out.println("a, secondids somefield are: "+a+", "+ac.getSecondIds().get(a).getSomefield());
    
    if(ac.getFirstId()!=null)
        String rt = "";
        if(ac.getFirstId().getSomefield()!=null)rt = ac.getFirstId().getSomefield();
        System.out.println("first id some field is: "+rt);
    
    if(ac.getThirdIds()!=null)
        for(int b = 0;b<ac.getThirdIds().size();b++)
            String sf = "";
            if(ac.getThirdIds().get(b).getSomefield()!=null)sf = ac.getThirdIds().get(b).getSomefield();
            System.out.println("b, third ids somefield are: "+b+", "+sf);
        
    
System.out.println("-------------------- end of data -------------------------------");
    this.serviceLayer.saveAClass(ac);

注意上面控制器中触发错误的代码行是:

this.serviceLayer.saveAClass(ac);

服务层最终调用的repository代码为:

@Override
public void saveAClass(AClass myac) throws DataAccessException
    if (myac.getAuid() == null) this.em.persist(myac);
    else this.em.merge(myac);
 

完整的堆栈跟踪是:

11:51:04.334 [http-nio-8080-exec-3] DEBUG o.s.web.servlet.DispatcherServlet - Handler execution resulted in exception - forwarding to resolved error view: ModelAndView: reference to view with name 'exception'; model is exception=org.springframework.orm.hibernate3.HibernateJdbcException: JDBC exception on Hibernate data access: SQLException for SQL [n/a]; SQL state [HY000]; error code [1364]; could not execute statement; nested exception is org.hibernate.exception.GenericJDBCException: could not execute statement
org.springframework.orm.hibernate3.HibernateJdbcException: JDBC exception on Hibernate data access: SQLException for SQL [n/a]; SQL state [HY000]; error code [1364]; could not execute statement; nested exception is org.hibernate.exception.GenericJDBCException: could not execute statement
    at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:651) ~[spring-orm-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:106) ~[spring-orm-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517) ~[spring-orm-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:755) ~[spring-tx-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:724) ~[spring-tx-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:475) ~[spring-tx-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:270) ~[spring-tx-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94) ~[spring-tx-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) ~[spring-aop-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) ~[spring-aop-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at com.sun.proxy.$Proxy27.saveAClass(Unknown Source) ~[na:na]
    at example.controller.SomeModelClassController.persistAClass(SomeModelClassController.java:96) ~[SomeModelClassController.class:na]
    at example.controller.SomeModelClassController.processFindForm(SomeModelClassController.java:50) ~[SomeModelClassController.class:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_79]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_79]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_79]
    at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_79]
    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219) ~[spring-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132) ~[spring-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) ~[spring-webmvc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745) ~[spring-webmvc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686) ~[spring-webmvc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80) ~[spring-webmvc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925) [spring-webmvc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856) [spring-webmvc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936) [spring-webmvc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827) [spring-webmvc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:618) [servlet-api.jar:na]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812) [spring-webmvc-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:725) [servlet-api.jar:na]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291) [catalina.jar:8.0.15]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.15]
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) [spring-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.15]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.15]
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) [tomcat-websocket.jar:8.0.15]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.15]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.15]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88) [spring-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239) [catalina.jar:8.0.15]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) [catalina.jar:8.0.15]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219) [catalina.jar:8.0.15]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106) [catalina.jar:8.0.15]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) [catalina.jar:8.0.15]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142) [catalina.jar:8.0.15]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) [catalina.jar:8.0.15]
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610) [catalina.jar:8.0.15]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) [catalina.jar:8.0.15]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537) [catalina.jar:8.0.15]
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1085) [tomcat-coyote.jar:8.0.15]
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658) [tomcat-coyote.jar:8.0.15]
    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222) [tomcat-coyote.jar:8.0.15]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556) [tomcat-coyote.jar:8.0.15]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513) [tomcat-coyote.jar:8.0.15]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_79]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_79]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-util.jar:8.0.15]
    at java.lang.Thread.run(Thread.java:745) [na:1.7.0_79]
Caused by: org.hibernate.exception.GenericJDBCException: could not execute statement
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:54) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:136) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:58) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1256) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.action.internal.CollectionRecreateAction.execute(CollectionRecreateAction.java:58) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:364) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:356) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:281) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:328) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1234) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:404) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:75) ~[hibernate-entitymanager-4.2.1.Final.jar:4.2.1.Final]
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:513) ~[spring-orm-3.2.5.RELEASE.jar:3.2.5.RELEASE]
    ... 57 common frames omitted
Caused by: java.sql.SQLException: Field 'thirdIds_huid' doesn't have a default value
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1078) ~[mysql-connector-java-5.1.27.jar:na]
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4237) ~[mysql-connector-java-5.1.27.jar:na]
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4169) ~[mysql-connector-java-5.1.27.jar:na]
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2617) ~[mysql-connector-java-5.1.27.jar:na]
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2778) ~[mysql-connector-java-5.1.27.jar:na]
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2825) ~[mysql-connector-java-5.1.27.jar:na]
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2156) ~[mysql-connector-java-5.1.27.jar:na]
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2459) ~[mysql-connector-java-5.1.27.jar:na]
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2376) ~[mysql-connector-java-5.1.27.jar:na]
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2360) ~[mysql-connector-java-5.1.27.jar:na]
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:133) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]
    ... 71 common frames omitted
11:51:04.336 [http-nio-8080-exec-3] DEBUG o.s.w.s.v.ContentNegotiatingViewResolver - Requested media types are [text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8] based on Accept header types and producible media types [*/*])
11:51:04.336 [http-nio-8080-exec-3] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Invoking afterPropertiesSet() on bean with name 'exception'
11:51:04.337 [http-nio-8080-exec-3] DEBUG o.s.w.s.v.ContentNegotiatingViewResolver - Returning [org.springframework.web.servlet.view.JstlView: name 'exception'; URL [/WEB-INF/jsp/exception.jsp]] based on requested media type 'text/html'
11:51:04.337 [http-nio-8080-exec-3] DEBUG o.s.web.servlet.DispatcherServlet - Rendering view [org.springframework.web.servlet.view.JstlView: name 'exception'; URL [/WEB-INF/jsp/exception.jsp]] in DispatcherServlet with name 'MinimalDbaseExample'
11:51:04.337 [http-nio-8080-exec-3] DEBUG o.s.web.servlet.view.JstlView - Added model object 'exception' of type [org.springframework.orm.hibernate3.HibernateJdbcException] to request in view with name 'exception'
11:51:04.337 [http-nio-8080-exec-3] DEBUG o.s.web.servlet.view.JstlView - Forwarding to resource [/WEB-INF/jsp/exception.jsp] in InternalResourceView 'exception'
11:51:04.380 [http-nio-8080-exec-3] DEBUG o.s.web.servlet.DispatcherServlet - Successfully completed request

回答


解决方案来自@VladMihalcea 的回答部分,该部分涉及删除AClass 属性列表中对HClass 的多个引用。具体来说,我创建了类型HClassFirstHClassSecondHClassThird,它们都具有相同的属性和方法。这样,hibernate 就不会被AClass 链接到同一类型的多个属性所迷惑。该应用程序的架构允许这样做。我决定不使用继承,因为每个表中已经有很多链接,而且我不想遇到与外键数量过多有关的其他错误。

因此,解决方案不在休眠注释中。相反,解决方案是调整要求 hibernate 持续存在的模型。

【问题讨论】:

【参考方案1】:

我认为在这个例子中是much simpler to use cascading:

@Entity(name = "AClass")
@Table(name = "a_class")
public class AClass 

    private Long auid;  
    private HClass firstId;
    private List<HClass> secondIds = new ArrayList<>();
    private List<HClass> thirdIds = new ArrayList<>();

    @Id
    @Column(name = "auid")
    @GeneratedValue(strategy = GenerationType.AUTO)
    public Long getAuid()return auid;
    public void setAuid(Long hid)auid = hid;

    @ManyToOne
    public HClass getFirstId()return firstId;
    public void setFirstId(HClass tid)firstId = tid;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    public List<HClass> getSecondIds()return secondIds;
    public void setSecondIds(List<HClass> tid)secondIds = tid;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    public List<HClass> getThirdIds()return thirdIds;
    public void setThirdIds(List<HClass> i)thirdIds = i;


那么持久化逻辑就变成这样了:

public void persistAClass(AClass ac)    
    this.serviceLayer.saveAClass(ac);

原来的问题可能是因为这个:

at org.hibernate.action.internal.CollectionRecreateAction.execute(CollectionRecreateAction.java:58) ~[hibernate-core-4.2.1.Final.jar:4.2.1.Final]

这是您应该如何初始化实体中的集合:

private List<HClass> secondIds = new ArrayList<>();
private List<HClass> thirdIds = new ArrayList<>();

因此,当您要修改集合时,不要重置它们,而是依靠 dirty checking mechanism 来添加/删除元素:

AClass ac = new AClass();
HClass hc = new HClass();
hc.setSomefield("some value goes here");

ac.getSecondIds().add(hc);

HClass hc2 = new HClass();
hc2.setSomefield("another value goes here");
ac.getThirdIds().add(hc2);

persistAClass(ac);

在合并期间,您应该删除不再属于父级的子级,并添加来自您的网络请求的新子级。

编辑

我在本地计算机上尝试了您的示例,并且问题在于您进行映射的方式。因为您在 3 个不同的关系(一个多对一和 2 个一对多)上将 Aclass 与 HClass 链接起来,所以您会得到:

create table a_class (auid bigint generated by default as identity (start with 1), firstId_huid bigint, primary key (auid))
create table a_class_h_class (a_class_auid bigint not null, thirdIds_huid bigint not null, secondIds_huid bigint not null)
create table h_class (huid bigint generated by default as identity (start with 1), somefield varchar(255), primary key (huid))
alter table a_class_h_class add constraint UK_qtt8gi008ssnfi4t3mo3tq310  unique (thirdIds_huid)
alter table a_class_h_class add constraint UK_35k583bmbiomo0rc6t74ba41g  unique (secondIds_huid)
alter table a_class add constraint FK_1hw1d6sy2yhp9hirqgb6rx6yr foreign key (firstId_huid) references h_class
alter table a_class_h_class add constraint FK_qtt8gi008ssnfi4t3mo3tq310 foreign key (thirdIds_huid) references h_class
alter table a_class_h_class add constraint FK_jng9ogc4rmlmojd31weygk6l9 foreign key (a_class_auid) references a_class
alter table a_class_h_class add constraint FK_35k583bmbiomo0rc6t74ba41g foreign key (secondIds_huid) references h_class

所以当你尝试输入实体时:

Query:[insert into a_class (auid, firstId_huid) values (default, ?)][-5] 
Query:[insert into h_class (huid, somefield) values (default, ?)][some value goes here] 
Query:[insert into h_class (huid, somefield) values (default, ?)][another value goes here] 
Query:[insert into a_class_h_class (a_class_auid, secondIds_huid) values (?, ?)][1,1] 
WARN  [Alice]: o.h.e.j.s.SqlExceptionHelper - SQL Error: -10, SQLState: 23502
ERROR [Alice]: o.h.e.j.s.SqlExceptionHelper - integrity constraint violation: NOT NULL check constraint; SYS_CT_10096 table: A_CLASS_H_CLASS column: THIRDIDS_HUID

唯一的解决方法是更改​​映射。而不是 3 个 HClass 关联,您应该有其他东西,也许是继承模型或其他东西。始终尝试在有效架构上为您的域实体建模。

【讨论】:

我根本不使用 Eclipse,所以我会坚持你发布的代码。你得到的错误是因为你调用了:“this.serviceLayer.saveHClass(hc2);”,它持久化了子实体,然后你调用了一个临时父级的持久化,它将持久化到已经管理的实体。这就是为什么我建议只依赖级联。 这很奇怪,因为根据代码,所有实体都是瞬态的。 尝试我的建议并发布错误。我检查了你的代码库,你可以添加一个单元测试来轻松复制它。 我在这个问题上加了 2 美分。不幸的是,我没有太多时间来调查它,因为我有一份工作,一个孩子,一个在路上,我正在写一本 Hibernate 书,所以我只会坚持专注于 Hibernate 问题。这种问题并不真正适合 SO 模型,因为它可以很容易地被主持人关闭,因为它适合“为什么这段代码不起作用?”而偏离主题。类别。小心并继续编码! 您的 EDIT 提供了解决问题的关键。请参阅我添加到 OP 末尾的 ANSWER。无需对注释进行任何更改。注释更改后问题仍然存在。问题在于要求休眠模式持续存在的模型。当我按照您的 EDIT 更改模型时,hibernate 突然知道如何完成它的工作。我最终没有使用更改后的注释,因为它们与问题无关。【参考方案2】:

“持久分离实体错误”是因为每个持久操作都会打开新事务。对于新打开的事务,最后一个事务中持久化的实体(HCClass)变为“分离”。 我建议您将所有持久化操作分组到一个事务中,您可以通过将 persistAClass 移动到服务层并对其进行注释@Transactional 来实现。

【讨论】:

这不是问题。但感谢您和 +1 对此进行调查。

以上是关于Hibernate 抛出 SQLException “id 字段没有默认值”的主要内容,如果未能解决你的问题,请参考以下文章

hibernate java.sql.SQLException

(Hibernate, mysql) 原因:java.sql.SQLException: Field 'id' doesn't have a default value

运行集成测试时抛出 SqlException [重复]

BoneCP 抛出“SQLException:连接已关闭!”批量插入 MySQL 时

ManyToMany 属性的 SELECT 上的 JPQL Hibernate SQLException

MySQL 抛出“java.sql.SQLException:列计数与第 1 行的值计数不匹配”[重复]