Spring Transactional метод не работает должным образом (не сохраняет БД) - PullRequest
0 голосов
/ 15 января 2019

Я провел день за днем, пытаясь найти решение моей проблемы с помощью транзакционных методов. Логика такая: Контроллер получает запрос, вызывает queueService, помещает его в PriorityBlockingQueue, а другой поток обрабатывает данные (поиск карт, обновление статуса, назначение текущей игре, возврат данных)

Контроллер:

@RequestMapping("/queue")
public DeferredResult<List<Card>> queueRequest(@Params...){
queueService.put(result, size, terminal, time) 
result.onCompletion(() ->  assignmentService.assignCards(result, game,room, cliente));
}

QueueService:

@Service
public class QueueService {
 private BlockingQueue<RequestQueue> queue = new PriorityBlockingQueue<>();

 @Autowired
 GameRepository gameRepository;
 @Autowired
 TerminalRepository terminalRepository;
 @Autowired
 RoomRpository roomRepository;

 private long requestId = 0;

 public void put(DeferredResult<List<Card>> result, int size, String client, LocalDateTime time_order){

        requestId++;

        --ommited code(find Entity: game, terminal, room)

        try {
            RequestQueue request= new RequestCola(requestId, size, terminal,time_order, result);
            queue.put(request);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        }
    }

CardService:

@Transactional
public class CardService {

@Autowired
EntityManager em;
@Autowired
CardRepository cardRepository;
@Autowired
AsignService asignacionService;

public List<Cards> processRequest(int size, BigDecimal value)
{

    List<Card> carton_query = em.createNativeQuery("{call cards_available(?,?,?)}",
            Card.class)           
            .setParameter(1, false)
            .setParameter(2, value)
            .setParameter(3, size).getResultList();

    List<String> ids = new ArrayList<String>();
    carton_query.forEach(action -> ids.add(action.getId_card()));
    String update_query = "UPDATE card SET available=true WHERE id_card IN :ids";
    em.createNativeQuery(update_query).setParameter("ids", ids).executeUpdate();

    return card_query;
}

QueueExecutor (Consumer)

@Component
public class QueueExecute {

@Autowired
QueueService queueRequest;
@Autowired
AsignService asignService;
@Autowired
CardService cardService;

@PostConstruct
public void init(){
    new Thread(this::execute).start();
}

private void execute(){

    while (true){
        try {

            RequestQueue request;
            request = queueRequest.take();

            if(request != null) {
                List<Card> cards = cardService.processRequest(request.getSize(), new BigDecimal("1.0"));
                request.getCards().setResult((ArrayList<Card>) cards);  
   } catch (InterruptedException e) {
            e.printStackTrace();
        }

}

AssignService:

@Transactional 
public void assignCards(DeferredResult<List<Card>> cards, Game game, Room room, Terminal terminal)
{

        game = em.merge(game);
        room = em.merge(room);
        terminal = em.merge(terminal);

        Order order = new Order();
        LocalDateTime datetime = LocalDateTime.now();
        BigDecimal total = new BigDecimal("0.0");
        order.setTime(datetime)
        order.setRoom(room);
        order.setGame(game);
        order.setId_terminal(terminal);

        for(Card card: (List<Card>)cards.getResult()) {
            card= em.merge(card)
        --> System.out.println("CARD STATUS" + card.getStatus());
// This shows the OLD value of the Card (not updated)
            card.setOrder(order); 
            order.getOrder().add(card); 

        }

        game.setOrder(order);
//gameRepository.save(game)

}

С помощью этого кода он не сохраняет новый статус карты в БД, но Game, Terminal и Room хорошо сохраняются в БД (более или менее ...). Если я удалю assignService, CardService правильно сохраняет новый статус в БД.

Я пытался сбросить вручную, сохранить с помощью репо и так далее ... но результат почти тот же. Кто-нибудь может мне помочь?

1 Ответ

0 голосов
/ 16 января 2019

Я думаю, что нашел решение (возможно, не оптимальное), но оно больше связано с логикой моей программы.

Одной из основных проблем было обновление свойства статуса карты, поскольку оно не отражалось на объекте сущности. Когда вызывается метод assignOrder, он получает значение old Card, потому что невозможно обмениваться информацией внутри Threads / Transactions (насколько я знаю). Это нормально для транзакций, потому что em.executeUpdate () фиксирует только базу данных, поэтому, если я хочу получить обновленную сущность, мне нужно обновить ее с помощью em.refresh (Entity), но это привело к снижению производительности.

В конце я изменил логику: сначала создайте Заказы (транзакционные), а затем назначьте карты для заказов (Транзакционные). Этот способ работает правильно.

...