Hibernate中的一对一关系

首先转别人的一片例子:

转贴:http://www.wangchao.net.cn/bbsdetail_68735.html

-----------------------------------------------------------------------------------------------------------------------------------------------

  一对一关联有两种映射方式:一种是使用主键关联,限制两个数据表的主键使用相同的值;另一种是一个外键和一个惟一关键字对应。
  下面的例子采用主键关联。一人一个房间。
  SQL:
  CREATE TABLE user (
   USER_ID varchar(10) NOT NULL default '',
   NAME varchar(16) NOT NULL default '',
   PRIMARY KEY (USER_ID)
  );
  CREATE TABLE room (
   ROOM_ID varchar(10) NOT NULL default '',
   ADDRESS varchar(32) NOT NULL default '',
   PRIMARY KEY (ROOM_ID)
  );
  User.java:
  package ivan.hibernate.one2one;
  public class User {
   private long id;
   private String name;
   private Room room;
   ...//Getters and Setters
  }
  User.hbm.xml:
  <hibernate-mapping>
   <class name="ivan.hibernate.one2one.User" table="USER">
   <id name="id" column="USER_ID" unsaved-value="0">
   <generator class="increment"/>
   </id>
   <property name="name">
   <column name="NAME" length="16" not-null="true"/>
   </property>
   <one-to-one name="room"
   class="ivan.hibernate.one2one.Room"
   cascade="all"/>
   </class>
  </hibernate-mapping>
  Room.java:
  package ivan.hibernate.one2one;
  public class Room {
   private long id;
   private String address;
   private User user;
   ...// Getters and Setters
  }
  Room.hbm.xml:
  <hibernate-mapping>
   <class name="ivan.hibernate.one2one.Room" table="ROOM">
   <id name="id" column="ROOM_ID" unsaved-value="0">
   <generator class="foreign">
   <param name="property">user</param>
   </generator>
   </id>
   <property name="address" type="string"/>
   <one-to-one name="user"
   class="ivan.hibernate.one2one.User"
   constrained="true"/>
   </class>
  </hibernate-mapping>
  hibernate.cfg.xml:
  <hibernate-configuration>
   <session-factory>
   <!-- properties -->
   <property name="connection.username">root</property>
   <property name="connection.url">jdbc:mysql://localhost:3306/hibernate</property>
   <property name="dialect">net.sf.hibernate.dialect.MySQLDialect</property>
   <property name="connection.password"></property>
   <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
   <mapping resource="ivan/hibernate/one2one/Room.hbm.xml" />
   <mapping resource="ivan/hibernate/one2one/User.hbm.xml" />
   </session-factory>
  </hibernate-configuration>
  Test.java:
  package ivan.hibernate.one2one;
  import net.sf.hibernate.*;
  import net.sf.hibernate.cfg.*;
  public class Test {
   public static void main(String[] args) throws HibernateException {
   SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
  
   Room room = new Room();
   room.setAddress("China-10-911");
  
   User user = new User();
   user.setName("bush");
   user.setRoom(room);
   room.setUser(user);
  
   Session session = sessionFactory.openSession();
   Transaction tx= session.beginTransaction();
   session.save(user);
  
   tx.commit();
   session.close();
   sessionFactory.close();
   }
  }
  运行后,在mysql,hibernate 数据库中可看见 User 表和 Room 表都增加了一条记录。
  存在问题:如果 Room 表已经存在某个 id 值的记录,而增加的 User 记录的 id 将会是此 id 值,将会抛出异常:java.sql.BatchUpdateException: Duplicate entry ...。这是因为 Room 的 id 是根据 User 的 id 来的。如果新增加的 id 在 Room 表中已经存在,就会抛出 SQL 异常。您可以试验,上面步骤成功后,只将表 User 清空。这样表 User 的记录 id 自增又会从 1 开始。当重新运行程序时就会抛出异常。

-----------------------------------------------------------------------------------------------------------------------------------------------

 

这篇文章是从网上搜索到的,原因是自己的工程当时遇见一个问题,我这边的机器人服务器的Hibernate和另外一边的PHP公用一个数据库的两张表:

uchome_blog:

                      blogid   mediumint(8) unsigned not  null

                      uid        mediumint(8) unsigned not  null

                      username char(15) not null

                      ....

uchome_blogfield 

                      blogid   mediumint(8) unsigned not  null

                      uid        mediumint(8) unsigned not  null

                      message mediumtext not null

                      .....

 

 现在的情况是:上面两张表关系是一对一,其中,blogfield的主键参照blog的主键,字段名字和值都是相同的,操作中保持级联更新删除。

