错误500:org.hibernate.HibernateException:找不到当前线程的会话

时间:2018-09-24 21:17:14

标签: java spring hibernate spring-mvc sessionfactory

当我尝试在项目中上传图片时出现此错误。项目必须执行良好,直到必须将图片有效地上传到数据库为止(我使用的是Postgresql),但是此最后一步永远行不通。

以下代码已更新,并考虑了以下答案。

这是我的控制器(一部分):

@Autowired
private FileUploadImpl fileUploadImpl;

...

@RequestMapping(value = "publish4" ,method = RequestMethod.POST)
public ModelAndView publish4(@Valid @ModelAttribute("fourthPublicationForm") final FourthPublicationForm form, final BindingResult errors,
                             @RequestParam("type") String type, @RequestParam("operation") String operation , @RequestParam CommonsMultipartFile[] fileUpload) {
    if (errors.hasErrors()) {
        //return helloPublish3(form,operation,type);
    }
    System.out.println("operation: "+ operation);
    System.out.println("type: "+ type);
    ps.create(form.getTitle(), form.getAddress(), operation, form.getPrice(), form.getDescription(), 
            type, form.getBedrooms(), form.getBathrooms(), form.getFloorSize(), form.getParking());

    if (fileUpload != null && fileUpload.length > 0) {
        for (CommonsMultipartFile aFile : fileUpload){

            System.out.println("Saving file: " + aFile.getOriginalFilename());

            UploadFile uploadFile = new UploadFile();
            uploadFile.setAddress(form.getAddress());
            uploadFile.setData(aFile.getBytes());
            fileUploadImpl.save(uploadFile);               
        }
    }
    return new ModelAndView("redirect:/hello/home");
}

这是界面中的fileUploadDao:

public interface FileUploadDao {
   void save(UploadFile uploadFile);
}

这在服务中

@Service
public class FileUploadImpl {

    @Autowired
    private FileUploadDao fileUploadDao;

    public FileUploadImpl() {
    }

    @Transactional
    public void save(UploadFile uploadFile) {
        fileUploadDao.save(uploadFile);
    }

}

以下是持久性的:

@Repository
public class FileUploadDAOImpl implements FileUploadDao {
    @Autowired
    private SessionFactory sessionFactory;

    public FileUploadDAOImpl() {
    }

    public FileUploadDAOImpl(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }


    public void save(UploadFile uploadFile) {
       sessionFactory.getCurrentSession().save(uploadFile);
    }
}

我在WebConfig.java中(除了其他东西)得到了

@Bean
public LocalSessionFactoryBean sessionFactory() {
   LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
   sessionFactory.setDataSource(dataSource());
   sessionFactory.setPackagesToScan(
       new String[] { "ar.edu.itba.paw" }
   );
   //sessionFactory.setHibernateProperties(hibernateProperties());

   return sessionFactory;
}

@Autowired
@Bean(name = "fileUploadDao")
public FileUploadDao getUserDao(SessionFactory sessionFactory) {
    return new FileUploadDAOImpl(sessionFactory);
}

@Bean(name = "multipartResolver")
public CommonsMultipartResolver getCommonsMultipartResolver() {
    CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
    multipartResolver.setMaxUploadSize(20971520);   // 20MB
    multipartResolver.setMaxInMemorySize(1048576);  // 1MB
    return multipartResolver;
}

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

更多错误:

org.hibernate.HibernateException: No Session found for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:106)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)
at ar.edu.itba.paw.persistence.FileUploadDAOImpl.save(FileUploadDAOImpl.java:25)
at ar.edu.itba.paw.webapp.controller.HelloWorldController.publish4(HelloWorldController.java:260)

我看到了其他问题,答案是缺乏对“事务性”的使用。我在这里使用该批注,但是我不确定它是否100%正确。

2 个答案:

答案 0 :(得分:2)

首先从@Transactional中删除FileUploadDAOImpl

相应地更改基本软件包,

sessionFactory.setPackagesToScan(
   new String[] { "base.package.to.scan" } 
);

base.package.to.scan似乎是无效的基本程序包命名,请将其更改为ar.edu.itba.paw

您需要交易经理来使用@Transactional。将其添加到WebConfig

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

这可能会使此代码正常工作,请尝试一下。

更新:还要确保WebConfig类上存在以下注释,

@Configuration
@ComponentScan({"ar.edu.itba.paw"})
@EnableTransactionManagement(mode = AdviceMode.PROXY)
public class WebConfig {
    // code
}

答案 1 :(得分:1)

正如您从一开始所说的,您已经混淆了实际的图层。仍然可以使它在您的情况下正常工作,但让我们讨论一下您的实现。

  • FileUploadDao是DAO还是服务?
  • FileUploadImpl似乎使@Service@Repository混淆, 也许读出来可能对您有帮助。 Spring Data RepositoriesSpring Service Annotation
  • 您已经制定了一种事务性方法save,在其中我无法说出您想要实现的目标。您还同时自动装配了FileUploadDaoSessionFactory,尽管您想实现方法的第一个和内部方法,但都试图通过首先在存储库上调用save来两次持久化对象(即StackOverflowError首先是您,但您很幸运,因为Spring知道如何自动连线),然后您尝试再次调用Hibernate的SessionFactory进行保存,这破坏了抽象的JPA契约。另外,如果您注意到了,则您发布的日志中的错误来自第二次保存。
  • @Transactional不会讨论这是如何工作的,因为您尚未发布整个应用程序配置。但同样,您可以阅读this了解更多信息。

因此,基于您共享的示例,我将准备2个案例,这些案例可能有助于您了解底层情况。

  1. 第一种情况,Spring DATA,并不真正在乎其下面的Hibernate或其他JPA提供程序。

您的FileUploadImpl成为:FileUploadService

@Service
public class FileUploadService {

    @Autowired
    private FileUploadDao fileUploadDao;

    public FileUploadService() {
    }

    @Transactional
    public void save(UploadFile uploadFile) {
        fileUploadDao.save(uploadFile);
    }

}

在控制器内部,您正在自动装配服务(层),而不是自动装配库/ DAO(层)。没有什么可以阻止您的了,这只是设计问题(如果您仍然不明白这一点,请提出另一个问题)。

部分控制器的一部分

    @Autowired
    private FileUploadService fileUploadService;


    @RequestMapping(value = "publish4" ,method = RequestMethod.POST)
    public ModelAndView publish4(@Valid @ModelAttribute("fourthPublicationForm") final FourthPublicationForm form, final BindingResult errors,
                             @RequestParam("type") String type, @RequestParam("operation") String operation , @RequestParam CommonsMultipartFile[] fileUpload) {
       .........
       fileUploadService.save(uploadFile);   
}
  1. 第二种情况,如果您真的想使用休眠功能,则没有任何理由自动装配存储库,而只需自己实现这些调用即可。
import org.springframework.stereotype.Component;


@Component
public class FileUploadDao {

    @Autowired
    private SessionFactory sessionFactory;

    public FileUpload save(FileUpload obj) {
        return sessionFactory.getCurrentSession().save(obj);
    }

    public FileUpload merge(FileUpload obj) {
        return sessionFactory.getCurrentSession().merge(obj);
    }

    ..... delete / update / or custom queries(SQL/JPQL/HQL) can be placed here

}

Your service simply exposes those methods , check the difference , i am applying the @Transactional annotation on this layer(ofc again you can put it in the DAO layer, but as i said its a matter of design).

@Transactional

您的控制器保持不变,这就是您需要分层的实际原因。