欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > > 文章正文

Hibernate一对一双向关联映射以及相互引用toString()方法的错误原因,hibernatetostring

来源: javaer 分享于  点击 18633 次 点评:138

Hibernate一对一双向关联映射以及相互引用toString()方法的错误原因,hibernatetostring


问题引入:首先我们搭建hibernate一对一双向关联关系,在我们建立hibernate一对一双向关联之后不能再toString()方法中相互引入,否则会报StackOverFlowError,也就是栈深度不够异常。为什么会出现这种错误,我们先搭建框架和配置关联关系,然后分析错误;我这里使用JDK-1.6和Hibernate-3.2版本,数据库使用Mysql.

一、首先我们搭建hibernate框架

  1.首先建立一个Java工程

  2.然后引入hibernate所需要的jar包和相关数据库连接包

  3.然后创建hibernate,cfg.xml文件(我这里提前把映射文件注入进来了)

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<!-- Generated by MyEclipse Hibernate Tools.                   -->
<hibernate-configuration>

    <session-factory>
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/accp2</property>
        <property name="connection.username">root</property>
        <property name="connection.password">123</property>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="myeclipse.connection.profile">mysql</property>
        
         <!-- 自动映射成表 -->
        <property name="hbm2ddl.auto">update</property>
        <!-- 生成格式化的sql语句 -->
        <property name="format_sql">true</property>
        <!-- 在控制台打印SQL语句 -->
        <property name="show_sql">true</property>
        
        <mapping resource="com/accp/model/IdCard.hbm.xml"/>
        <mapping resource="com/accp/model/User.hbm.xml"/>
    
    </session-factory>

</hibernate-configuration>

4.然后创建实体类,这里我用User用户类和IdCard身份信息类来关联,就像一个人只能有一张身份证,一张身份证也只能找到一个名字,正好构成一对一双向关联关系。

    4.1 创建User.java

package com.accp.model;

import java.io.Serializable;

/**
 * @author huangdaye
 *用户实体类
 */
public class User implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private Integer id;
	
	private String username;
	
	private String password;
	
	private IdCard idCard;

	public User() {
		super();
		// TODO Auto-generated constructor stub
	}

	public User(String username, String password) {
		super();
		this.username = username;
		this.password = password;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public IdCard getIdCard() {
		return idCard;
	}

	public void setIdCard(IdCard idCard) {
		this.idCard = idCard;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", password="
				+ password + ", idCard=" + idCard + "]";
	}

	

}

 4.2创建User.hbm.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 配置用户实体类的映射文件 -->
<hibernate-mapping package="com.accp.model">
      <class name="User" table="user">
           <id name="id" column="u_id" type="java.lang.Integer">
              <generator class="native"></generator>
           </id>
           <property name="username" column="u_username" type="java.lang.String"/>
           <property name="password" column="u_password" type="java.lang.String"/>
           <!-- 配置一对一的关联关系, 使用unique属性将多对一转化为一对一-->
           <many-to-one name="idCard" column="cid" 
           class="com.accp.model.IdCard" unique="true"/>
      </class>

</hibernate-mapping>

4.3创建Idcard.java

package com.accp.model;

import java.io.Serializable;

/**
 * @author huangdaye
 *用户身份证实体类
 */
public class IdCard implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private Integer id;
	private String number;
	private User user;
	
	public IdCard() {
		super();
		// TODO Auto-generated constructor stub
	}
	public IdCard(String number) {
		super();
		this.number = number;
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getNumber() {
		return number;
	}
	public void setNumber(String number) {
		this.number = number;
	}
	public User getUser() {
		return user;
	}
	public void setUser(User user) {
		this.user = user;
	}
	@Override
	public String toString() {
		return "IdCard [id=" + id + ", number=" + number + ", user=" + user
				+ "]";
	}
	
}


