Skip to main content
 首页 » 编程设计

spring之通过注解配置 Spring MVC 的 JPA

2025年02月15日21wuhuacong

我正在尝试创建一个将 JPA 用于其持久层的 Spring MVC 应用程序。不幸的是,我在访问 EntityManager 时遇到了 NullPointerException,因为 Spring 似乎没有注入(inject)它。我的配置都是基于注解的@EnableWebMvc。经过一番搜索,我在我的 DAO 上添加了@Transactional,在我的 @Configuration 类上添加了@EnableTransactionManagement。然后我收到一个关于没有数据源的错误。假设一个带有@EnableTransactionManagement 的类需要实现TransactionManagementConfigurer。但是,我在弄清楚如何创建 DataSource 以及为什么它不能从我的 persistence.xml 中获取它时遇到了问题。

在尝试将 EntityManager 注入(inject)我的 DAO 时,我将不胜感激。

我的@Configuration 类(class)

@Configuration 
@EnableWebMvc 
@EnableTransactionManagement 
@ComponentScan("com.example.myapp") 
public class MvcConfig extends WebMvcConfigurerAdapter  
        implements TransactionManagementConfigurer { 
 
private static final boolean CACHE_ENABLED = true; 
private static final String TEMPLATE_PATH = "/WEB-INF/freemarker"; 
private static final String TEMPLATE_SUFFIX = ".ftl"; 
 
private static final Logger LOG = Logger.getLogger( MvcConfig.class ); 
 
@Override 
public void addResourceHandlers( ResourceHandlerRegistry registry ) { 
    registry.addResourceHandler( "/stylesheets/**" ).addResourceLocations( "/stylesheets/" ); 
} 
 
@Bean 
public FreeMarkerConfigurer configureFreeMarker() { 
    final FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); 
    configurer.setTemplateLoaderPath( TEMPLATE_PATH ); 
    return configurer; 
} 
 
@Bean 
public ViewResolver configureViewResolver() { 
    final FreeMarkerViewResolver resolver = new FreeMarkerViewResolver(); 
    resolver.setCache( CACHE_ENABLED ); 
    resolver.setSuffix( TEMPLATE_SUFFIX ); 
    return resolver; 
} 
 
@Bean 
@Override 
public PlatformTransactionManager annotationDrivenTransactionManager() { 
    return new DataSourceTransactionManager(); 
} 
 
} 

我的 DAO
@Component 
@Transactional 
public class MyDAO { 
 
    private static final Logger LOG = Logger.getLogger( MyDAO.class ); 
 
    @PersistenceContext 
    private EntityManager entityManager; 
 
    public MyClass getMyClass() { 
        LOG.debug( "getMyClass()" ); 
        final CriteriaQuery<MyClass> query = criteriaBuilder.createQuery( MyClass.class ); 
        // more code here, but it breaks by this point 
        return myData; 
    } 
 
} 

我的更新代码

我已经达到了几乎所有工作的地步。 EntityManager 被正确注入(inject)。但是,交易不起作用。如果我尝试使用 RESOURCE_LOCAL 方法,我会收到错误,因此我正在查看 JTA 托管事务。当我在我的任何 DAO 方法上添加 @Transactional 时,我会收到“事务标记为回滚”错误,并且在任何日志文件中都没有更多详细信息来帮助进行故障排除。如果我从基本只读选择中删除注释,则选择将工作得很好(不确定我是否应该将注释放在仅选择方法上)。但是,我显然需要对执行数据库写入的方法进行这项工作。如果我通过代码进行调试,似乎可以很好地检索数据。但是,当它从该方法返回时,会抛出 javax.transaction.RollbackException。根据我对一切的理解,似乎异常发生在AOP后方法处理中。

