Spring Transactional方法无法正常工作(无法保存数据库)

时间:2019-01-15 12:11:30

标签: spring-boot jpa transactional

我日复一日地试图为我的事务性方法找到解决方案。逻辑是这样的: 控制器接收请求,调用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(消费者)

@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)

}

使用此代码,它不会在DB上保存新的卡状态,但是Game,Terminal和Room在DB上可以保存(或多或少...)。如果删除了assignService,CardService会将新状态正确保存在数据库中。

我尝试手动刷新,使用回购保存等等...但是结果几乎相同。有人可以帮我吗?

1 个答案:

答案 0 :(得分:0)

我认为我找到了一个解决方案(可能不是最佳解决方案),但它与我的程序的逻辑关系更大。

主要问题之一是卡状态属性的更新,因为它没有反映在实体对象上。调用assignOrder方法时,它收到了 old 卡值,因为无法在Threads / Transactions中共享信息(据我所知)。这在事务内是正常的,因为em.executeUpdate()仅提交数据库,所以如果我要获取更新的实体,则需要使用em.refresh(Entity)刷新它,但这会导致性能下降。

最后,我更改了逻辑:首先创建订单(交易),然后将卡片分配给订单(交易)。这种方式可以正常工作。