首页 > 解决方案 > Spring Boot JPA 数据:服务层方法没有正在进行的事务异常

问题描述

@Lock(LockModeType.PESSIMISTIC_WRITE)问题是我无法使用注释的服务层方法来处理简单的项目 @Transactional。我需要在锁定的实体/数据库行上运行业务逻辑。当我运行应用程序时,它会在会话层引发错误

org.springframework.dao.InvalidDataAccessApiUsageException: no transaction is in progress; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress

Main class

@SpringBootApplication
@EnableConfigurationProperties
@ConfigurationPropertiesScan
@RequiredArgsConstructor
@Slf4j
@EnableTransactionManagement
public class BackendApplication {

    private final BackendConfiguration configuration;

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

}

SessionService

@Service
@RequiredArgsConstructor
@Slf4j
public class SessionService {

    final private SessionRepository sessionRepository;

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
    Session readAndUpdateSession(String sessionId, Function<Session, Session> sessionPreUpdateHandler, String threadName) {
        Optional<SessionEntity> forUpdate = sessionRepository.getBySessionId(sessionId);
        Session session = new Session(forUpdate.map(SessionEntity::getSessionId).orElse(null), false);

        Session updatedSession = sessionPreUpdateHandler.apply(session);

        sessionRepository.save(forUpdate.orElse(null));

        log.info(" thread [{}] updated session", threadName);

        return updatedSession;
    }
}

SessionRepository

@Repository
public interface SessionRepository extends JpaRepository<SessionEntity, String> {

    @Lock(LockModeType.PESSIMISTIC_WRITE)
    Optional<SessionEntity> getBySessionId(String id);

}

CommandLineRunner测试

@Component
@RequiredArgsConstructor
@Slf4j
public class CommandLineRunner implements org.springframework.boot.CommandLineRunner {

    private final SessionRepository sessionRepository;
    private final ApplicationContext applicationContext;

    @Override
    public void run(String... args) throws Exception {
        sessionRepository.save(new SessionEntity().setSessionId("7d010e0a-cf6e-492c-9db4-690a96b4e345"));

        log.info("" + sessionRepository.findForUpdate("7d010e0a-cf6e-492c-9db4-690a96b4e345").orElse(null));

        new Thread(() -> applicationContext.getBean(SessionService.class).readAndUpdateSession("7d010e0a-cf6e-492c-9db4-690a96b4e345", session -> {

            log.info("first thread reading and updating doing business ");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("first thread return session back ");
            return session;
        }, "first")).start();

        new Thread(() -> applicationContext.getBean(SessionService.class).readAndUpdateSession("7d010e0a-cf6e-492c-9db4-690a96b4e345", session -> {

            log.info("second thread reading and updating but first is not accomplished");

            log.info("second thread return session back ");
            return session;

        }, "second")).start();

    }
}

最后但并非最不重要application.yml

spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/backend
    hikari:
      username: backend
      password: backend
      driver-class-name: org.postgresql.Driver
      connection-timeout: 1000
      connection-test-query: SELECT 1
      maximum-pool-size: 32
    sql-script-encoding: UTF-8
  cache:
    type: jcache
  jpa:
    generate-ddl: false
    database-platform: org.hibernate.dialect.PostgreSQLDialect

我在互联网上应用了建议,但没有弄清楚如何解决这个问题,

标签: javahibernatejpaspring-transactions

解决方案


推荐阅读