提问者:小点点

Spring Boot WebSocket Stomp JPA:即使使用@Transactional注释也没有插入数据


我有一个RestController,其中包含两个方法:

  1. 方法beat1带有@MessageMaps注释以从客户端接收websocket消息(在STOMP协议中)
  2. 方法beat2带有@Request estMaps注释以接收来自客户端的HTTP请求

这两个方法里面有相同的代码:

@RestController
@RequestMapping("/api/member")
@MessageMapping("member")
public class MemberCtrl
{
  @MessageMapping("beat")
  public Heartbeat beat1(@Payload Heartbeat heartbeat)
  {
    return memberService.beat(heartbeat);
  }

  @RequestMapping(value = "/beat", method = RequestMethod.POST)
  public Heartbeat beat2(@RequestBody Heartbeat heartbeat)
  {
    return memberService.beat(heartbeat);
  }
}

memberService只是一个普通的Spring服务,它包含将使用SpringJPARepository进行数据库数据插入的业务逻辑:

@Service
public class MemberServiceImpl implements MemberService, UserDetailsService
{

    @Autowired
    private HeartbeatRepository heartbeatRepository;

    @Transactional
    @Override
    public Heartbeat beat(Heartbeat heartbeat)
    {
        heartbeat = heartbeatRepository.save(heartbeat);
        return heartbeat;
    }
}

至于我的HeartbeatRepository的代码:

@Repository
public interface HeatbeatRepository extends JpaRepository<Heartbeat, Integer>
{

}

我的问题是:

