我日复一日地试图为我的事务性方法找到解决方案。逻辑是这样的: 控制器接收请求,调用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会将新状态正确保存在数据库中。
我尝试手动刷新,使用回购保存等等...但是结果几乎相同。有人可以帮我吗?
答案 0 :(得分:0)
我认为我找到了一个解决方案(可能不是最佳解决方案),但它与我的程序的逻辑关系更大。
主要问题之一是卡状态属性的更新,因为它没有反映在实体对象上。调用assignOrder方法时,它收到了 old 卡值,因为无法在Threads / Transactions中共享信息(据我所知)。这在事务内是正常的,因为em.executeUpdate()仅提交数据库,所以如果我要获取更新的实体,则需要使用em.refresh(Entity)刷新它,但这会导致性能下降。
最后,我更改了逻辑:首先创建订单(交易),然后将卡片分配给订单(交易)。这种方式可以正常工作。