Transactional annotation not working in Spring Boot

后端 未结 1 504
醉话见心
醉话见心 2020-12-08 03:08

@Transactional not working in Spring Boot.

Application.java :

@EnableTransactionManagement(         


        
相关标签:
1条回答
  • 2020-12-08 03:36

    First you are using Spring Boot then use Spring Boot and let that auto configure things for you. It will configure a datasource, entitymanagerfactory, transaction manager etc.

    Next you are using the wrong transaction manager, you are using JPA so you should use the JpaTransactionManager instead of the HibernateTransactionManager as that is already configured for you you can simply remove the bean definition for that.

    Second your hibernate.current_session_context_class is messing up proper tx integration remove it.

    Use auto-config

    When you take all this into account you can basically reduce your Application class to the following.

    @SpringBootApplication(exclude = {ErrorMvcAutoConfiguration.class})
    @EntityScan("com.buhryn.interviewer.models")
    public class Application {
    
        public static void main(String[] args) {
            System.out.println("--------------------------- Start Application ---------------------------");
            ApplicationContext ctx = SpringApplication.run(Application.class, args);
        }
    
        @Bean
        public SessionFactory sessionFactory(EntityManagerFactory emf) {
            if (emf.unwrap(SessionFactory.class) == null) {
                throw new NullPointerException("factory is not a hibernate factory");
            }
            return emf.unwrap(SessionFactory.class);
        }
    }
    

    Next add an application.properties in src/main/resources containing the following.

    # DataSource configuration
    spring.datasource.driver-class-name=org.postgresql.Driver
    spring.datasource.username=postgres
    spring.datasource.password=postgres
    spring.datasource.url=jdbc:postgresql://localhost:5432/interviewer
    
    # General JPA properties
    spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
    spring.jpa.show-sql=false
    
    # Hibernate Specific properties
    spring.jpa.properties.hibernate.format_sql=false
    spring.jpa.hibernate.ddl-auto=create
    

    This will configure the datasource and JPA correctly.

    Use JPA instead of plain Hibernate

    Another tip instead of using the plain hibernate API simply use JPA that way you could remove the bean for the SessionFactory as well. Simply change your dao to use an EntityManager instead of a SessionFactory.

    @Repository
    public class CandidateDao implements ICandidateDao{
    
        @PersistenceContext
        private EntityManager em;
    
        @Override
        @Transactional
        public CandidateModel create(CandidateDto candidate) {
            CandidateModel candidateModel = new CandidateModel(candidate.getFirstName(), candidate.getLastName(), candidate.getEmail(), candidate.getPhone());
            return em.persist(candidateModel);
        }
    
        @Override
        public CandidateModel show(Long id) {
            return new CandidateModel(
                    "new",
                    "new",
                    "new",
                    "new");
        }
    
        @Override
        public CandidateModel update(Long id, CandidateDto candidate) {
            return new CandidateModel(
                    "updated",
                    candidate.getLastName(),
                    candidate.getEmail(),
                    candidate.getPhone());
        }
    
        @Override
        public void delete(Long id) {
    
        }
    }
    

    Adding Spring Data JPA

    And if you really want to benefit add Spring Data JPA into the mix and remove your DAO completely and leave only an interface. What you have now would be moved to a service class (where it belongs IMHO).

    The whole repository

    public interface ICandidateDao extends JpaRepository<CandidateModel, Long> {}
    

    The modified service (which is now also transactional as it should and all business logic is in the service).

    @Service
    @Transactional
    public class CandidateService implements ICandidateService{
    
        @Autowired
        ICandidateDao candidateDao;
    
        @Override
        public CandidateModel create(CandidateDto candidate) {
            CandidateModel candidateModel = new CandidateModel(candidate.getFirstName(), candidate.getLastName(), candidate.getEmail(), candidate.getPhone());
            return candidateDao.save(candidate);
        }
    
        @Override
        public CandidateModel show(Long id) {
            return candidateDao.findOne(id);
        }
    
        @Override
        public CandidateModel update(Long id, CandidateDto candidate) {
            CandidateModel cm = candidateDao.findOne(id);
            // Update values.
            return candidateDao.save(cm);
        }
    
        @Override
        public void delete(Long id) {
            candidateDao.delete(id);
        }
    }
    

    Now you can also remove the bean definition for the SessionFactory reducing your Application to just a main method.

    @SpringBootApplication(exclude = {ErrorMvcAutoConfiguration.class})
    @EntityScan("com.buhryn.interviewer.models")
    public class Application {
    
        public static void main(String[] args) {
            System.out.println("--------------------------- Start Application ---------------------------");
            ApplicationContext ctx = SpringApplication.run(Application.class, args);
        }
    }
    

    So I would strongly suggest to work with the framework instead of trying to work around the framework. As that will really simplify your developer live.

    Dependencies

    As a final note I would suggest removing the spring-data-jpa dependency from your dependencies and use the starter instead. The same goes for AspectJ use the AOP starter for that. Also jackson 1 isn't supported anymore so adding that dependency doesn't add anything

    dependencies {
        compile("org.springframework.boot:spring-boot-starter-web")
        compile("org.springframework.boot:spring-boot-starter-actuator")
        compile("org.springframework.boot:spring-boot-starter-data-jpa")
        compile("org.springframework.boot:spring-boot-starter-aop")
        compile("com.google.code.gson:gson:2.3.1")
        compile("org.hibernate:hibernate-entitymanager:4.3.10.Final")
        compile("postgresql:postgresql:9.1-901-1.jdbc4")
    
        testCompile("org.springframework.boot:spring-boot-starter-test")
    }
    
    0 讨论(0)
提交回复
热议问题