我在操作一个含有外键的表时插入数据竟然抛出如下错误,望高手指教!不甚感激
org.springframework.dao.DataIntegrityViolationException: could not insert: [com.mwgj.wmw.spring.Wmwusertable]; nested exception is org.hibernate.exception.ConstraintViolationException: could not insert: [com.mwgj.wmw.spring.Wmwusertable]
Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [com.mwgj.wmw.spring.Wmwusertable]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:1986)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2405)
at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:37)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:248)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:269)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:167)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:101)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:530)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:518)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:514)
at org.springframework.orm.hibernate3.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:635)
at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:372)
at org.springframework.orm.hibernate3.HibernateTemplate.save(HibernateTemplate.java:632)
at com.mwgj.wmw.spring.WmwusertableDAO.save(WmwusertableDAO.java:51)
at com.mwgj.wmw.data.DBSource.SavaUser(DBSource.java:49)
at com.mwgj.wmw.struts.action.RegisterAction.execute(RegisterAction.java:79)
at org.apache.struts.chain.commands.servlet.ExecuteAction.execute(ExecuteAction.java:58)
at org.apache.struts.chain.commands.AbstractExecuteAction.execute(AbstractExecuteAction.java:67)
at org.apache.struts.chain.commands.ActionCommandBase.execute(ActionCommandBase.java:51)
at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:190)
at org.apache.commons.chain.generic.LookupCommand.execute(LookupCommand.java:304)
at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:190)
at org.apache.struts.chain.ComposableRequestProcessor.process(ComposableRequestProcessor.java:283)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)
at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:462)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.mwgj.wmw.filter.RequestFilter.doFilter(RequestFilter.java:109)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:263)
at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:852)
at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:584)
at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1508)
at java.lang.Thread.run(Unknown Source)
org.springframework.dao.DataIntegrityViolationException: could not insert: [com.mwgj.wmw.spring.Wmwusertable]; nested exception is org.hibernate.exception.ConstraintViolationException: could not insert: [com.mwgj.wmw.spring.Wmwusertable]
Caused by: org.hibernate.exception.ConstraintViolationException: could not insert: [com.mwgj.wmw.spring.Wmwusertable]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:1986)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2405)
at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:37)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:248)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:269)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:167)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:101)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:530)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:518)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:514)
at org.springframework.orm.hibernate3.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:635)
at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:372)
at org.springframework.orm.hibernate3.HibernateTemplate.save(HibernateTemplate.java:632)
at com.mwgj.wmw.spring.WmwusertableDAO.save(WmwusertableDAO.java:51)
at com.mwgj.wmw.data.DBSource.SavaUser(DBSource.java:49)
at com.mwgj.wmw.struts.action.RegisterAction.execute(RegisterAction.java:79)
at org.apache.struts.chain.commands.servlet.ExecuteAction.execute(ExecuteAction.java:58)
at org.apache.struts.chain.commands.AbstractExecuteAction.execute(AbstractExecuteAction.java:67)
at org.apache.struts.chain.commands.ActionCommandBase.execute(ActionCommandBase.java:51)
at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:190)
at org.apache.commons.chain.generic.LookupCommand.execute(LookupCommand.java:304)
at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:190)
at org.apache.struts.chain.ComposableRequestProcessor.process(ComposableRequestProcessor.java:283)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)
at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:462)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.mwgj.wmw.filter.RequestFilter.doFilter(RequestFilter.java:109)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:263)
at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:852)
at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:584)
at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1508)
at java.lang.Thread.run(Unknown Source)
解决方案 »
- ssh框架下的分页 实例
- java实现的FtpClient , 下载到本地后,文件名正确但文件大小为0
- javaweb传送对象是怎样实现的?
- 关于获取路径,request.getRealPath
- 高手来啊,救命。!!!
- 在jetty下使用jdk1.6出现Unable to compile class for JSP
- 请给我一个防止刷新的,用图片代替数字的JSP计数器的源代码好吗?50分求
- request获得的Cookie为什么只有四个呢?
- 求绘制直方图的代码,且方便将jsp脚本中查询得到的数据传递给他!
- 怎样学习Jsp能速成???帮忙指点,多谢!!!!
- struts2.1.3 rest plugin : rest 方式和 传统的配置文件方式 能否并存?
- 从SERVLET(response.sendRedirect)方法重定向到JSP页面出现乱码!!!!!
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:931)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2941)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1623)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1715)
at com.mysql.jdbc.Connection.execSQL(Connection.java:3249)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1268)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1541)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1455)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1440)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:1968)
... 46 more
2008-12-18 16:21:33 org.apache.catalina.core.StandardWrapperValve invoke
严重: Servlet.service() for servlet action threw exception
com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`wmw/wmwusertable`, CONSTRAINT `FK_wmw_upopedom_pcode` FOREIGN KEY (`wmw_upopedom`) REFERENCES `wmwpopedomtable` (`wmw_pcode`))
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:931)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2941)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1623)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1715)
at com.mysql.jdbc.Connection.execSQL(Connection.java:3249)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1268)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1541)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1455)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1440)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:1968)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2405)
at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:37)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:248)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:269)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:167)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:101)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:530)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:518)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:514)
at org.springframework.orm.hibernate3.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:635)
at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:372)
at org.springframework.orm.hibernate3.HibernateTemplate.save(HibernateTemplate.java:632)
at com.mwgj.wmw.spring.WmwusertableDAO.save(WmwusertableDAO.java:51)
at com.mwgj.wmw.data.DBSource.SavaUser(DBSource.java:49)
at com.mwgj.wmw.struts.action.RegisterAction.execute(RegisterAction.java:79)
at org.apache.struts.chain.commands.servlet.ExecuteAction.execute(ExecuteAction.java:58)
at org.apache.struts.chain.commands.AbstractExecuteAction.execute(AbstractExecuteAction.java:67)
at org.apache.struts.chain.commands.ActionCommandBase.execute(ActionCommandBase.java:51)
at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:190)
at org.apache.commons.chain.generic.LookupCommand.execute(LookupCommand.java:304)
at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:190)
at org.apache.struts.chain.ComposableRequestProcessor.process(ComposableRequestProcessor.java:283)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)
at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:462)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.mwgj.wmw.filter.RequestFilter.doFilter(RequestFilter.java:109)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:263)
at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:852)
at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:584)
at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1508)
at java.lang.Thread.run(Unknown Source)
外键约束问题,
也就是你定义了表的一个外键参照,但是你插入数据的时候
并没有你外键表里根本就没有你刚才插入的数据,
解决办法,现在外键表里插入数据,再把数据插入你实际要插入的表里
String popedom="普通用户";
String wmwUser=registerForm.getWmwUser();
String wmwPass=registerForm.getWmwPass();
String wmwNickName=registerForm.getWmwNickname();
String wmwMail=registerForm.getWmwMail();
String wmwWisdom=registerForm.getWmwWisdom();
String wmwHeadportraitImg=registerForm.getWmwHeadportraitImg();
DBSource dSource=new DBSource();
Wmwheadimgtable wmwheadimgtable=dSource.GetHeadImg(request, wmwHeadportraitImg);
Wmwpopedomtable wmwpopedomtable=dSource.GetPopedom(request, popedom);
String wmwCode=dSource.CreateUserCode(request);
Wmwusertable bean = new Wmwusertable();
bean.setWmwUuser(wmwUser);
bean.setWmwUpass(wmwPass);
bean.setWmwUinitpass(wmwPass);
bean.setWmwUnickname(wmwNickName);
bean.setWmwUmail(wmwMail);
bean.setWmwUwisdom(wmwWisdom);
bean.setWmwheadimgtable(wmwheadimgtable);
bean.setWmwpopedomtable(wmwpopedomtable);
bean.setWmwUcode(wmwCode);
dSource.SavaUser(request, bean);
DBSource类
public boolean SavaUser(HttpServletRequest request,Wmwusertable transientInstance) {
WmwusertableDAO dao = (WmwusertableDAO) ctx.getBean("WmwusertableDAO");
dao.save(transientInstance);
return true;
}
public Wmwheadimgtable GetHeadImg(HttpServletRequest request,String imgName) {
WmwheadimgtableDAO dao = (WmwheadimgtableDAO) ctx.getBean("WmwheadimgtableDAO");
List<Wmwheadimgtable> imgList=dao.findByWmwHname(imgName);
Wmwheadimgtable wmwHimg = new Wmwheadimgtable();
for (int i = 0; i < imgList.size(); i++) {
wmwHimg.setWmwHcode(imgList.get(i).getWmwHcode());
wmwHimg.setWmwHid(imgList.get(i).getWmwHid());
wmwHimg.setWmwHname(imgList.get(i).getWmwHname());
wmwHimg.setWmwHpath(imgList.get(i).getWmwHpath());
wmwHimg.setWmwHnewpath(imgList.get(i).getWmwHnewpath());
wmwHimg.setWmwusertables(imgList.get(i).getWmwusertables());
}
return wmwHimg;
}
public Wmwpopedomtable GetPopedom(HttpServletRequest request,String popedom) {
WmwpopedomtableDAO dao=(WmwpopedomtableDAO) ctx.getBean("WmwpopedomtableDAO");
List<Wmwpopedomtable> popedomList=dao.findByWmwPname(popedom);
Wmwpopedomtable wmwpopedomtable = new Wmwpopedomtable();
for (int i = 0; i < popedomList.size(); i++) {
wmwpopedomtable.setWmwPcode(popedomList.get(i).getWmwPcode());
wmwpopedomtable.setWmwPid(popedomList.get(i).getWmwPid());
wmwpopedomtable.setWmwPname(popedomList.get(i).getWmwPname());
wmwpopedomtable.setWmwPopedom(popedomList.get(i).getWmwPopedom());
wmwpopedomtable.setWmwPintegral(popedomList.get(i).getWmwPintegral());
wmwpopedomtable.setWmwusertables(popedomList.get(i).getWmwusertables());
}
return wmwpopedomtable;
}
就是保存外键关联表对应的实体bean的非空对象一同保存,
比如
你要插入的表a,表a外键关联表b,关联属性字段为 b_id
一般hibernate外键关联不是这样吗?b_id指的是表b对应的实体bean vo的对象,
所以你要保存表a的时候的把表b的非空属性赋值的表b对象,赋值给b_id。
一般就是通过查询关联表来获取表b bean对象set给表a,然后一块保存。
假如Wmwusertable 和B表通过ID外键对应的话...
你现在要插入Wmwusertable 数据.
先得在B中插入对应ID的记录..
我在表单中选择了Wmwheadimgtable对应的name 然后调用方法查询出Wmwheadimgtable对象
上面的方法也可以看出来
wmw_upopedom varchar(255) not null comment '权限',
constraint FK_wmw_upopedom_pcode foreign key (wmw_upopedom) references wmwPopedomTable(wmw_pcode), #建立权限关联
constraint FK_wmw_uheadportrait_hcode foreign key(wmw_uheadportrait) references wmwHeadImgTable(wmw_hcode) #建立头像关联长度是肯定不会超的,主外键也应该没有错
还有其它的解决方式没
<column name="wmw_uheadportrait">
<comment>头像</comment>
</column>
</many-to-one>
<many-to-one name="wmwpopedomtable" class="com.mwgj.wmw.spring.Wmwpopedomtable" fetch="select">
<column name="wmw_upopedom" not-null="true">
<comment>权限</comment>
</column>
</many-to-one> <set name="wmwusertables" inverse="true">
<key>
<column name="wmw_uheadportrait">
<comment>头像</comment>
</column>
</key>
<one-to-many class="com.mwgj.wmw.spring.Wmwusertable" />
</set> <set name="wmwusertables" inverse="true">
<key>
<column name="wmw_upopedom" not-null="true">
<comment>权限</comment>
</column>
</key>
<one-to-many class="com.mwgj.wmw.spring.Wmwusertable" />
</set>
hibernate+spring自动映射的,没做任何修改
同志 ,是获取的值不对,牛头不对马嘴!a,b通过id关联
a(id,name),b(id,desc,a_id)
你将获取的name的值赋给了id,将id的值赋给了name,(造成了两个表关联字段数据不一致)所以两张表就违反了外键约束!