我们知道在处理hibernate的一对多的问题时,我们一般会在配置文件中写清它们的关系以及操作的规则。
比如,在做网页时,会有博主和文章表,是一对多的关系。我用hiberbnate来实现它们的级联关系,配置文件如下
博主Userinfo.hbm.xml代码如下:
<hibernate-mapping> <!-- 指定类到表的映射 --> <class name="test.pojo.Userinfo" table="userinfo"> <!--主键id的生成机制:native将自动根据数据库生成,mysql是自增长方式 --> <id name="id" column="id"> <generator class="native"></generator> </id> <!--设定Userinfo类每个属性到userinfo表中对应列名的映射 --> <property name="name" column="name" /> <property name="psw" column="psw"/> <property name="signature" column="signature"/> <property name="sex" column="sex"/> <property name="age" column="age"/> <property name="birthday" column="birthday"/> <property name="qq" column="qq"/> <property name="e_mail" column="e_mail"/> <property name="phone" column="phone"/> <property name="occupation" column="occupation"/> <property name="score" column="score"/> <property name="graduateSchool" column="graduateSchool"/> <property name="country" column="country"/> <property name="province" column="province"/> <property name="head_path" column="head_path"/> <!--save-update --> <!-- 映射Userinfo对象与Article对象的一对对多关系,以article方式映射 ,按id顺序排序,并延迟加载--> <bag name="articles" table="article" order-by="id asc" lazy="false" cascade="all-delete-orphan" > <key column="userid"></key> <one-to-many class="test.pojo.Article"></one-to-many> </bag> </class> </hibernate-mapping>
其实关键的一段是
<bag name="articles" table="article" order-by="id asc" lazy="false" cascade="all-delete-orphan" > <key column="userid"></key> <one-to-many class="test.pojo.Article"></one-to-many> </bag>
这一段实现对象与对象的级联关系
文章Article.hbm.xml代码如下:
<hibernate-mapping> <!--指定类到表的映射 --> <class name="test.pojo.Article" table="article"> <!--主键id的生成机制:native将自动根据数据生成,mysql是自增长方式 --> <id name="id" column="id"> <generator class="native"></generator> </id> <!--设定Article 类每个属性到article表中 对应列名的映射 --> <property name="title" column="title"></property> <property name="content" column="content"></property> <property name="publishTime" column="publishTime"></property> <property name="published" column="published"></property> <property name="clickCount" column="clickCount"></property> <property name="type" column="type"></property> <!--设定Article对象与Userinfo对象的多对一 关系 --> <many-to-one name="user" class="test.pojo.Userinfo" fetch="select" cascade="delete" outer-join="true"> <column name="userid"/> </many-to-one> </class> </hibernate-mapping>
关键的一段是
<many-to-one name="user" class="test.pojo.Userinfo" fetch="select" cascade="delete" outer-join="true"> <column name="userid"/> </many-to-one>
这样写在测试时“增”,“改”,“查”是可以实现了,但是删除就不行。
现在,我要把一个博主删掉,代码:
Userinfo temuser=userDao.getUserinfoById(4); userDao.deleteUser(temuser);
会报如下错误:
Hibernate: select userinfo0_.id as id0_0_, userinfo0_.name as name0_0_, userinfo0_.psw as psw0_0_, userinfo0_.signature as signature0_0_, userinfo0_.sex as sex0_0_, userinfo0_.age as age0_0_, userinfo0_.birthday as birthday0_0_, userinfo0_.qq as qq0_0_, userinfo0_.e_mail as e9_0_0_, userinfo0_.phone as phone0_0_, userinfo0_.occupation as occupation0_0_, userinfo0_.score as score0_0_, userinfo0_.graduateSchool as graduat13_0_0_, userinfo0_.country as country0_0_, userinfo0_.province as province0_0_, userinfo0_.head_path as head16_0_0_ from userinfo userinfo0_ where userinfo0_.id=? Hibernate: select articles0_.userid as userid0_1_, articles0_.id as id1_, articles0_.id as id1_0_, articles0_.title as title1_0_, articles0_.content as content1_0_, articles0_.publishTime as publishT4_1_0_, articles0_.published as published1_0_, articles0_.clickCount as clickCount1_0_, articles0_.type as type1_0_, articles0_.userid as userid1_0_ from article articles0_ where articles0_.userid=? order by articles0_.id asc 查询用户‘xiang'成功! Hibernate: update article set userid=null where userid=? 1953 [main] WARN org.hibernate.util.JDBCExceptionReporter - SQL Error: 0, SQLState: 22001 1953 [main] ERROR org.hibernate.util.JDBCExceptionReporter - Data truncation: Column was set to data type implicit default; NULL supplied for NOT NULL column 'userid' at row 1 1953 [main] ERROR org.hibernate.event.def.AbstractFlushingEventListener - Could not synchronize database state with session org.hibernate.exception.DataException: Could not execute JDBC batch update at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:102) at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275) at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:262) at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:180) 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:1206) at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:375) at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137) at test.DAO.UserinfoDAO.deleteUser(UserinfoDAO.java:70) at test.test.TestUserinfo.main(TestUserinfo.java:25) Caused by: java.sql.BatchUpdateException: Data truncation: Column was set to data type implicit default; NULL supplied for NOT NULL column 'userid' at row 1 at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1213) at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:912) at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70) at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268) ... 9 more
这是为什么呢?
我们首先看它执行的sql语句,它为什么要update文章表呢?
其实这跟hibernate的inverse有很大的关系,现在来看下inverse:
下面是百度百科对inverse的解释
其中还有一段时cascade和inverse的区别
而在binernate的文档里也写有
所以要是在Userinfo.hbm.xml没设置inverse的话,它默认的是false,那么它就会把级联关系刷新,因为user_id是在
article表中设置,所以会出现user_id=null,所以会报错。
当在Userinfo.hbm.xml设置 inverse="true",它就不会再去更新级联关系,就可以直接进入数据库层面操作数据,所以上面删除用户时同时也把有级联关系的文章删掉了。
所以解决级联的“增删查改”问题,应该在“一对多”关系中的“一方”设置inverse=true;
如:
<bag name="articles" table="article" order-by="id asc" lazy="false" cascade="all-delete-orphan" inverse="true"> <key column="userid"></key> <one-to-many class="test.pojo.Article"></one-to-many> </bag>
这样就行了。