错误 500:org.hibernate.HibernateException:找不到当前线程的会话
Error 500: org.hibernate.HibernateException: No Session found for current thread
我尝试在我的项目中上传图片时遇到此错误。该项目执行正常,直到它必须有效地将图片上传到数据库(我使用的是 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)
我看到其他问题的答案是没有使用 "transactional"。我在这里使用该注释,但我不确定它的方式是否 100% 正确。
正如您一开始所说的,您混淆了实际的图层。你仍然可以让它在你的情况下正常工作,但让我们讨论一下你的实现。
FileUploadDao
是 DAO 还是服务?
FileUploadImpl
似乎您将 @Service
与 @Repository
混淆了,
也许阅读这篇文章可能会对你有所帮助。 Spring Data Repositories , Spring Service Annotation
- 您已经创建了一个交易方法,
save
我无法准确地说出您想要实现的目标。您还自动装配了 FileUploadDao
和 SessionFactory
,尽管您想要实现第一个方法,并且在方法内部您尝试通过首先在存储库上调用 save
来持久化对象两次(那是WhosebugError
从一开始,但你很幸运,因为 Spring 知道自动装配什么)然后你试图在 Hibernate 的 SessionFactory 上第二次调用 save ,这打破了抽象的 JPA 契约。另外,如果您注意到,您发布的日志中的错误来自第二次保存。
@Transactional
不打算讨论它是如何工作的,因为您还没有发布整个应用程序配置。但同样,您可以阅读 this 了解更多信息。
因此,根据您分享的示例,我将准备 2 个案例,这可能会帮助您了解背后发生的事情。
- 第一个案例,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);
}
}
在您的控制器内部,您正在自动装配服务(层),而不是直接 Repository/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);
}
- 第二种情况,如果你真的想使用 hibernate 好东西,那么没有任何理由自动装配存储库,只需自己实现这些调用即可。
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
}</pre>
<p>你的服务只是公开了那些方法,检查差异,我在这个层上应用了 <code>@Transactional
注释(你可以再次将它放在 DAO 层中,但正如我所说,这是一个设计问题).
@Service
public class FileUploadService {
@Autowired
private FileUploadDao fileUploadDao;
public FileUploadService() {
}
@Transactional
public UploadFile save(UploadFile uploadFile) {
fileUploadDao.save(uploadFile);
}
@Transactional
public UploadFile merge(UploadFile uploadFile) {
fileUploadDao.merge(uploadFile);
}
....rest of the methods you want to expose , or combinations of mulitple DAOs
}
您的控制器保持不变,这就是您需要层的实际原因。
首先从 FileUploadDAOImpl
中删除 @Transactional
。
相应地更改基础包,
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
class、
上存在以下注释
@Configuration
@ComponentScan({"ar.edu.itba.paw"})
@EnableTransactionManagement(mode = AdviceMode.PROXY)
public class WebConfig {
// code
}
我尝试在我的项目中上传图片时遇到此错误。该项目执行正常,直到它必须有效地将图片上传到数据库(我使用的是 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)
我看到其他问题的答案是没有使用 "transactional"。我在这里使用该注释,但我不确定它的方式是否 100% 正确。
正如您一开始所说的,您混淆了实际的图层。你仍然可以让它在你的情况下正常工作,但让我们讨论一下你的实现。
FileUploadDao
是 DAO 还是服务?FileUploadImpl
似乎您将@Service
与@Repository
混淆了, 也许阅读这篇文章可能会对你有所帮助。 Spring Data Repositories , Spring Service Annotation- 您已经创建了一个交易方法,
save
我无法准确地说出您想要实现的目标。您还自动装配了FileUploadDao
和SessionFactory
,尽管您想要实现第一个方法,并且在方法内部您尝试通过首先在存储库上调用save
来持久化对象两次(那是WhosebugError
从一开始,但你很幸运,因为 Spring 知道自动装配什么)然后你试图在 Hibernate 的 SessionFactory 上第二次调用 save ,这打破了抽象的 JPA 契约。另外,如果您注意到,您发布的日志中的错误来自第二次保存。 @Transactional
不打算讨论它是如何工作的,因为您还没有发布整个应用程序配置。但同样,您可以阅读 this 了解更多信息。
因此,根据您分享的示例,我将准备 2 个案例,这可能会帮助您了解背后发生的事情。
- 第一个案例,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);
}
}
在您的控制器内部,您正在自动装配服务(层),而不是直接 Repository/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);
}
- 第二种情况,如果你真的想使用 hibernate 好东西,那么没有任何理由自动装配存储库,只需自己实现这些调用即可。
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 }</pre> <p>你的服务只是公开了那些方法,检查差异,我在这个层上应用了 <code>@Transactional
注释(你可以再次将它放在 DAO 层中,但正如我所说,这是一个设计问题).@Service public class FileUploadService { @Autowired private FileUploadDao fileUploadDao; public FileUploadService() { } @Transactional public UploadFile save(UploadFile uploadFile) { fileUploadDao.save(uploadFile); } @Transactional public UploadFile merge(UploadFile uploadFile) { fileUploadDao.merge(uploadFile); } ....rest of the methods you want to expose , or combinations of mulitple DAOs }您的控制器保持不变,这就是您需要层的实际原因。
首先从 FileUploadDAOImpl
中删除 @Transactional
。
相应地更改基础包,
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
class、
@Configuration
@ComponentScan({"ar.edu.itba.paw"})
@EnableTransactionManagement(mode = AdviceMode.PROXY)
public class WebConfig {
// code
}