Hibernate一对一双向关联映射以及相互引用toString()方法的错误原因,hibernatetostring
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>
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();
}
}
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项目中的一些问题总结出来的,如果有不对之处,欢迎大家指出!!!
相关文章
- 暂无相关文章
用户点评