>

  • 当我使用websocket发送STOMP消息时,控制器中的beat1方法会执行,但是没有数据插入DB表中。

    当我发送超文本传输协议请求时,执行控制器中的beat2方法,并成功地将Heartbeat域对象插入DB表中。

    我正在实现websocket,所以我需要的是让beat1工作,我实际上根本不需要beat2。(beat2只是为了测试)

    由于beat1beat2方法都在memberService中调用相同的Service方法,并且beat2有效,我认为我的MemberServiceHeartbeatRepository的实现没有问题。

    对于beat1beat2中的每一个的Hibernate日志,

    >

  • baat1只打印获取next id的SQL,没有看到插入和事务提交的SQL:

    2016-08-23 18:32:56.227 DEBUG 43874 --- [nboundChannel-4] org.hibernate.SQL                        : select nextval ('heartbeat_id_seq')
    2016-08-23 18:32:56.227 DEBUG 43874 --- [nboundChannel-4] o.h.e.j.internal.LogicalConnectionImpl   : Obtaining JDBC connection
    2016-08-23 18:32:56.242 DEBUG 43874 --- [nboundChannel-4] o.h.e.j.internal.LogicalConnectionImpl   : Obtained JDBC connection
    2016-08-23 18:32:56.261 DEBUG 43874 --- [nboundChannel-4] org.hibernate.id.SequenceGenerator       : Sequence identifier generated: BasicHolder[java.lang.Integer[20]]
    2016-08-23 18:32:56.261 DEBUG 43874 --- [nboundChannel-4] o.h.e.i.AbstractSaveEventListener        : Generated identifier: 20, using strategy: org.hibernate.id.SequenceHiLoGenerator
    2016-08-23 18:32:56.266 DEBUG 43874 --- [nboundChannel-4] o.h.e.j.internal.LogicalConnectionImpl   : Releasing JDBC connection
    2016-08-23 18:32:56.266 DEBUG 43874 --- [nboundChannel-4] o.h.e.j.internal.LogicalConnectionImpl   : Released JDBC connection
    

    2.beat2打印完成的insetaionSQL并提交事务,这就是为什么它成功地插入DB表:

    2016-08-23 18:20:29.937 DEBUG 43846 --- [nio-8989-exec-9] o.h.e.t.spi.AbstractTransactionImpl      : begin
    2016-08-23 18:20:29.937 DEBUG 43846 --- [nio-8989-exec-9] o.h.e.j.internal.LogicalConnectionImpl   : Obtaining JDBC connection
    2016-08-23 18:20:29.951 DEBUG 43846 --- [nio-8989-exec-9] o.h.e.j.internal.LogicalConnectionImpl   : Obtained JDBC connection
    2016-08-23 18:20:29.951 DEBUG 43846 --- [nio-8989-exec-9] o.h.e.t.internal.jdbc.JdbcTransaction    : initial autocommit status: true
    2016-08-23 18:20:29.951 DEBUG 43846 --- [nio-8989-exec-9] o.h.e.t.internal.jdbc.JdbcTransaction    : disabling autocommit
    2016-08-23 18:20:29.966 DEBUG 43846 --- [nio-8989-exec-9] org.hibernate.SQL                        : select nextval ('heartbeat_id_seq')
    2016-08-23 18:20:29.986 DEBUG 43846 --- [nio-8989-exec-9] org.hibernate.id.SequenceGenerator       : Sequence identifier generated: BasicHolder[java.lang.Integer[19]]
    2016-08-23 18:20:29.986 DEBUG 43846 --- [nio-8989-exec-9] o.h.e.i.AbstractSaveEventListener        : Generated identifier: 19, using strategy: org.hibernate.id.SequenceHiLoGenerator
    2016-08-23 18:20:29.992 DEBUG 43846 --- [nio-8989-exec-9] o.h.e.t.spi.AbstractTransactionImpl      : committing
    2016-08-23 18:20:29.993 DEBUG 43846 --- [nio-8989-exec-9] o.h.e.i.AbstractFlushingEventListener    : Processing flush-time cascades
    2016-08-23 18:20:29.993 DEBUG 43846 --- [nio-8989-exec-9] o.h.e.i.AbstractFlushingEventListener    : Dirty checking collections
    2016-08-23 18:20:29.995 DEBUG 43846 --- [nio-8989-exec-9] o.h.e.i.AbstractFlushingEventListener    : Flushed: 1 insertions, 0 updates, 0 deletions to 1 objects
    2016-08-23 18:20:29.995 DEBUG 43846 --- [nio-8989-exec-9] o.h.e.i.AbstractFlushingEventListener    : Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
    2016-08-23 18:20:29.996 DEBUG 43846 --- [nio-8989-exec-9] o.hibernate.internal.util.EntityPrinter  : Listing entities:
    2016-08-23 18:20:29.998 DEBUG 43846 --- [nio-8989-exec-9] o.hibernate.internal.util.EntityPrinter  : com.yamk.api.domain.orm.Heartbeat{lifespanSec=0, lostedSec=0, lastHeartbeatTime=Tue Aug 23 18:19:35 UTC 2016, createdTime=Tue Aug 23 18:20:29 UTC 2016, location=POINT (121.56818389892578 25.033194472364688), id=19}
    2016-08-23 18:20:30.006 DEBUG 43846 --- [nio-8989-exec-9] org.hibernate.SQL                        : insert into heartbeat (created_time, last_heartbeat_time, lifespan_sec, location, losted_sec, id) values (?, ?, ?, ?, ?, ?)
    Hibernate: insert into heartbeat (created_time, last_heartbeat_time, lifespan_sec, location, losted_sec, id) values (?, ?, ?, ?, ?, ?)
    2016-08-23 18:20:30.088 DEBUG 43846 --- [nio-8989-exec-9] o.h.e.t.internal.jdbc.JdbcTransaction    : committed JDBC Connection
    2016-08-23 18:20:30.088 DEBUG 43846 --- [nio-8989-exec-9] o.h.e.t.internal.jdbc.JdbcTransaction    : re-enabling autocommit
    2016-08-23 18:20:30.091 DEBUG 43846 --- [nio-8989-exec-9] m.m.a.RequestResponseBodyMethodProcessor : Written [com.yamk.api.domain.orm.Heartbeat@32] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@69f8302c]
    2016-08-23 18:20:30.091 DEBUG 43846 --- [nio-8989-exec-9] o.s.web.servlet.DispatcherServlet        : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
    2016-08-23 18:20:30.091 DEBUG 43846 --- [nio-8989-exec-9] o.h.e.jdbc.internal.JdbcCoordinatorImpl  : HHH000420: Closing un-released batch
    2016-08-23 18:20:30.091 DEBUG 43846 --- [nio-8989-exec-9] o.h.e.j.internal.LogicalConnectionImpl   : Releasing JDBC connection
    2016-08-23 18:20:30.091 DEBUG 43846 --- [nio-8989-exec-9] o.h.e.j.internal.LogicalConnectionImpl   : Released JDBC connection
    

    那么,我的代码有什么问题导致beat1(WebSocket)和beat2(HTTP请求)出现如此不同的结果呢?

    似乎Spring不会自动给我一个事务,即使在调用MessageMaps方法beat1时使用了@Transactional注释,这很奇怪。


  • 共1个答案

    匿名用户

    最后我自己找到了解决方案。原来我必须使用@Bean并使用JpaTransactionManager作为实现手动配置PlatformTransactionManager

        @ComponentScan
        @Configuration
        @EnableSwagger2
        @EnableCaching
        @EnableJpaRepositories
        @EnableTransactionManagement
        @EnableJpaAuditing
        @SpringBootApplication
        public class App
        {
          public static void main(String[] args)
          {
              SpringApplication.run(App.class, args);
          }
    
          @Autowired
          private EntityManagerFactory entityManagerFactory;
    
          @Bean
          public PlatformTransactionManager transactionManager() 
          {
            return new JpaTransactionManager(entityManagerFactory);
          }
    
        }
    

    就这样,然后一切正常。

    但是我仍然不明白为什么Spring Boot没有使用我的application. Properties ites文件自动配置PlatformTransactionManager。也许我误解了application.properties ites中的某些内容或遗漏了某些内容,下面是我的applicaion.properties的样子:

        # data source
        spring.datasource.driver-class-name=org.postgresql.Driver
        spring.datasource.url=jdbc:postgresql://xxx.xxx.xxx.xxxx:####/xxxx
        spring.datasource.username=my-user-name
        spring.datasource.password=my-password
        spring.datasource.validationQuery=SELECT 1
        spring.datasource.test-on-borrow=true
    
        # jpa / hibernate
        spring.jpa.hibernate.ddl-auto:validate
        spring.jpa.show-sql:true
        spring.jpa.properties.hibernate.dialect = org.hibernate.spatial.dialect.postgis.PostgisDialect
        spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
        logging.level.org.hibernate=DEBUG