gpt4 book ai didi

java - 如何使用 spring 管理的事务性 EntityManager 执行自定义 SQL 查询

转载 作者:IT老高 更新时间:2023-10-28 13:59:23 27 4
gpt4 key购买 nike

我有一个基于 Spring 构建的应用程序。我让 Spring 执行所有 @Transactional 魔法,只要我对映射到 Java 对象的实体进行操作,一切都会正常工作。

但是,当我想在未映射到我的任何 Java 实体的表上执行一些自定义作业时,我遇到了困难。前段时间,我找到了执行这样的自定义查询的解决方案:

// em is instance of EntityManager
em.getTransaction().begin();
Statement st = em.unwrap(Connection.class).createStatement();
ResultSet rs = st.executeQuery("SELECT custom FROM my_data");
em.getTransaction().commit();

当我用 @PersistenceContext 注释从 Spring 注入(inject)的实体管理器尝试此操作时,我收到几乎明显的异常:

java.lang.IllegalStateException: 
Not allowed to create transaction on shared EntityManager -
use Spring transactions or EJB CMT instead

我终于设法像这样提取非共享实体管理器:

@Inject
public void myCustomSqlExecutor(EntityManagerFactory emf){
EntityManager em = emf.createEntityManager();
// the em.unwrap(...) stuff from above works fine here
}

不过,我觉得这个解决方案既不舒适也不优雅。我只是想知道在这个 Spring 事务驱动的环境中是否有任何其他方法可以运行自定义 SQL 查询?

对于那些好奇的人 - 当我尝试同时在我的应用程序和相关论坛中创建用户帐户时出现了这个问题 - 我不希望论坛的用户表映射到我的任何 Java 实体。

最佳答案

您可以使用 createNativeQuery在您的数据库上执行任意 SQL。

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

上述答案仍然适用,但我想编辑一些其他信息,这些信息可能也与查看此问题的人相关。

虽然您确实可以使用 createNativeQuery通过 EntityManager 执行 native 查询的方法;如果您使用的是 Spring 框架,还有另一种(可以说是更好的)方法。

使用 Spring 执行查询的替代方法(将与配置的事务一起运行)是使用 JDBCTemplate .可以在同一应用程序中同时使用 JDBCTemplate JPA EntityManager。配置如下所示:

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;
}
}

还有一个同时使用 JPA 和 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");
}
}

关于java - 如何使用 spring 管理的事务性 EntityManager 执行自定义 SQL 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18262630/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com