4

I am using spring data/jpa to perform some database operations. I have a while loop which runs and successfully inserts data as it runs, but i also need an update operation to happen at the end of each run of a while loop. Here is basically what I have in a simple example. This is exactly the structure I am using.

Class doing all the operations:

@Component
public class MyClassImpl implements MyClass {
    @Autowired
    MyOtherClass myOtherClass;

    @Override
    public void run() {
        while (expression) {
            // get some data into and entity object

            myOtherClass.insertMethod(entity);
            myOtherClass.updateMethod(entityId);
        }
    } 

}

my other class:

@Component
public class MyOtherClassImpl implements MyOtherClass {

    @Override
    JpaClass jpaClass;

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void insertMethod(EntityObject entity) {
         jpaClass.save(entity);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateMethod(String entityId) {
         EntityObject entity = jpaClass.findById(entityId);
         //change something on the entity
         jpaClass.save(entity);
    }
}

entity object:

public interface JpaClass extends JpaRepository<EntityObject, Long> {
      EntityObject findById(String entityId);
}

the problem I am having is that the insert works just fine, but within the while loop I cannot get any updates to work like i have them. I have tried moving the logic around and putting the findById logic in a different method but cannot get it working. I am trying to update 1 row in a table which handles 1 value I then need to reference in the next run of the while loop.

so it goes:

  1. get value
  2. operate using value
  3. update value
  4. repeat

I set up the database config using spring @Configuration on a class which works fine for all transactions, for reference it is essentially set up like this:

@Configuration
@EnableTransactionManagement
@PropertySource(value = { "classpath:/${app.execution.environment}/application.properties" })
@EnableJpaRepositories(basePackages = "com.example", entityManagerFactoryRef = "mysqlEntityManager", transactionManagerRef = "mysqlTransactionManager")
public class MysqlHibernateConfig {

// all the needed beans here
}

Just to confirm as well, i ran this logic without the while loop and the data does update as expected, so the problem is somewhere in the database transaction, but I am stuck on how to resolve it.

wondergoat77
  • 1,765
  • 9
  • 32
  • 60
  • 1
    Define "not working", do you get an exception? Also shouldn't you do the while loop job in the same transaction (insert / update etc)? –  Aug 08 '16 at 16:34
  • Try this link. It may help. http://stackoverflow.com/questions/24338150/how-to-manually-force-a-commit-in-a-transactional-method – Najeeb Arif Aug 08 '16 at 16:38
  • not working means, it never updates the value i expect it to update. no exceptions occur at all. The value i expect to change in the database table never updates. – wondergoat77 Aug 08 '16 at 16:39
  • thanks @NajeebArif thats where i first started working, but i am clearly misunderstanding something – wondergoat77 Aug 08 '16 at 16:39
  • @RC. what do you mean by putting the while loop in the same job? do you mean put the while loop inside the actual transactional method? i.e. while (condition) { // do database transactions} – wondergoat77 Aug 08 '16 at 16:41
  • I mean take the DB operations and put that in a service method that is `@Transactional` My hypothesis: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html#REQUIRES_NEW *and suspend the current transaction if one exists* –  Aug 08 '16 at 16:43
  • @RC. is that not what i have in MyOtherClassImpl#updateMethod() ? or do you mean the calling method from MyClass#run()? – wondergoat77 Aug 08 '16 at 16:44
  • I added @Transactional(propagation = Propagation.REQUIRES_NEW) to the JpaClass method to findById and I can now get 1 update to happen each time i run the application. basically running in a unit test. Not sure yet why it works once and never again, but i guess thats some progress. – wondergoat77 Aug 08 '16 at 16:46
  • Your edited comment sounds like what i just ran into. Ill read the doc. – wondergoat77 Aug 08 '16 at 16:47
  • what are the primary keys against the entity object in DB? – Najeeb Arif Aug 08 '16 at 16:53
  • @NajeebArif primary key is just an Id which is auto incremented, in the mysql db it is a BIGINT(20) in Jave it is a Long type – wondergoat77 Aug 08 '16 at 16:55
  • @RC. so since i have one "REQUIRES_NEW" transaction already running, I cannot run another transaction from the same calling method since they are both called from the same spring proxt class? If that is correct, having trouble figuring out how to work around it. – wondergoat77 Aug 08 '16 at 16:56
  • @RC. I figured out what the problem really is, not sure how to solve yet. My update was in fact working, but the next time through each loop, I use a value on the updated entity from the previous loop. I kept getting the same value over and over again because it never had time to clear the cache. The cache appears to be around 3 minutes storing the previous values I got from the database. The loop ran faster than this, so appeared to not be updating at all. So now i just need to figure out how to force a cache/memory clear each time i query the database. – wondergoat77 Aug 09 '16 at 15:31

1 Answers1

0

This problem is caused by cache. You can try like this.

  1. in service class,

        @Autowired
        private EntityManager entityManager;
        entityManager.clear();
    
  2. in application.properties, you should set

        spring.jpa.open-in-view = false