How to execute custom SQL query with spring-managed transactional EntityManager

丶灬走出姿态 提交于 2019-12-04 01:13:20

You can use createNativeQuery to execute any arbitrary SQL on your database.

EntityManager em = emf.createEntityManager();
List<Object> results = em.createNativeQuery("SELECT custom FROM my_data").getResultList();

The above answer still holds true but I would like to edit in some additional information that may also be relevant to people looking at this question.

While it is true that you can use the createNativeQuery method to execute native queries through an EntityManager; there is an alternative (arguably better) way of doing it if you are using the Spring Framework.

The alternative method for executing queries with Spring (that will behave with the configured transactions) is to use the JDBCTemplate. It is possible to use both the JDBCTemplate and a JPA EntityManager within the same application. The configuration would look something like this:

InfrastructureConfig.class:

@Configuration
@Import(AppConfig.class)
public class InfrastructureConfig {

    @Bean //Creates an in-memory database.
    public DataSource dataSource(){
        return new EmbeddedDatabaseBuilder().build(); 
    }   

    @Bean //Creates our EntityManagerFactory
    public AbstractEntityManagerFactoryBean entityManagerFactory(DataSource dataSource){
        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setDataSource(dataSource);
        emf.setJpaVendorAdapter(new HibernateJpaVendorAdapter());

        return emf;
    }

    @Bean //Creates our PlatformTransactionManager. Registering both the EntityManagerFactory and the DataSource to be shared by the EMF and JDBCTemplate
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf, DataSource dataSource){
        JpaTransactionManager tm = new JpaTransactionManager(emf);
        tm.setDataSource(dataSource);
        return tm;
    }

}

AppConfig.class:

@Configuration
@EnableTransactionManagement
public class AppConfig {

    @Bean
    public MyService myTransactionalService(DomainRepository domainRepository) {
        return new MyServiceImpl(domainRepository);
    }

    @Bean
    public DomainRepository domainRepository(JdbcTemplate template){
        return new JpaAndJdbcDomainRepository(template);
    }

    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource){
        JdbcTemplate template = new JdbcTemplate(dataSource);
        return template;
    }
}

And an example repository that would use both JPA and JDBC:

public class JpaAndJdbcDomainRepository implements DomainRepository{

    private JdbcTemplate template;
    private EntityManager entityManager;

    //Inject the JdbcTemplate (or the DataSource and construct a new JdbcTemplate)
    public DomainRepository(JdbcTemplate template){
        this.template = template;
    }

    //Inject the EntityManager
    @PersistenceContext
    void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    //Execute a JPA query
    public DomainObject getDomainObject(Long id){
        return entityManager.find(id);
    }

    //Execute a native SQL Query
    public List<Map<String,Object>> getData(){
        return template.queryForList("select custom from my_data");
    }
}

You can use EntityManager.createNativeQuery(String sql) to use direct sql code or use EntityManager.createNamedQuery(String name) to execute precompiled query. You still use spring-managed Entity manager, but working on non managed objects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!