使用一对多映射保存对象时Spring + Hibernate id问题

时间:2013-05-06 16:31:37

标签: spring hibernate hibernate-onetomany

我遇到了Hibernate 4和Spring 3的问题。我也在使用BoneCP。我正在尝试使用许多图像保存文章,并且效果很好。但是,当我尝试获取任何Image的ID时,它返回0.然而,在数据库中,一切都保存得很好。我猜问题存在于关系持久性或我对Hibernate的理解中,因为执行后id有效,但我找不到它。

我的档案: 的弹簧hibernate.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">    

    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" autowire="autodetect">
        <property name="dataSource" ref="dataSource" />
        <property name="annotatedClasses">
            <list>
<value>com.smiechmateusz.model.Article</value>
<value>com.smiechmateusz.model.Image</value>
            </list>
        </property>

        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
            </props>
        </property>
    </bean>  

    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
        <property name="targetDataSource">
            <ref local="mainDataSource" />
        </property>
    </bean>

    <bean id="mainDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/java" />
        <property name="username" value="root"/>
        <property name="password" value="toor"/>
        <property name="idleConnectionTestPeriod" value="60"/>
        <property name="idleMaxAge" value="240"/>    
        <property name="maxConnectionsPerPartition" value="60"/>
        <property name="minConnectionsPerPartition" value="20"/>
        <property name="partitionCount" value="3"/>
        <property name="acquireIncrement" value="10"/>                           
        <property name="statementsCacheSize" value="50"/>
        <property name="releaseHelperThreads" value="3"/>
    </bean>

    <bean id="txManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    <tx:annotation-driven transaction-manager="txManager" />

    <context:annotation-config />
    <context:component-scan base-package="com.smiechmateusz.dao" />

     <bean id="hibernateConfiguration" factory-bean="&amp;sessionFactory" factory-method="getConfiguration" /> 

    <bean id="AbstractHibernateDAO" abstract="true"
        class="com.smiechmateusz.dao.AbstractDAO">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    <bean id="ImageDAO" parent="AbstractHibernateDAO" class="com.smiechmateusz.dao.ImageDAO" />
    <bean id="ArticleDAO" parent="AbstractHibernateDAO" class="com.smiechmateusz.dao.ArticleDAO" />
</beans>

AbstractDAO.java

package com.smiechmateusz.dao;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.PersistentObjectException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
@Transactional()
public abstract class AbstractDAO<T extends Serializable> 
{
    private final Class<T> clazz;
    @Autowired
    SessionFactory sessionFactory;

    public AbstractDAO(final Class< T> clazzToSet) 
    {
        this.clazz = clazzToSet;
    }

    public T getById(final Long id) 
    {
        if (id != null)
            return (T) this.getCurrentSession().get(this.clazz, id);
        return null;
    }

    public List<T> getAll() 
    {
        return this.getCurrentSession().createQuery("from " + this.clazz.getName()).list();
    }

    public void create(final T entity) 
    {
        if (entity != null)
        {
            try
            {
                this.getCurrentSession().persist(entity);
            }
            catch (PersistentObjectException e)
            {
                this.getCurrentSession().saveOrUpdate(entity);
            }
        }
    }

    public void update(final T entity) 
    {
        if (entity != null)
        {
            this.getCurrentSession().merge(entity);

        }
    }

    public void delete(final T entity) 
    {
        if (entity != null)
            this.getCurrentSession().delete(entity);
    }

    public void deleteById(final Long entityId) 
    {
        final T entity = this.getById(entityId);
        if (entity != null)
            this.delete(entity);
    }

    public void setSessionFactory(SessionFactory sessionFactory) 
    {
        this.sessionFactory = sessionFactory;
    }

    protected final Session getCurrentSession() 
    {
        return this.sessionFactory.getCurrentSession();
    }

    public List<T> getWithCriteria(List<Criterion> criteria)
    {
        Criteria c = this.getCurrentSession().createCriteria(this.clazz);
        for (Criterion cr : criteria)
        {
            c.add(cr);
        }
        return c.list();
    }
}

