Próbuję utworzyć aplikację Spring MVC wykorzystującą JPA dla jej warstwy trwałości. Niestety, otrzymałem wyjątek NullPointerException podczas uzyskiwania dostępu do EntityManager, ponieważ Spring nie wydaje się go wstrzykiwać. Moja konfiguracja jest oparta na adnotacji z @EnableWebMvc. Po pewnym wyszukiwaniu dodałem @Transactional na moich DAO i @EnableTransactionManagement na mojej klasie @Configuration. Wtedy dostałem błąd dotyczący braku źródła danych. Podobno klasa z @EnableTransactionManagement musi wdrożyć TransactionManagementConfigurer. Mam jednak problemy z ustaleniem, jak utworzyć źródło danych, a także dlaczego nie można go pobrać z pliku persistence.xml.JPA ze Spring MVC Configured via Adnotations
Byłbym wdzięczny za każdą pomoc w próbie wprowadzenia EntityManager do mojego DAO.
Moja klasa @Configuration
@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();
}
}
Moja 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;
}
}
Moja zaktualizowanego kodu
doszedłem do punktu, w którym to prawie wszystkie prace. EntityManager jest prawidłowo wstrzykiwany. Jednak transakcje nie działają. Występują błędy, jeśli próbuję użyć podejścia RESOURCE_LOCAL, więc szukam transakcji zarządzanych przez JTA. Kiedy dodaję @Transactional do każdej z moich metod DAO, pojawia się błąd "Transakcja oznaczona dla przywrócenia", bez żadnych szczegółów w plikach dziennika, aby pomóc w rozwiązywaniu problemów. Jeśli usunę adnotację z podstawowego wyboru tylko do odczytu, wybór będzie działał idealnie dobrze (nie jestem pewien, czy powinienem nawet umieszczać adnotację na metodach tylko do wyboru). Jednak oczywiście potrzebuję tego działa na metodach, które wykonują zapisy db. Jeśli debuguję kod, wydaje się, że dane są idealnie dokładne. Jednak po powrocie z metody generowany jest wyjątek javax.transaction.RollbackException. Z mojego rozumienia wszystkiego wydaje się, że wyjątek występuje w przetwarzaniu końcowym AOP.
Moja klasa @Configuration
@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;
}
}
Łagodnie niepokoi mnie to, że wyraźnie odwołujesz się do klas specyficznych dla Hibernacji, ponieważ wydaje się, że wiąże to z podstawową implementacją. Również najlepiej byłoby użyć wyszukiwania JNDI dla źródła danych, ale nie wiem, jak to zrobić. Zakładam, że to nie robi? – Marshmellow1328
Informacje o powiązaniu z podstawową implementacją - nawet jeśli używasz JPA bez Spring, definiujesz ustawienia dostawcy utrwalania w pliku persistence.xml. Tutaj definiujesz je w kodzie w jednej metodzie entityManagerFactoryBean(). Ale możesz przenieść je do pliku konfiguracyjnego xml) – dimas
Dodałem przykład jak uzyskać DataSource za pośrednictwem wyszukiwania JNDI w mojej oryginalnej odpowiedzi. – dimas