1

In short, I have three methods:

    @Transactional(propagation=Propagation.REQUIRED, noRollbackFor=Exception.class)
    public void Manage(long bookId) throws Exception {

        Book book = dao.getByKey(bookId);

        //...

        register(book);

    }


    @Transactional(propagation=Propagation.REQUIRED, noRollbackFor=Exception.class)
    public void register(Book book) {

        try {

            // updateSomeId method should be called in another thread
            // POST request to the service, waiting for the response then updating the DB
            Runnable task = () -> {

                if(someId > 0) {
                    dao.updateSomeId(book, someId);

            }
            Thread thread = new Thread(task);
            thread.start();
        } catch (Exception e) {

        }

    }



    @Transactional(propagation=Propagation.REQUIRED, noRollbackFor=Exception.class)
    public void updateSomeId(Book book, long someId) {
        try {
            Book findedBook = getByKey(book.getBookId());
            findedBook.setSomeId(someId);
        } catch (Exception e) {
            logger.error("error", e);
        }
    }

updateSomeId method must update the someId property in Book table.
In the log I see: Hibernate: update Book set author=?, someId=? where bookId=?

But, there are no any changes in my DB, no any errors. Could anyone explain what happens and how to solve it? It's one of thousands of updates I have and only in this case it hasn't updated the DB table.

JPA 2.1

Hibernate 5.2.10.Final

John
  • 446
  • 6
  • 16
  • Do you see the query in the DB log? What parameters are substituted into the query - do they match those that you expect? Do you see a `COMMIT` statement in the DB log? – Boris the Spider Feb 13 '19 at 05:29
  • 1
    The problem is likely that transactions don't generally propagate across multiple threads. Why do you feel you need to perform part of the work on a separate thread, though? Judging by the code you posted, it doesn't make much sense. If you don't want the client of `Manage` to block waiting for the method to finish, data access layer is not where you want to handle async execution – crizzis Feb 13 '19 at 08:37
  • @Boris the Spider, it's impossible now... – John Feb 15 '19 at 08:20
  • @crizzis, I need to perform part of the work on a separate thread because I've simplified the logic in the question. In fact I send POST request to other service there and I should not wait the response, but when I receive the response I need to update the DB. – John Feb 15 '19 at 08:21
  • In that case: (1) sending a request is an irreversible operation, why should it be a part of the transaction? Most likely, you should schedule sending the request *after* the transaction commits *and then* call `updateSomeId` in a separate transaction altogether, (2) if you insist that the request happens inside the transaction, then you should make `Manage` *completely synchronous*. It's the calling code's job to schedule the execution of `Manage` on a separate thread – crizzis Feb 15 '19 at 08:48

2 Answers2

0

May be your main thread is not waiting the update task thread. Therefore container cannot commit your transaction. Can you change your register method like below and give it a try?

   @Transactional(propagation=Propagation.REQUIRED, noRollbackFor=Exception.class)
    public void register(Book book) {

        try {

            // updateSomeId method should be called in another thread
            Runnable task = () -> {

                if(someId > 0) {
                    dao.updateSomeId(book, someId);

            }
            Thread thread = new Thread(task);
            thread.start();
            thread.join();//this tells the main thread to wait until it finishes execution.

        } catch (Exception e) {

        }

    }
mstfyldz
  • 482
  • 1
  • 6
  • 12
  • Yes, the main thread is not waiting the update task thread and after the task was started the main thread responses to another service. I was debugging my code and in this case I saw that the data was updated although the main thread has already stopped. I have to create separate thread because it really nesessery here and I should not wait the task will be stopped. – John Feb 15 '19 at 08:45
-1

You are trying to update someId field alone in findedBook object but in log Hibernate: update Book set author=?, someId=? where bookId=? update statement shows multiple fields author=?, someId=?, seems the logged statement is not meant for your current operation.

  • Create new method in dao class with statement as session.update(book) and call the same method from updateSomeId method and pass book object as parameter.
Selvam M
  • 520
  • 4
  • 18
  • By default hibernate includes all the fields in the update query. https://stackoverflow.com/questions/10315377/why-in-jpa-hibernate-update-query-all-attributes-get-update-in-sql In my case, I've checked many times the log and it's exactly that operation I'm interested in. – John Feb 13 '19 at 05:24
  • Without dynamic updates Hibernate will use prepared statements that update all fields. – Boris the Spider Feb 13 '19 at 05:25