MySQL TransactionRequiredException

krgewb

Top Contributor
Bei uns kann ein Request sehr lange dauern, da mehr als 10.000 Datensätze in der Datenbank gespeichert werden müssen. Deshalb führe ich saveMyCanvasFlexview2b nicht direkt aus, sondern habe einen Timer programmiert.

Java:
@PostMapping(value = "/db/saveMyCanvasFlexview2")
public void saveMyCanvasFlexview2(@RequestBody MyCanvasFlexViewBean myCanvasFlexViewBean, HttpSession session) {
    service.saveMyCanvasFlexview2(myCanvasFlexViewBean, session);
}

Java:
@Override
@Transactional
public void saveMyCanvasFlexview2(MyCanvasFlexViewBean myCanvasFlexViewBean, HttpSession session) {

    String uuidForProgress = myCanvasFlexViewBean.getUuidForProgress();
    FlexViewProgressInfoDTO dto = new FlexViewProgressInfoDTO();
    DBRestController.mappingUuidAndFlexViewProgressInfoDTO.put(uuidForProgress, dto);

    Timer timer = new Timer();
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            cancel();
            saveMyCanvasFlexview2b(myCanvasFlexViewBean, dto, session);
        }
    }, 100);
}
Das Frontend fragt den Fortschritt kontinuierlich ab. Benutzer wird dadurch kontinuierlich über den Fortschritt des Speichervorgangs informiert.

Mit DB2 funktioniert das. Mit MariaDB hingegen funktioniert es nicht. Fehlermeldung:
Java:
Exception in thread "Timer-36" javax.persistence.TransactionRequiredException: Executing an update/delete query
    at org.hibernate.internal.AbstractSharedSessionContract.checkTransactionNeededForUpdateOperation(AbstractSharedSessionContract.java:422)
    at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1679)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$DeferredQueryInvocationHandler.invoke(SharedEntityManagerCreator.java:406)
    at com.sun.proxy.$Proxy226.executeUpdate(Unknown Source)
    at com.ametras.vision.backend.service.ApplicationService2Impl.deleteFlexViewB(ApplicationService2Impl.java:5568)
    at com.ametras.vision.backend.service.ApplicationService2Impl.saveMyCanvasFlexview2b(ApplicationService2Impl.java:5389)
    at com.ametras.vision.backend.service.ApplicationService2Impl$7.run(ApplicationService2Impl.java:5350)
    at java.base/java.util.TimerThread.mainLoop(Timer.java:556)
    at java.base/java.util.TimerThread.run(Timer.java:506)

In saveMyCanvasFlexview2b werden Daten zuerst alle Daten gelöscht und dann die gewünschten Daten gespeichert.
 

KonradN

Super-Moderator
Mitarbeiter
Zeig doch einmal die Methode im service - was machst Du da genau? Und wenn Du Repositories nutzt, dann könnten da die Details interessant sein.

Von der Fehlermeldung her ist es recht deutlich: Du hast keine Transaction gestartet und die wird benötigt.
Evtl. reicht auf der Service Methode ein einfaches @Transactional.
Oder wenn Du Methoden eines Repositories aufrufst, dann fehlt da ggf. ein @Modifying
Ggf. kann es auch sinnvoll sein, eine Transaction selbst zu starten

Java:
    EntityTransaction transaction = entityManager.getTransaction();
    try {
        transaction.begin();
        
        // Update Logic ...
        
        transaction.commit();
    } catch (Exception e) {
        transaction.rollback();
        throw e;
    }
 

krgewb

Top Contributor
Ich hatte mehrere Methoden. Die deleteFlexViewB() gibt es nicht mehr. Ich mache jetzt alles in der saveMyCanvasFlexview2b(). Die Exception fliegt anscheinend wegen folgender Zeile:
Java:
int countItems = q.executeUpdate();

