Hibernate一对一双向关联映射以及相互引用toString()方法的错误原因
2016-12-27 14:28
507 查看
问题引入:首先我们搭建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的工具类
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测试,测试结果如下:
![](https://img-blog.csdn.net/20161227150922990)
这里我直接截图,可以看出能发出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语句,而且正确读取到数据库的结果 。
![](https://img-blog.csdn.net/20161227152503311)
最后,这是我第一次发博客,也是我个人根据自己学习Java虚拟机结合JavaEE项目中的一些问题总结出来的,如果有不对之处,欢迎大家指出!!!
一、首先我们搭建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 sessionFac 4000 tory; 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项目中的一些问题总结出来的,如果有不对之处,欢迎大家指出!!!
相关文章推荐
- hibernate一对一主键关联映射双向
- Hibernate中的one2one映射实例二(一对一主键关联映射双向)
- 【Hibernate步步为营】--双向关联一对一映射详解(一)
- Hibernate关系映射(2)_一对一双向外键关联
- Hibernate一对多单向关联和双向关联映射方法及其优缺点
- Hibernate从入门到精通(六)一对一双向关联映射
- 【Hibernate步步为营】--双向关联一对一映射详解(二)
- 【Hibernate步步为营】--双向关联一对一映射详解(二)
- 【Hibernate步步为营】--双向关联一对一映射详解(二)
- 【Hibernate步步为营】--双向关联一对一映射详解(二)
- Hibernate多对多单向关联和双向关联映射的方法
- Hibernate关系映射(4)_一对一双向主键关联
- ORM框架Hibernate (四) 一对一单向、双向关联映射
- 【Hibernate步步为营】--双向关联一对一映射详解(二)
- Hibernate关系映射 --- 一对一实例分析(双向关联,是基于主键的)
- hibernate 关系映射之 双向外键关联一对一
- ORM框架Hibernate (四) 一对一单向、双向关联映射
- Hibernate从入门到精通(六)一对一双向关联映射
- 【Hibernate步步为营】--双向关联一对一映射详解(二)
- 【Hibernate步步为营】--双向关联一对一映射详解(二)