1

I have a minimal spring boot application, consisting of 3 classes: an Entity, a component that tries to populate db in @PostConstruct and an application class. Nothing else.

@SpringBootApplication
public class App {
  public static void main(String[] args) {
    SpringApplication.run(App.class, args);
  }
}

@Component
@Transactional
public class Initializer {
    @Autowired
    EntityManager em;

    @PostConstruct
    public void populate() {
        em.persist(new MyEntity());
    }
}

@Entity
public class MyEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    int id;
}

When I run the application I get an javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call

I'm not the only one ever getting that error and I read a lot of the posts, but did not find a magic solution.

If I autowire an EntityMananagerFactory and instead do:

EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(new MyEntity());
em.getTransaction().commit();
em.close();

It works. Question is: Is there a simpler way (place the right annotation at the right spot) to get an EntityManager that can persist an entity? I have good reasons for not creating a repository (I tried doing that and that works).

Best regards Jens

Jens Møller
  • 525
  • 5
  • 20
  • 1
    Spring transactional management is the easy way. However, that does not make a transaction available in a PostConstruct method. Trying to initialize data in such a method is simply the wrong way to go about it. You initialize the bean in such a method, not a database. – Gimby Jun 17 '19 at 15:11
  • This might be helpful: https://stackoverflow.com/questions/17346679/transactional-on-postconstruct-method – Maxim Markov Jun 17 '19 at 15:40
  • Thanks @MaximMarkov, that helped me solve my problem, will post a working solution shortly. – Jens Møller Jun 18 '19 at 07:52
  • @Gimby is there a right way for initializing database on application startup (perhaps an @EventListener)? I remember researching how to programatically initialize/populate the database on application startup a while ago without finding any best-practice. – Jens Møller Jun 18 '19 at 09:14

2 Answers2

2

So after trying a lot of different stuff, I think that I found a working solution, where the initalization is done in an ApplicationReadyEvent handler instead of in a @PostConstruct method:

@Component
public class Initializer {

    @PersistenceContext
    EntityManager em;

    @EventListener(ApplicationReadyEvent.class)
    @Transactional
    public void init() {
        em.persist(new MyEntity());
    }
}

Working example: https://github.com/djarnis73/spring-boot-db-init-with-jpa-entity-manager

Jens Møller
  • 525
  • 5
  • 20
0

As per my understanding, @PostConstruct gets called on app startup when we want to initialize the beans and the configs. I think @PostConstruct is not the right place to do so.

However you can use @PersistenceContext on your entityManger instead of autowiring it.

  • Yes, I have seen the several pointers about not having transactions in @PostConstruct/InitializingBean. You do have them if you use a Repository instead of an EntityManager, which I guess is what confused me. I did try with @PersistenceContext and did not see any difference in behaviour. – Jens Møller Jun 18 '19 at 07:16