Java:
    @Transactional
    public void saveMyCanvasFlexview2b(MyCanvasFlexViewBean myCanvasFlexViewBean, FlexViewProgressInfoDTO dto, HttpSession session) {

        logger.info("saveMyCanvasFlexview2b() called");

        long flexViewId;

        int numberOfItemsThatShallBeSaved = 0;
        for (MyScreenView screenView : myCanvasFlexViewBean.getScreens()) {
            if (screenView.getMagnetoTemplate() != null && screenView.getMagnetoTemplate().getStreamWidgets() != null) {
                numberOfItemsThatShallBeSaved += screenView.getMagnetoTemplate().getStreamWidgets().size();
            }
        }

        int numberOfLinesThatShallBeSaved = 0;
        for (MyScreenView screenView : myCanvasFlexViewBean.getScreens()) {
            if (screenView.getMagnetoTemplate() != null && screenView.getMagnetoTemplate().getLines() != null) {
                numberOfLinesThatShallBeSaved += screenView.getMagnetoTemplate().getLines().size();
            }
        }

        dto.setNumberOfPagesThatShallBeSaved823478(myCanvasFlexViewBean.getScreens().size());
        dto.setNumberOfItemsThatShallBeSaved234578(numberOfItemsThatShallBeSaved);
        dto.setNumberOfLinesThatShallBeSaved194334(numberOfLinesThatShallBeSaved);
        dto.setInitialized345456(true);

        flexViewId = Long.parseLong(myCanvasFlexViewBean.getId());

        logger.info("id of the flexView that shall be deleted: " + flexViewId);

        MyCanvasFlexViewBean flexViewBean = null;
        for (MyCanvasFlexViewBean canvasFlexViewBean : getSavedFlexviews()) {
            if (canvasFlexViewBean.getId().equals("" + flexViewId)) {
                flexViewBean = canvasFlexViewBean;
                break;
            }
        }
        if (flexViewBean == null) {
            logger.warn("flexViewBean is null");
            return;
        }

        Query q = entityManager.createQuery("DELETE FROM CanvasFlexViewPageItemsEntity WHERE flexviewId = ?1");
        q.setParameter(1, flexViewId);
        int countItems = q.executeUpdate();
        logger.info("successfully deleted " + countItems + " entry/entries from CANVAS_FLEXVIEW_PAGE_ITEMS");

        if (useLinesInFlexViewConfig) {
            Query q2 = entityManager.createQuery("DELETE FROM CanvasFlexViewPageLineEntity WHERE fk.canvasFlexviewPage.pk.flexviewId = ?1");
            q2.setParameter(1, flexViewId);
            int countLines = q2.executeUpdate();
            logger.info("successfully deleted " + countLines + " entry/entries from CANVAS_FLEXVIEW_PAGE_LINE");
        }

        Query q3 = entityManager.createQuery("DELETE FROM CanvasFlexViewPageEntity WHERE pk.flexviewId = ?1");
        q3.setParameter(1, flexViewId);
        int countPages = q3.executeUpdate();
        logger.info("successfully deleted " + countPages + " entry/entries from CANVAS_FLEXVIEW_PAGE");

        //
        // PAGES
        //

        int counter = 1;

        for (MyScreenView screenView : myCanvasFlexViewBean.getScreens()) {

            logger.info("trying to save flexview page " + counter + " of " + myCanvasFlexViewBean.getScreens().size());

            String pageName = screenView.getId();

            CanvasFlexViewPageEntity entity = new CanvasFlexViewPageEntity();
            CanvasFlexViewPageEntityPK pk = new CanvasFlexViewPageEntityPK();
            pk.setFlexviewId(flexViewId);
            pk.setPageName(pageName);
            entity.setPk(pk);
            canvasFlexViewPageRepository.save(entity);

            counter++;
        }

        //
        // ITEMS
        //

        counter = 1;

        for (MyScreenView screenView : myCanvasFlexViewBean.getScreens()) {

            String pageName = screenView.getId();

            if (screenView.getMagnetoTemplate() != null && screenView.getMagnetoTemplate().getStreamWidgets() != null) {
                for (MyStreamWidgetTemplate sw : screenView.getMagnetoTemplate().getStreamWidgets()) {

                    logger.info("trying to save flexview item " + counter + " of " + numberOfItemsThatShallBeSaved);

                    String streamId = null;
                    String camId = null;
                    String link = null;
                    String streamPage = null;
                    Double rotation = null;
                    String elementId = null;

                    if (sw.getStreamItem() != null) {
                        streamId = sw.getStreamItem().getStreamId();
                        camId = sw.getStreamItem().getCamId();
                        if (sw.getStreamItem().getUuid() != null && !sw.getStreamItem().getUuid().equals("")) {
                            elementId = sw.getStreamItem().getUuid();
                        } else {
                            UUID uuid = UUID.randomUUID();
                            elementId = uuid.toString();
                        }
                        link = sw.getStreamItem().getLink();
                        streamPage = sw.getStreamItem().getStreamPage();
                        rotation = sw.getStreamItem().getRotate();
                    } else {
                        UUID uuid = UUID.randomUUID();
                        elementId = uuid.toString();
                    }

                    if (streamId == null || streamId.equals("")) {
                        streamId = "_0";
                    }
                    if (camId == null) {
                        camId = "";
                    }
                    if (link == null) {
                        link = "";
                    }
                    if (streamPage == null) {
                        streamPage = "";
                    }
                    if (rotation == null) {
                        rotation = 0d;
                    }

                    Double size = sw.getSize();
                    Double relationX = sw.getRelationX();
                    Double relationY = sw.getRelationY();
                    Double x = sw.getX();
                    Double y = sw.getY();
                    Short masterRecItem = 0;
                    if (sw.getMasterRecItem() == true) {
                        masterRecItem = 1;
                    }

                    CanvasFlexViewPageItemsEntity entity = new CanvasFlexViewPageItemsEntity();
                    entity.setUuid(UUID.randomUUID().toString());
                    entity.setStreamId(streamId);
                    entity.setCamId(camId);
                    entity.setLink(link);
                    entity.setStreamPage(streamPage);
                    entity.setRotation(rotation);
                    entity.setSize(size);
                    entity.setRelationX(relationX);
                    entity.setRelationY(relationY);
                    entity.setX(x);
                    entity.setY(y);
                    entity.setMasterRecItem(masterRecItem);
                    entity.setPageName(pageName);
                    entity.setFlexviewId(flexViewId);
                    entity.setElementId(elementId);
                    canvasFlexViewPageItemsRepository.save(entity);

                    counter++;
                }
            }
        }

        if (useLinesInFlexViewConfig) {

            //
            // LINES
            //

            counter = 1;

            for (MyScreenView screenView : myCanvasFlexViewBean.getScreens()) {

                String pageName = screenView.getId();

                if (screenView.getMagnetoTemplate() != null && screenView.getMagnetoTemplate().getLines() != null) {
                    for (MyLineTemplate lt : screenView.getMagnetoTemplate().getLines()) {

                        logger.info("trying to save line " + counter + " of " + numberOfLinesThatShallBeSaved);

                        CanvasFlexViewPageLineEntity entity = new CanvasFlexViewPageLineEntity();
                        CanvasFlexViewPageLineEntityFK fk = new CanvasFlexViewPageLineEntityFK();
                        CanvasFlexViewPageEntityPK canvasFlexViewPageEntityPK = new CanvasFlexViewPageEntityPK();
                        canvasFlexViewPageEntityPK.setPageName(pageName);
                        canvasFlexViewPageEntityPK.setFlexviewId(flexViewId);
                        fk.setCanvasFlexviewPage(canvasFlexViewPageRepository.getById(canvasFlexViewPageEntityPK));
                        entity.setFk(fk);
                        entity.setX1(lt.getX1());
                        entity.setX2(lt.getX2());
                        entity.setY1(lt.getY1());
                        entity.setY2(lt.getY2());
                        canvasFlexViewPageLineRepository.save(entity);

                        dto.setNumberOfLinesThatHaveBeenSaved292133(dto.getNumberOfLinesThatHaveBeenSaved292133() + 1);

                        counter++;
                    }
                }
            }
        }

        saveLog(ModuleEnum.FLEX_VIEW.getId(), "Saved FlexView via FlexViewConfig. FLEXVIEW_ID = " + flexViewId, session);

        dto.setDone593461(true);
    }
 