我的@Configuration 类(class)
@Configuration 
@EnableWebMvc 
@EnableTransactionManagement 
@ComponentScan("com.example.myapp") 
public class MvcConfig extends WebMvcConfigurerAdapter { 
 
private static final boolean CACHE_ENABLED = true; 
private static final String TEMPLATE_PATH = "/WEB-INF/freemarker"; 
private static final String TEMPLATE_SUFFIX = ".ftl"; 
 
private static final Logger LOG = Logger.getLogger( MvcConfig.class ); 
 
@Override 
public void addResourceHandlers( ResourceHandlerRegistry registry ) { 
    registry.addResourceHandler( "/stylesheets/**" ).addResourceLocations( "/stylesheets/" ); 
} 
 
@Bean 
public FreeMarkerConfigurer configureFreeMarker() { 
    final FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); 
    configurer.setTemplateLoaderPath( TEMPLATE_PATH ); 
    return configurer; 
} 
 
@Bean 
public ViewResolver configureViewResolver() { 
    final FreeMarkerViewResolver resolver = new FreeMarkerViewResolver(); 
    resolver.setCache( CACHE_ENABLED ); 
    resolver.setSuffix( TEMPLATE_SUFFIX ); 
    return resolver; 
} 
 
@Bean 
public PlatformTransactionManager transactionManager() { 
    return new JtaTransactionManager(); 
} 
 
@Bean 
public AbstractEntityManagerFactoryBean entityManagerFactoryBean() { 
    LocalEntityManagerFactoryBean factory = new LocalEntityManagerFactoryBean(); 
    factory.setPersistenceUnitName( "my_db" ); 
    return factory; 
} 
 
} 

请您参考如下方法:

在我的应用程序中,我没有实现 TransactionManagerConfigurer 接口(interface)。我使用下一个代码来配置 JPA(使用 Hibernate 实现)。您可以在配置类中执行相同的操作。

    @Bean 
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() { 
        LocalContainerEntityManagerFactoryBean factoryBean =  
                new LocalContainerEntityManagerFactoryBean(); 
 
        factoryBean.setDataSource(dataSource()); 
        factoryBean.setPackagesToScan(new String[] {"com.dimasco.springjpa.domain"}); 
 
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); 
        vendorAdapter.setShowSql(true); 
        //vendorAdapter.setGenerateDdl(generateDdl) 
 
        factoryBean.setJpaVendorAdapter(vendorAdapter); 
 
        Properties additionalProperties = new Properties(); 
        additionalProperties.put("hibernate.hbm2ddl.auto", "update"); 
 
        factoryBean.setJpaProperties(additionalProperties); 
 
 
        return factoryBean; 
    } 
 
    @Bean 
    public DataSource dataSource() { 
        final ComboPooledDataSource dataSource = new ComboPooledDataSource(); 
 
        try { 
            dataSource.setDriverClass(driverClass); 
        } catch (PropertyVetoException e) { 
            throw new RuntimeException(e); 
        } 
 
        dataSource.setJdbcUrl(jdbcUrl); 
        dataSource.setUser(user); 
        dataSource.setPassword(password); 
        dataSource.setMinPoolSize(3); 
        dataSource.setMaxPoolSize(15); 
        dataSource.setDebugUnreturnedConnectionStackTraces(true); 
 
        return dataSource; 
    } 
 
    @Bean 
    public PlatformTransactionManager transactionManager() { 
        JpaTransactionManager transactionManager = new JpaTransactionManager(); 
        transactionManager.setEntityManagerFactory(entityManagerFactoryBean().getObject()); 
 
        return transactionManager; 
    } 
 
    @Bean 
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){ 
        return new PersistenceExceptionTranslationPostProcessor(); 
    } 

希望对你有帮助)

编辑:

您可以使用 JNDI 查找来获取数据源:
@Bean 
public DataSource dataSource() throws Exception { 
   Context ctx = new InitialContext(); 
   return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource"); 
} 

更多详情您可以找到 in this article .有 JndiDatasourceConfig 类的示例。

编辑 2:
我在我的项目中使用了 persistence.xml,但它是空的:
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> 
    <persistence-unit name="JPA_And_Spring_Test"> 
    </persistence-unit> 
</persistence> 

而且我没有在我的 java 配置中指定任何持久单元名称。