2
votes

I have a PSU entity:

@Entity
public class Psu extends PanacheEntityBase {
    @Id
    @GeneratedValue
    public UUID uuid;

    @Column(nullable = false, length = 50)
    public String username;
    public Integer coins;
    public String firebaseRegistrationToken;

    public void setCoins(int coins){
        this.coins = coins;
    }

    public int getCoins(){
        return coins;
    }

    public static Psu findByUsername(String username){
        return find("username", username).firstResult();
    }
} 

And a function in my PsuService class:

@Transactional
public Transaction changeBalance(Transaction transaction){
    Psu psuSender = Psu.findById(transaction.senderId);
    psuSender.coins = psuSender.coins - transaction.amount;
    Psu.persist(psuSender);

    transaction.status = TransactionStatus.PROCESSED;

    return transaction;
}

When I log, after the function call, all users and their amount of coins it shows that the coins are updated for the right person:

List<Psu> allPsu = Psu.findAll().list();
for(Psu psu : allPsu){
    System.out.println("ID: " + psu.uuid + " coins: " + psu.coins);
}

When I retrieve the balance of the updated user via the API:

@GET
@Path("psu/getBalance/{uuid}")
@Produces(MediaType.APPLICATION_JSON)
public String getBalanceById(@PathParam("uuid") UUID uuid) {
    List<Psu> allPsu = Psu.findAll().list();
    for(Psu psu : allPsu){
        System.out.println("ID: " + psu.uuid + " coins: " + psu.coins);
    }

    return gson.toJson(psuService.getBalanceById(uuid));
}

Using this method in the PsuService class:

@Transactional
public int getBalanceById(UUID uuid){
    Psu psu = Psu.findById(uuid);
    return psu.getCoins();
}

Then it returns the old balance which is not updated.

Does anyone know why I can't update the balance?

  • PsuService extends PanacheEntityBase
  • PsuService is @ApplicationScoped

EDIT When doing an update with:

Psu.update("coins = ?1 where id= ?2", 10, transaction.senderId);

I receive the error:

ERROR [io.qua.sch.run.SimpleScheduler] (executor-thread-1) Error occured while executing task for trigger IntervalTrigger [id=1_com.msp.sqs.MessageQueue_ScheduledInvoker_receiveMessages_e721e20dd5fdaa8a94c141
a7768b0311d6f32352, interval=1000]: javax.persistence.TransactionRequiredException: Executing an update/delete query
3
I've experienced the same. My understanding is that the new entity state hasn't been written to the database yet and the second findById() call reads the old state back from the database. However, I also think that Hibernate should detect this and return the updated entity from the memory cache. The workaround is to call psuSender.flush() (instead of Psu.persist(psuSender)). persist() only make sense when an entity is created, not when it is updated. - Codo
The flush should happens automatically when the transaction is committed. In this case an explicit flush shouldn't be necessary. About the error with the query, it tells you what the problem is: there is not transaction and you need to be inside a transaction to run it. - Davide
Regarding the error: You should be inside a transaction if you are within a method that is marked @Transactional. Where is your update code? - Codo

3 Answers

0
votes

I think it's not updated because you are using persist with an existing entity. Because the entity is managed and exists, you can change the code this way:

@Transactional
public Transaction changeBalance(Transaction transaction){
    Psu psuSender = Psu.findById(transaction.senderId);
    psuSender.coins = psuSender.coins - transaction.amount;
    // Psu.persist(psuSender); <-- Remove this

    transaction.status = TransactionStatus.PROCESSED;
    return transaction;
}

Changes will be propagated to the database when the transaction is committed because the entity is in a managed state.

0
votes

I think instead of writing

Psu.persist(psuSender);

You should write

psuSender.persist();
0
votes

While writing the code I accidentally deleted @Inject...

However, Quarkus didn't gave me any error or something.

After Injecting the psuService class everything worked fine.