KonradN

Super-Moderator
Mitarbeiter
Wenn das @Transactional nicht geholfen hat, dann nimm das mal raus und pack alles manuell in eine Transaktion. Den Rahmen dafür hatte ich ja auch einmal gezeugt. Das einfach als eine Idee.
 

krgewb

Top Contributor
Ich habe nun den Timer in die andere saveMyCanvasFlexview2-Methode getan. Das ist die mit der PostMapping-Annotation. Jetzt stürzt mein Programm an einer späteren Stelle ab und zwar in
Java:
canvasFlexViewPageLineRepository.save(entity);
Da steht:
Java:
2025-01-03 11:35:40.023 [Timer-36] ERROR o.h.e.jdbc.spi.SqlExceptionHelper - (conn=1400701) Cannot add or update a child row: a foreign key constraint fails (`FLEXVIEW`.`CANVAS_FLEXVIEW_PAGE_LINE`, CONSTRAINT `FK2tssq2iia6y68w9sf6ky9imvk` FOREIGN KEY (`FLEXVIEW_ID`, `PAGE_NAME`) REFERENCES `CANVAS_FLEXVIEW_PAGE` (`FLEXVIEW_ID`, `PAGE_NAME`))

Aber ich speichere ja davor die entsprechenden Daten in CANVAS_FLEXVIEW_PAGE. Die Daten existieren auch. Ich habe mir bereits die Daten von fk per logger ausgeben lassen. fk wird hier befüllt:
Java:
fk.setCanvasFlexviewPage(canvasFlexViewPageRepository.getById(canvasFlexViewPageEntityPK));
 

