从SpringMVC到SpringBoot的Hibernate配置

时间:2017-11-15 15:27:43

标签: java hibernate spring-boot

我(该死的)移植SpringMVC应用程序,将Tomcat中的战争部署到SpringBootApplication,我面临很多问题,基本上来自Hibernate。

应用程序是使用DAO / Service模式制作的。 我知道Spring引导想使用Spring数据JPA,但我不想重构所有的应用程序。

问题尤其在某个地方我得到了No Session的hibernate异常,而且更多的是旧的SpringMVC应用程序工作的org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role

例如,我有这个实体

@Entity
@Table(name = "PARK")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "idPark")
public class Park implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = -7630704706109692038L;
    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "id_park", unique = true, nullable = false)
    private int idPark;

    @NotEmpty
    @Column(name = "nome_park")
    private String nomePark;

    @Column(name = "latitude")
    private double latitude;

    @Column(name = "longitude")
    private double longitude;

    @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.DETACH, CascadeType.REFRESH}, mappedBy = "park")
    @JsonIgnore
    private List<Piano> piani;
//getters and setters

如果我打电话给控制器

List<Piano> piani = pianoService.findPianoByPark(park);

来自我的@Transactional注释的服务类,我仍然得到例外

这就是我配置Hibernate的方式

@Configuration
@EnableTransactionManagement
@ComponentScan({ "it.besmart.epark.persistence" })
@PropertySource(value = { "classpath:application.properties" })
public class HibernateConfiguration {

@Autowired
private Environment environment;

@Bean
public LocalSessionFactoryBean sessionfactory(){
    LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
    sessionFactory.setDataSource(dataSource());
    sessionFactory.setPackagesToScan(new String[] {"it.besmart.epark.persistence.model"});
    sessionFactory.setHibernateProperties(hibernateProperties());
    return sessionFactory;
}

@Bean
public DataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
    dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
    dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
    dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
    return dataSource;
}

private Properties hibernateProperties() {
    Properties properties = new Properties();
    properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
    properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
    properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
    return properties;        
}

@Bean
@Autowired
public HibernateTransactionManager transactionManager(SessionFactory s) {
   HibernateTransactionManager txManager = new HibernateTransactionManager();
   txManager.setSessionFactory(s);
   return txManager;
}
}

我认为这是一个配置问题,因为旧的应用程序可以使用这个模式,所以可能使用Spring启动我们需要配置其他东西来使用Hibernate。 我使用的是Spring Boot 1.5.8以及Hibernate 5.0.12.Final

2 个答案:

答案 0 :(得分:0)

我认为你试图在Hibernate事务之外获取一个延迟加载的集合(例如,在视图,控制器或非事务服务中)。您可以尝试使用getPiani() @Transactional调用对该课程进行注释。

还要记住,一个好的做法是只有服务层事务。

答案 1 :(得分:0)

如果你在类路径中拥有所有必需的依赖项,则不必再显式配置hibernate。 因此,请确保已将spring-boot-starter-data-jpaspring-boot-starter-data-jdbc添加为依赖项。

尝试删除HibernateConfiguration并在application.properties中添加配置,以便Spring Boot可以处理设置:

spring.jpa.database-platform = org.hibernate.dialect.PostgreSQL94Dialect
spring.jpa.show-sql = false
spring.datasource.url = jdbc:...
spring.datasource.username = ...
spring.datasource.password = ...
spring.datasource.driver-class-name=...jdbc.Driver

您可以在此处阅读有关使用Spring Boot的数据库配置的更多信息: https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html 可用应用程序属性的参考: https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

只要您不停用实体,Spring Boot就会自动选择您的实体。 如果您确实需要指定包,则可以使用@EntityScan执行此操作。例如,我们必须在我们的实体中执行此操作,而不是我们的Application类。

@SpringBootApplication
@EntityScan(basePackages = { "it.besmart.epark.persistence" })
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}