Container Managed Transactions can not rollback

2019-04-12 22:54发布

I am playing arround with transactions.

I configured JPA to handle my Entitys, and want to persist them in the database. The problem is, CMT will not rollback, when my program throws an runtimeException.

The idea behind this "container thing" is so hard to understand and so poorly documented.

@transactional managed transactions, pure CDI Interceptor managed transactions and Bean Managed transactions are working like a charm.

Here is what I coded: This is a simple "Cinema-Demonstration". you want to see two Movies with X seats. The Seats are limited. If there are not enough seats in Films, there should not be a Transaction (ACID and stuff)


in my buyTicketsBoundary class:

at first I tell my class we are using CMT:

@Named("buchungBoundry")
@RequestScoped
@TransactionManagement(TransactionManagementType.CONTAINER)
public class BuchungBoundry {

@EJB
private BuchungVerwaltung buyTicketsController;
@EJB
private KundenVerwaltung customerController;
@EJB
private SaalVerwaltung roomController;
@EJB
private MovieVerwaltung movieController;



private int ticketsForMovie1; //this is how many tickets we want to buy
private int ticketsForMovie2;

public BuchungBoundry() {
}

@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void buyTickets() throws MyException {


    int numberOfSeantsInRoom1=roomController.getSaal(4).getAnzahlPlaetze();
    int numberOfSeantsInRoom2=roomController.getSaal(5).getAnzahlPlaetze();

    int alreadyBoughtSeatsIn1=buyTicketsController.getBelegtePlatzeNachSaal(4);
    int alreadyBoughtSeatsIn2=buyTicketsController.getBelegtePlatzeNachSaal(5);

    int availableSeats1 = numberOfSeantsInRoom1 - alreadyBoughtSeatsIn1;
    int availableSeats2 = numberOfSeantsInRoom2 - alreadyBoughtSeatsIn2;


    System.out.println("Saal A: ("+alreadyBoughtSeatsIn1+"/"+numberOfSeantsInRoom1+") want to buy :" + ticketsForMovie1);
    System.out.println("Saal B: ("+alreadyBoughtSeatsIn2+"/"+numberOfSeantsInRoom2+") want to buy :" + ticketsForMovie2);

    try {
        if (ticketsForMovie1 <= availableSeats1) {
        buyTicketsController.erstelleBuchung(customerController.getKunde(1),
                movieController.getMovie(7),
                roomController.getSaal(4),
                ticketsForMovie1);
        } else {
            throw new MyException("ERROR: no room for "
                    + ticketsForMovie1 + " person! "
                    +alreadyBoughtSeatsIn1);
        }
        if (ticketsForMovie2 <= availableSeats2) {
            buyTicketsController.erstelleBuchung(customerController.getKunde(1),
                    movieController.getMovie(8),
                    roomController.getSaal(5),
                    ticketsForMovie2);
        } else {
            throw new MyException("ERROR: no room for "
                    + ticketsForMovie2 + " person! "
                    +alreadyBoughtSeatsIn2);
        }

    } catch (MyException | IllegalStateException | SecurityException ex) {
        Logger.getLogger(BuchungBoundry.class.getName()).log(Level.SEVERE, null, ex);
    }
}

My Exception:

@ApplicationException(rollback=true)
public class MyException extends RuntimeException{
    public MyException()  {

    }

    public MyException(String s) {
        System.out.println(""+s);
    }
}

The Controller class which is writing the Bought tickets in the Database via JPA:

@Stateless
public class BuchungVerwaltung implements Serializable {

@PersistenceContext(unitName = "kbse-JTA")
private EntityManager em;

public BuchungVerwaltung() {
}

public void erstelleBuchung(Kunde k, Movie movie, Saal saal, int anzahlPlaetze) {
    Buchung b = new Buchung(k, movie, saal, anzahlPlaetze);
    em.persist(b);
}

public int getBelegtePlatzeNachSaal(int id) {
    try {
        Query query = em.createNativeQuery("select sum(b.ANZAHL) from SAAL s,BUCHUNG b where s.SAAL_ID = b.SAAL_SAAL_ID and s.SAAL_ID=?");
        query.setParameter(1, id);
        return (int) query.getSingleResult();
    } catch (Exception e) {
        return 0;
    }
}

public List<Buchung> getAlleBuchungen() {
    TypedQuery<Buchung> query = em.createQuery("select s from Buchung s", Buchung.class);
    return query.getResultList();
}
}

the problem is, when this class reaches the em.persist state for the first movie, and the second movie throws an exception, the database can not rollback.

I thought if a RuntimeException was thrown, the Container would rollback

What can I to to make it work?

Plase tell me if something is not clear

1条回答
男人必须洒脱
2楼-- · 2019-04-12 23:35

I did everything corectly, the only error was to catch "myException"

} catch (MyException | IllegalStateException | SecurityException ex) {

} catch ( IllegalStateException | SecurityException ex) {

It woroks now and the container can rollback like it should

查看更多
登录 后发表回答