How to manually start a transaction on a shared EntityManager in Spring?

前端 未结 4 1185
我在风中等你
我在风中等你 2020-12-25 11:36

I have a LocalContainerEntityManagerFactoryBean as EntityManager instance.

To quickly drop a full tables\' content, I want to run the follo

相关标签:
4条回答
  • 2020-12-25 12:15

    Spring Data JPA automatically runs CRUD method in transactions for you (without needing to set up anything except a transaction manager). If you want to use transactions for your query methods, you can simply add @Transactional to these:

    interface MyRepository extends CrudRepository<MyEntity, Integer> {
    
      @Transactional
      @Modifying
      @Query(value = "TRUNCATE TABLE MyTable", nativeQuery = true)
      void clear();
    }
    

    On a more general note, what you have declared here is logically equivalent to CrudRepository.deleteAll(), except that it (your declaration) doesn't honor JPA-level cascades. So I wondered that's really what you intended to do. If you're using Spring Boot, the activation and transaction manager setup should be taken care of for you.

    If you want to use @Transactional on the service level, you need to setup both a JpaTransactionManager and activate annotation based transaction management through either <tx:annotation-driven /> or @EnableTransactionManagement (looks like the activation was the missing piece on your attempt to create transactions on the service layer).

    0 讨论(0)
  • 2020-12-25 12:23

    You should use TransactionTemplate object to manage transaction imperatively:

    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                em.createNativeQuery("TRUNCATE TABLE MyTable).executeUpdate();
            }
        });
    

    To create TransactionTemplate just use injected PlatformTransactionManager:

    transactionTemplate = new TransactionTemplate(platformTransactionManager);
    

    And if you want to use new transaction just invoke

    transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
    
    0 讨论(0)
  • 2020-12-25 12:35

    @Transactional annotation should not be applied on Dao method but on a service method. Although your code says DatabaseService is a service, but by inserting EntityManger inside a service does not make any sense.

    Correct way to implement is to create a Dao like below.

    @Repository
    public class DatabaseDao {
        @PersistenceContext
        private EntityManager em;
    
        public void clear() {
            em.createNativeQuery("TRUNCATE TABLE MyTable").executeUpdate();
        }
    }
    

    Then call the dao method from a service method with @Transactional annotation.

    @Service
    public class DatabaseService {
        @Autowired
        private DatabaseDao dao;
    
        @Transactional
        public void clear() {
            dao.clear();
        }
    }
    

    Also, add @EnableTransactionManagement in your Configuration class

    0 讨论(0)
  • 2020-12-25 12:36

    As a workaround I now created a new EntityManager explicit using the EMF, and starting the transaction manually.

    @Autowired
    private EntityManagerFactory emf;
    
    public void clearTable() {
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        em.createNativeQuery("TRUNCATE TABLE MyTable").executeUpdate();
        tx.commit();
        em.close();
    }
    

    That's probably not ideal, but works for the moment.

    0 讨论(0)
提交回复
热议问题