4.4创建IdCard.hbm.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 身份证实体类映射文件 -->
<hibernate-mapping package="com.accp.model">
      <class name="IdCard" table="idcard">
           <id name="id" column="c_id" type="java.lang.Integer">
              <generator class="native"></generator>
           </id>
           <property name="number" column="c_number" type="java.lang.String"/>
           
           <!-- 配置一对一关联关系 -->
           <one-to-one name="user" class="com.accp.model.User" property-ref="idCard"/>
      </class>
      
</hibernate-mapping>


5.建立开启Session的工具类
package com.accp.tools;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class Tool {
	
	private static Configuration cfg;
	private static SessionFactory sessionFactory;
	
	static{
		cfg=new Configuration().configure();
		sessionFactory=cfg.buildSessionFactory();
	}
	
	public Session getSession(){
		return sessionFactory.openSession();
	}
}


6.建立Test.java测试类

package com.accp.test;

import java.util.Iterator;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.After;
import org.junit.Before;

import com.accp.model.IdCard;
import com.accp.model.User;
import com.accp.tools.Tool;

public class Test {
	private Session session;
	private Transaction transaction;
	
	@Before
	public void before(){
		session=new Tool().getSession();
		transaction=session.beginTransaction();
	}
	
	@After
	public void after(){
		try {
			transaction.commit();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
			transaction.rollback();
		}finally{
			session.close();
		}
	}
	
	@org.junit.Test
	public void add(){
		User u=new User("leo003", "123");
		IdCard ic=new IdCard("430904199412131134");
		u.setIdCard(ic);
		session.save(ic);
		session.save(u);
	}
	
	@org.junit.Test
	public void query(){
		User u=(User) session.load(User.class, 1);
		System.out.println("---------------------------------------------------");
		System.out.println(u);
		System.out.println("---------------------------------------------------");
		User u1=(User) session.get(User.class, 1);
		System.out.println(u1);
	}
	
	public void queryList(){
		String hql="select from User";
		Query query=session.createQuery(hql);
		List<User> list=query.list();
		Iterator<User> it=list.iterator();
		while (it.hasNext()) {
			User user = (User) it.next();
			System.out.println(user);
		}
	}
	
	
}

注:这里User类和IdCard类在toString()方法上存在相互调用,为了能直接使用toString()直接输出关联对象的信息

然后执行Test类中的query()方法,这里使用JUnit测试,测试结果如下:


这里我直接截图,可以看出能发出SQL语句,query获取不到对应的对象信息,而且出现了StackOverFlowError的错误,原因在于Java在栈区调用方法的时候出现了死循环,导致一直调用对应对象toString()的方法,然后出现栈内存深度不够,为什么不出现OutOfMemoryError的错误呢?原因在于Java虚拟机内存分布中,栈区是一个储存基本数据和执行方法的区域,而在单线程中,由于内存够用,在出现OutOfMemoryError之前就会出现StackOverFlowError错误。然而在多线程并发中就有可能会出现OutOfMemoryError,因为多个线程同时请求,就会造成栈区的动态扩展内存不够,出现内存溢出的异常。


我们删除其中一个JavaBean中的对应对象的调用,再测试,这里我们删掉toString()方法中IdCard调用


package com.accp.model;

import java.io.Serializable;

/**
 * @author huangdaye
 *用户身份证实体类
 */
public class IdCard implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private Integer id;
	private String number;
	private User user;
	
	public IdCard() {
		super();
		// TODO Auto-generated constructor stub
	}
	public IdCard(String number) {
		super();
		this.number = number;
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getNumber() {
		return number;
	}
	public void setNumber(String number) {
		this.number = number;
	}
	public User getUser() {
		return user;
	}
	public void setUser(User user) {
		this.user = user;
	}
	@Override
	public String toString() {
		return "IdCard [id=" + id + ", number=" + number + "]";
	}
	
}

然后再在测试类中执行query()方法,看一看出能发出sql语句,而且正确读取到数据库的结果 。







最后,这是我第一次发博客,也是我个人根据自己学习Java虚拟机结合JavaEE项目中的一些问题总结出来的,如果有不对之处,欢迎大家指出!!!


相关文章

    暂无相关文章

用户点评