ImageDAO.java

package com.smiechmateusz.dao;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.smiechmateusz.model.Image;

@Service
@Transactional()
public class ImageDAO extends AbstractDAO
{
    public ImageDAO()
    {
        super(Image.class);
    }
}

ArticleDAO.java

package com.smiechmateusz.dao;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.smiechmateusz.model.Article;

@Service
@Transactional()
public class ArticleDAO extends AbstractDAO
{
    public ArticleDAO()
    {
        super(Article.class);
    }
}

Image.java

package com.smiechmateusz.model;

import java.io.Serializable;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name="Image")
public class Image implements Serializable
{
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="id")
    long id;
    @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
    @JoinColumn(name="article")
    Article article;
    @Column(name="path")
    String path;
    @Column(name="type")
    int type;
    public long getId()
    {
        return id;
    }
    public void setId(long id)
    {
        this.id = id;
    }
    public Article getArticle()
    {
        return article;
    }
    public void setArticle(Article article)
    {
        this.article = article;
    }
    public String getPath()
    {
        return path;
    }
    public void setPath(String path)
    {
        this.path = path;
    }
    public int getType()
    {
        return type;
    }
    public void setType(int type)
    {
        this.type = type;
    }
}

Article.java

package com.smiechmateusz.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name="Article")
public class Article implements Serializable
{
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="id")
    long id;
    @Column(name="images")
    @OneToMany(targetEntity=com.smiechmateusz.model.Image.class, mappedBy="article",cascade=CascadeType.ALL, fetch=FetchType.LAZY)
    List<Image> images;
    @Column(name="description")
    String description;
    @Temporal(TemporalType.DATE)
    @Column(name="addDate")
    Date addDate;
    public Article()
    {
        this.images = new ArrayList<Image>();
    }
    public long getId()
    {
        return id;
    }
    public void setId(long id)
    {
        this.id = id;
    }
    public List<Image> getImages()
    {
        return images;
    }
    public void setImages(List<Image> images)
    {
        this.images = images;
    }
    public String getDescription()
    {
        return description;
    }
    public void setDescription(String description)
    {
        this.description = description;
    }
    public Date getAddDate()
    {
        return addDate;
    }
    public void setAddDate(Date addDate)
    {
        this.addDate = addDate;
    }
}

我正在使用以下代码进行测试:

ApplicationContext context = new ClassPathXmlApplicationContext("spring-hibernate.xml");
        Configuration config = (Configuration) context.getBean("hibernateConfiguration");
        new SchemaExport(config).create(true, true);
        ArticleDAO ad = (ArticleDAO) context.getBean("ArticleDAO");
        ImageDAO id = (ImageDAO) context.getBean("ImageDAO");
        Article a = new Article();
        Image i = new Image();
        i.setPath("path");
        i.setType(0);
        i.setArticle(a);
        a.setAddDate(new Date());
        a.setDescription("desc");
        Image i2 = new Image();
        i2.setPath("path2");
        i2.setType(1);
        i2.setArticle(a);
        List<Image> list = new ArrayList<Image>();
        list.add(i);
        list.add(i2);
        ad.create(a);
        a.setImages(list);
        ad.update(a);
        System.out.println(i.getId()); //Returns 0 instead of 1.

数据库查询:

mysql> SELECT * FROM Image;
+----+-------+------+---------+
| id | path  | type | article |
+----+-------+------+---------+
|  1 | path  |    0 |       1 |
|  2 | path2 |    1 |       1 |
+----+-------+------+---------+
2 rows in set (0.00 sec)

修改

如果我尝试获取Article a的ID,则返回有效的id(1)。

System.out.println(a.getId());
1

1 个答案:

答案 0 :(得分:1)

问题出在AbstractDAO.update()方法中。您尝试merge数据库的所有内容,但您应该save()新实体。

看一下这个问题Hibernate : Downside of merge() over update()