Hibernate OneToMany:StackOverFlowError和Partial Save

时间:2017-05-17 21:51:18

标签: java spring hibernate

我在Hibernate上创建了一个简单易用的小应用程序。 我有一个Country对象和一个City对象。一个国家可以拥有许多城市。

我有以下无法解决的问题:

  • save方法在Countries表中创建记录,但不在相应的Cities表中创建记录。

  • list方法引发以下StackOverFlow异常。堆栈跟踪是1027行,所以我只发布前10行,因为它似乎重复。

堆栈跟踪

SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/datatracker] threw exception [Handler processing failed; nested exception is java.lang.StackOverflowError] with root cause
java.lang.StackOverflowError
    at java.lang.Integer.toString(Unknown Source)
    at java.lang.Integer.toString(Unknown Source)
    at java.lang.String.valueOf(Unknown Source)
    at java.lang.StringBuilder.append(Unknown Source)
    at com.johnsteed.datatracker.model.Country.toString(Country.java:93)
    at java.lang.String.valueOf(Unknown Source)
    at java.lang.StringBuilder.append(Unknown Source)

代码如下:

城市类

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import org.springframework.stereotype.Component;

@Component
@Entity
@Table(name = "cities")
public class City {

    @Id 
    @GeneratedValue
    Integer id;
    String name;    
    Boolean visited;
    String mainAttraction;  

    @ManyToOne
    @JoinColumn(name = "countryId")
    Country country;

    public City () { }

    public City(Integer id, String name, Boolean visited, String mainAttraction, Country country) {     
        this.id = id;
        this.name = name;
        this.visited = visited;
        this.mainAttraction = mainAttraction;
        this.country = country;
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Boolean getVisited() {
        return visited;
    }

    public void setVisited(Boolean visited) {
        this.visited = visited;
    }

    public String getMainAttraction() {
        return mainAttraction;
    }

    public void setMainAttraction(String mainAttraction) {
        this.mainAttraction = mainAttraction;
    }

    public Country getCountry() {
        return country;
    }

    public void setCountry(Country country) {
        this.country = country;
    }

    @Override
    public String toString() {
        return "City [id=" + id + ", name=" + name + ", visited=" + visited + ", mainAttraction=" + mainAttraction + ", country=" + country + "]";
    }


}

国家/地区类

首选的是获取提取类型

import java.util.List;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.springframework.stereotype.Component;

@Component
@Entity
@Table(name = "countries")
public class Country {

    @Id 
    @GeneratedValue
    Integer id;
    String name;
    String continent;
    Boolean visited;
    String leader;

    @OneToMany(fetch = FetchType.EAGER, mappedBy = "country")
    List<City> cities;


    public Country() { }

    public Country(Integer id, String name, String continent, Boolean visited, String leader, List<City> cities) {  
        this.id = id;
        this.name = name;
        this.continent = continent;
        this.visited = visited;
        this.leader = leader;
        this.cities = cities;
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getContinent() {
        return continent;
    }

    public void setContinent(String continent) {
        this.continent = continent;
    }

    public Boolean getVisited() {
        return visited;
    }

    public void setVisited(Boolean visited) {
        this.visited = visited;
    }

    public String getLeader() {
        return leader;
    }

    public void setLeader(String leader) {
        this.leader = leader;
    }

    public List<City> getCities() {
        return cities;
    }

    public void setCities(List<City> cities) {
        this.cities = cities;
    }

    @Override
    public String toString() {
        return "Country [id=" + id + ", name=" + name + ", continent=" + continent + ", visited=" + visited + ", leader=" + leader + ", cities=" + cities + "]";
    }

}

import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.johnsteed.datatracker.model.Country;

@SuppressWarnings("unchecked")
@Repository
@Transactional("DataTrackerTransactionManager")
@Component("Dao")
public class Dao {

    // MEMBERS

    @Autowired
    @Qualifier("DataTrackerSessionFactory")
    protected SessionFactory sessionFactory;

    // DATABASE METHODS

    @Transactional
    public List<Country> getCountries(){

        Criteria criteria = session().createCriteria(Country.class);        
        criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

        return criteria.list();
    }

    @Transactional
    public void saveCountry(Country country){

        session().save(country);

    }

    @Transactional
    protected Session session() {
        // convenience method
        return sessionFactory.getCurrentSession();
    }

}

调用Dao方法

@RequestMapping(value = "geography/testDao", method = RequestMethod.GET, produces = "application/json")
public @ResponseBody void testDao() throws Exception {


    System.out.println(dao.getCountries());

    Country country = new Country();
    country.setContinent("Asia");
    country.setLeader("Xi Jinping");
    country.setName("China");
    country.setVisited(false);

    City city1 = new City();
    city1.setMainAttraction("Great Wall");
    city1.setName("Beijing");
    city1.setVisited(false);

    List<City> cityList = new ArrayList<City>();
    cityList.add(city1);
    country.setCities(cityList);

    dao.saveCountry(country);

}

Spring Dao配置类

import java.util.Properties;
import javax.sql.DataSource;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTemplate;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.EnableTransactionManagement;


@Component
@Configuration
@EnableTransactionManagement
public class DaoConfig {

    @Bean(name="DataTrackerDataSource")
    public DataSource getDataSource() {

        DriverManagerDataSource ds = new DriverManagerDataSource();

        try {

            String username = "root";
            String password = "xxx";
            String dbUrl = "jdbc:mysql://localhost:3306/geography";
            String driverClassName = "com.mysql.jdbc.Driver";

            ds.setDriverClassName(driverClassName);
            ds.setUrl(dbUrl);
            ds.setUsername(username);
            ds.setPassword(password);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return ds;

    }

    //Hibernate Beans

    @Bean(name="DataTrackerTransactionManager") 
    @Autowired
    public HibernateTransactionManager transactionManager(@Qualifier("DataTrackerSessionFactory") SessionFactory sessionFactory) {
        HibernateTransactionManager htm = new HibernateTransactionManager();
        htm.setSessionFactory(sessionFactory);
        return htm;
    }

    @Bean(name="DataTrackerHibernateTemplate")  
    @Autowired
    public HibernateTemplate getHibernateTemplate(@Qualifier("DataTrackerSessionFactory") SessionFactory sessionFactory) {
        HibernateTemplate hibernateTemplate = new HibernateTemplate(sessionFactory);
        return hibernateTemplate;
    }

    @Bean(name="DataTrackerSessionFactory") 
    public LocalSessionFactoryBean getSessionFactory() {
        LocalSessionFactoryBean asfb = new LocalSessionFactoryBean();
        asfb.setDataSource(getDataSource());
        asfb.setHibernateProperties(getHibernateProperties());
        asfb.setPackagesToScan(new String[] { "com.johnsteed.datatracker.dao", "com.johnsteed.datatracker.model" });
        return asfb;
    }

    @Bean(name="DataTrackerHibernateProperties")
    public Properties getHibernateProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
        properties.put("hibernate.show_sql", "false");
        properties.put("hibernate.hbm2ddl.auto", "update");
        properties.put("hibernate.hbm2ddl.auto", "update");     

        return properties;
    }

}

国家/地区表

id  int(11)
name    varchar(45)
continent   varchar(45)
visited tinyint(4)
leader  varchar(45)

城市表

id  int(11)
name    varchar(45)
countryId   varchar(45)
visited tinyint(4)
mainAttraction  varchar(45)

我感谢任何帮助/建议,因为我无法弄清楚为什么代码对于这两种基本方法是不正确的。

0 个答案:

没有答案