数据库是MySQL5,配置文件<因为我负责机器人部分去了,我整完框架,这部分就有另外一个同事去做了,配置文件是他写的>:

    <class name="UchomeBlog" table="uchome_blog" catalog="stage_uhome">
        <id name="blogid" type="java.lang.Integer">
            <column name="blogid" />
            <generator class="increment" />
        </id>
        <property name="uid" type="java.lang.Integer">
            <column name="uid" not-null="true" />
        </property>
        <property name="username" type="java.lang.String">
            <column name="username" length="15" not-null="true" />
        </property>
        <property name="subject" type="java.lang.String">
            <column name="subject" length="80" not-null="true" />
        </property>
        <property name="classid" type="java.lang.Short">
            <column name="classid" not-null="true" />
        </property>
        <property name="viewnum" type="java.lang.Integer">
            <column name="viewnum" not-null="true" />
        </property>
        <property name="replynum" type="java.lang.Integer">
            <column name="replynum" not-null="true" />
        </property>
        <property name="tracenum" type="java.lang.Integer">
            <column name="tracenum" not-null="true" />
        </property>
        <property name="dateline" type="long">
            <column name="dateline" not-null="true" />
        </property>
        <property name="pic" type="java.lang.String">
            <column name="pic" length="120" not-null="true" />
        </property>
        <property name="picflag" type="java.lang.Byte">
            <column name="picflag" not-null="true" />
        </property>
        <property name="noreply" type="java.lang.Byte">
            <column name="noreply" not-null="true" />
        </property>
        <property name="friend" type="java.lang.Byte">
            <column name="friend" not-null="true" />
        </property>
        <property name="password" type="java.lang.String">
            <column name="password" length="10" not-null="true" />
        </property>
       
        <one-to-one name="blogfield"
                    class="UchomeBlogfield"
                    cascade="all"/>
    </class>   
   
    <class name="UchomeBlogfield" table="uchome_blogfield" catalog="stage_uhome">

        <id name="blogid" column="blogid" unsaved-value="0">
            <generator class="foreign">
                <param name="property">blog</param>
            </generator>
        </id>
        <property name="uid" type="java.lang.Integer">
            <column name="uid" not-null="true" />
        </property>
        <property name="tag" type="java.lang.String">
            <column name="tag" not-null="true" />
        </property>
        <property name="message" type="java.lang.String">
            <column name="message" length="16777215" not-null="true" />
        </property>
        <property name="postip" type="java.lang.String">
            <column name="postip" length="20" not-null="true" />
        </property>
        <property name="related" type="java.lang.String">
            <column name="related" length="65535" not-null="true" />
        </property>
        <property name="relatedtime" type="long">
            <column name="relatedtime" not-null="true" />
        </property>
        <property name="targetIds" type="java.lang.String">
            <column name="target_ids" length="65535" not-null="true" />
        </property>
       
        <one-to-one name="blog"
                    class="UchomeBlog"
                    constrained="true"/>
    </class> 

 

 工程能跑起来,开始操作也正常,保存了几次之后,抛出异常:

2009-09-18 10:13:53,312 - 3056875 [pool-1-thread-1] WARN  org.hibernate.util.JDBCExceptionReporter  - SQL Error: 1062, SQLState: 23000
2009-09-18 10:13:53,312 - 3056875 [pool-1-thread-1] ERROR org.hibernate.util.JDBCExceptionReporter  - Duplicate entry '6659' for key 'PRIMARY'
2009-09-18 10:13:53,328 - 3056891 [pool-1-thread-1] ERROR org.hibernate.event.def.AbstractFlushingEventListener  - Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
 at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
 at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
 at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:249)
 at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:235)
 at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:139)
 at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
 at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
 at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
 at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
 at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
 at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:575)
 at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:651)
 at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:621)
 at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:311)
 at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:117)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)
 at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:203)
 at $Proxy5.publishBlog(Unknown Source)
 at sun.reflect.GeneratedMethodAccessor65.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:304)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:172)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:139)
 at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:107)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)
 at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:203)
 at $Proxy6.publishBlog(Unknown Source)
 at sun.reflect.GeneratedMethodAccessor65.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:304)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:172)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:139)
 at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:107)
 at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)
 at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:203)
 at $Proxy6.publishBlog(Unknown Source)
 at com.iouyou.robot.model.helper.MessageProcesser.processMsg(MessageProcesser.java:156)
 at com.iouyou.robot.model.QQRobotModel.handleCommonsMessage(QQRobotModel.java:238)
 at com.iouyou.robot.model.QQRobotModel.receivedCommonsMessage(QQRobotModel.java:198)
 at com.iouyou.robot.model.QQRobotModel.qqEvent(QQRobotModel.java:129)
 at edu.tsinghua.lumaqq.qq.QQClient.fireQQEvent(QQClient.java:1084)
 at edu.tsinghua.lumaqq.qq.BasicFamilyProcessor.processReceiveIM(BasicFamilyProcessor.java:1836)
 at edu.tsinghua.lumaqq.qq.BasicFamilyProcessor.packetArrived(BasicFamilyProcessor.java:275)
 at edu.tsinghua.lumaqq.qq.ProcessorRouter.packetArrived(ProcessorRouter.java:64)
 at edu.tsinghua.lumaqq.qq.QQClient.firePacketArrivedEvent(QQClient.java:1073)
 at edu.tsinghua.lumaqq.qq.PacketEventTrigger.call(PacketEventTrigger.java:47)
 at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
 at java.util.concurrent.FutureTask.run(FutureTask.java:138)
 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:98)
 at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:207)
 at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
 at java.lang.Thread.run(Thread.java:619)