KonradN

Super-Moderator
Mitarbeiter
Evtl. hast Du Probleme mit Transaktionsgrenzen? Du hast ja teilweise eigene Queries und teilweise Zugriffe über Repositories. Wenn also die Zugriffe über das Repository in einer eigenen Transaktion läuft und die vorherige Transaktion, die da etwas eingefügt hat, noch nicht beendet wurde, dann wäre das vermutlich eine Erklärung.

Evtl. liegt es aber auch daran, dass der Persistence-Cache vom EntityManager nicht mehr stimmig ist. Da wäre dann evtl. etwas wie
Java:
entityManager.flush();
entityManager.clear();
eine Möglichkeit? (Evtl. nur das flush() ausprobieren nach den direkten Queries)

Aber dieses Mischen von Zugriffen ist etwas, das ich so nie machen würde. In Spring Boot arbeite ich immer in Repositories und da wäre dann z.B. Deine Query mit "DELETE FROM CanvasFlexViewPageItemsEntity WHERE flexviewId = ?1" etwas wie:
Java:
    @Modifying
    @Transactional
    void deleteByFlexviewId(Long flexviewId);
in dem Repository<CanvasFlexViewPageItemsEntity>.

Und bei verbundenen Enntities: Dies kann auch direkt mit gehandhabt werden. Wenn Du also eine Entity mit Child Enttities hast, dann kann das JPA komplett mit erledigen. Da sind dann die CascadeTypes zu setzen und so.

Aber evtl. habe ich einfach einige Informationen nicht im Kopf, die Dein Vorgehen erläutern. Du hattest ja schon mehrere Threads daher ist das nur ein Hinweis am Rande. Und ich weiss in erster Linie halt, was ich bisher so gemacht habe und das heisst natürlich nicht, das andere Wege / Möglichkeiten falsch sind oder so.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
A SQL TransactionRequiredException Datenbankprogrammierung 8

Ähnliche Java Themen


Oben