java - Spring Boot Async ResultSet 已关闭

标签 java spring spring-boot asynchronous

我正在使用 Spring Boot 实现通知并使用 @Async 通知不同线程中的用户.
没有这个注释,一切正常,但是当我把它放在我用来通知的方法上时,只有一个可观察的实体,观察者不会得到通知,我得到了这个堆栈跟踪:

Unexpected exception occurred invoking async method: public void pt.ulisboa.tecnico.socialsoftware.tutor.notifications.NotificationServic
e.notifyObservers(package.notifications.Observable,package.notifications.domain.Notification,ppackage.user.User)                                
                                                                                                                                                                                                                                               
org.hibernate.exception.GenericJDBCException: could not initialize a collection: [package.course.CourseExecution.users#11]
        at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
        at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
        at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:97) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
        at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:707) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
        at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:76) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
        at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:108) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]                                                                          at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:2145) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
        at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:589) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
        at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:264) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
        at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
        at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
        at org.hibernate.collection.internal.PersistentSet.toString(PersistentSet.java:327) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]
        at java.base/java.lang.String.valueOf(String.java:2951) ~[na:na]
        at java.base/java.io.PrintStream.println(PrintStream.java:897) ~[na:na]
        at package.course.CourseExecution.Notify(CourseExecution.java:210) ~[classes/:na]
        at package.notifications.NotificationService.notifyObservers(NotificationService.java:82) ~[classes/:na]
        at package.notifications.NotificationService$$FastClassBySpringCGLIB$$d43e740c.invoke(<generated>) ~[classes/:na]
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769) ~[spring-aop-5.2.2.RELEASE.jar:5.2.2.RELEASE]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.2.RELEASE.jar:5.2.2.RELEASE]                                                                             
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747) ~[spring-aop-5.2.2.RELEASE.jar:5.2.2.RELEASE]                                                                                 
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:366) ~[spring-tx-5.2.2.RELEASE.jar:5.2.2.RELEASE]                                                        
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99) ~[spring-tx-5.2.2.RELEASE.jar:5.2.2.RELEASE]                                                                              
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.2.RELEASE.jar:5.2.2.RELEASE]                                                                             
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747) ~[spring-aop-5.2.2.RELEASE.jar:5.2.2.RELEASE]                                                                                         at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:115) ~[spring-aop-5.2.2.RELEASE.jar:5.2.2.RELEASE]                                               
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]                                                                                                                                                         
        at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]                                                                                                                                                                            
Caused by: org.postgresql.util.PSQLException: This statement has been closed.                                                                                                                                                                  
        at org.postgresql.jdbc.PgStatement.checkClosed(PgStatement.java:705) ~[postgresql-42.2.8.jar:42.2.8]                                                                                                                                   
        at org.postgresql.jdbc.PgPreparedStatement.setInt(PgPreparedStatement.java:270) ~[postgresql-42.2.8.jar:42.2.8]                                                                                                                        
        at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.setInt(HikariProxyPreparedStatement.java) ~[HikariCP-3.4.1.jar:na]                                                                                                              
        at org.hibernate.type.descriptor.sql.IntegerTypeDescriptor$1.doBind(IntegerTypeDescriptor.java:46) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]                                                                                               at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:73) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]                                                                                                                       at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:276) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]                                                                                                  at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:271) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]                                                                                                  at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.bindPositionalParameters(AbstractLoadPlanBasedLoader.java:320) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]                                                    
        at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.bindParameterValues(AbstractLoadPlanBasedLoader.java:291) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]                                                         
        at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.prepareQueryStatement(AbstractLoadPlanBasedLoader.java:210) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]                                                       
        at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeQueryStatement(AbstractLoadPlanBasedLoader.java:162) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]                                                       
        at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:104) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]                                                                 
        at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:87) ~[hibernate-core-5.4.9.Final.jar:5.4.9.Final]                                        
        ... 25 common frames omitted
Caused by异常消息总是相同的,另一个,并不总是
跟踪中提到的方法是:
  • 通知程序(异步方法)
  •     @Async("notifyExecutor") // Even with the default executor, the error occurs
        @Retryable(
                value = { SQLException.class },
                backoff = @Backoff(delay = 5000))
        @Transactional(isolation = Isolation.REPEATABLE_READ)
        public void notifyObservers(Observable observable, Notification notification, User exclude) {
            observable.Notify(notification, exclude);
        }
    
  • 调用通知程序的方法(需要的服务是 @Autowired )
  •     @Retryable(value = { SQLException.class }, backoff = @Backoff(delay = 5000))
        @Transactional(isolation = Isolation.REPEATABLE_READ)
        public AnnouncementDto createAnnouncement(AnnouncementDto announcementDto) {
    
            checkIfConsistentAnnouncement(announcementDto);
    
            User user = getTeacher(announcementDto.getUserId());
    
            CourseExecution courseExecution = getCourseExecution(announcementDto.getCourseExecutionId());
    
            if (announcementDto.getCreationDate() == null) {
                announcementDto
                        .setCreationDate(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")));
            }
    
            // Announcement has a CourseExecution as attribute
            Announcement announcement = new Announcement(user, courseExecution, announcementDto);
            entityManager.persist(announcement);
    
            NotificationDto notification = NotificationsCreation.create(ADD_ANNOUNCEMENT_TITLE,
                    List.of(announcement.getUser().getName()), ADD_ANNOUNCEMENT_CONTENT,
                    List.of(announcement.getTitle(), user.getName()), Notification.Type.ANNOUNCEMENT);
    
            this.notify(courseExecution, notification, user);
    
            return new AnnouncementDto(announcement);
        }
    
        // Calls the Async method
        private void notify(CourseExecution course, NotificationDto notification, User user) {
            notificationService.notifyObservers(course, notificationService.createNotification(notification), user);
        }
    
  • 发生错误的方法(仅在访问元素时)
  •     @Override
        public void Notify(Notification notification, User user) {
            for (Observer observer : this.users) { // Error occurs here, doesn't get inside the loop
                if (((User) observer).getId() == user.getId()) {
                    continue;
                }
    
                observer.update(this, notification);
            }
        }
    
    我已经看到了这些答案,但它们不适用于这里。我认为非常奇怪的是,这只发生在 Announcement 上。而不是与其他可观察对象。因为我想要所有观察者的公告CourseExecution , 我做了 CourseExecution observable,当有新公告时,我们会通知所有 CourseExecution观察员。
    有人能帮助我吗?

    最佳答案

    我敢打赌这是数据库连接和异步的问题。数据库连接保存在本地线程中,异步方法不会在同一线程中执行,并且由于并行执行的潜力无法真正共享相同的连接/事务。您是否尝试过传播需要新的异步方法?
    更有经验的成员可能能够澄清异步和未完成数据库连接的交互,但这可能是罪魁祸首。

    关于java - Spring Boot Async ResultSet 已关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62560368/

    相关文章:

    java - 我如何确定使用 Spring Security 访问 URL 需要哪些角色?

    java - org.springframework.beans.factory.UnsatisfiedDependencyException : 问题

    java - 如果多个用户同时处理它,使用单例模式是否会使我的应用程序变慢

    java - 在Spring Boot中的JPA查询中使用规范

    java - 使用相同的键添加多个值到映射?

    Java - 如果要发送的文件不是普通文本文件,则通过套接字发送的文件为空

    java - @Transactional 不打开 Hibernate 事务

    java - 如何在格式化的 xpath 中使用撇号?

    java - 在 super 调用Java中调用父的内部类

    spring - 无法执行CommandLineRunner-Spring Batch