Caused by: java.sql.BatchUpdateException: Duplicate entry '6659' for key 'PRIMARY'
 at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1669)
 at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1085)
 at sun.reflect.GeneratedMethodAccessor64.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.logicalcobwebs.proxool.ProxyStatement.invoke(ProxyStatement.java:100)
 at org.logicalcobwebs.proxool.ProxyStatement.intercept(ProxyStatement.java:57)
 at $java.sql.Statement$$EnhancerByProxool$$7b04b7fe.executeBatch(<generated>)
 at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
 at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:242)
 ... 52 more

 

Hibernate 我一般只是当作框架来用,很少深入框架本身里面一些东西,这个错误以前没遇见过。说是主键重复,可是到数据库查那个重复的主键,查不到数据,感觉有点奇怪,而且服务器跑起来之后,是保存了几条记录之后才出现这个问题的。

搜索了一下,于是搜索到上面转贴的帖子,大概理解了一下。于是尝试把映射文件的generator改称为native(在我用Hibernate和MySQL的经历中,从来都是用native的)映射文件如下:

 

    <class name="UchomeBlog" table="uchome_blog" catalog="stage_uhome">
        <id name="blogid" type="java.lang.Integer">
            <column name="blogid" />
            <generator class="native" />
        </id>
        <property name="uid" type="java.lang.Integer">
            <column name="uid" not-null="true" />
        </property>
        <property name="username" type="java.lang.String">
            <column name="username" length="15" not-null="true" />
        </property>
        <property name="subject" type="java.lang.String">
            <column name="subject" length="80" not-null="true" />
        </property>
        <property name="classid" type="java.lang.Short">
            <column name="classid" not-null="true" />
        </property>
        <property name="viewnum" type="java.lang.Integer">
            <column name="viewnum" not-null="true" />
        </property>
        <property name="replynum" type="java.lang.Integer">
            <column name="replynum" not-null="true" />
        </property>
        <property name="tracenum" type="java.lang.Integer">
            <column name="tracenum" not-null="true" />
        </property>
        <property name="dateline" type="long">
            <column name="dateline" not-null="true" />
        </property>
        <property name="pic" type="java.lang.String">
            <column name="pic" length="120" not-null="true" />
        </property>
        <property name="picflag" type="java.lang.Byte">
            <column name="picflag" not-null="true" />
        </property>
        <property name="noreply" type="java.lang.Byte">
            <column name="noreply" not-null="true" />
        </property>
        <property name="friend" type="java.lang.Byte">
            <column name="friend" not-null="true" />
        </property>
        <property name="password" type="java.lang.String">
            <column name="password" length="10" not-null="true" />
        </property>
       
        <one-to-one name="blogfield"
                    class="UchomeBlogfield"
                    cascade="all"/>
    </class>   
   
    <class name="UchomeBlogfield" table="uchome_blogfield" catalog="stage_uhome">

        <id name="blogid" column="blogid" unsaved-value="0">
            <generator class="foreign">
                <param name="property">blog</param>
            </generator>
        </id>
        <property name="uid" type="java.lang.Integer">
            <column name="uid" not-null="true" />
        </property>
        <property name="tag" type="java.lang.String">
            <column name="tag" not-null="true" />
        </property>
        <property name="message" type="java.lang.String">
            <column name="message" length="16777215" not-null="true" />
        </property>
        <property name="postip" type="java.lang.String">
            <column name="postip" length="20" not-null="true" />
        </property>
        <property name="related" type="java.lang.String">
            <column name="related" length="65535" not-null="true" />
        </property>
        <property name="relatedtime" type="long">
            <column name="relatedtime" not-null="true" />
        </property>
        <property name="targetIds" type="java.lang.String">
            <column name="target_ids" length="65535" not-null="true" />
        </property>
       
        <one-to-one name="blog"
                    class="UchomeBlog"
                    constrained="true"/>
    </class> 

 

跑一下,OK。于是不停的测试,不停的发保存记录。跑到了现在几个小时过去,还是没问题。看来问题是在这里了。

 

但是具体的详细问题出现的原因在哪里,还不知道。现在列出hibernate3中关于主键映射到底是native还是increment的描述:

 

increment:用于为long, short或者int类型生成 唯一标识。只有在没有其他进程往同一张表中插入数据时才能使用。 在集群下不要使用。

 

native:根据底层数据库的能力选择identity, sequence 或者hilo中的一个。

 

关于increment的试用,Hibernate API里面说的如此清楚了,呵呵。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值