2013-02-10 9 views
5

私は永続化層としてJPAを利用してSpring MVCアプリケーションを作成しようとしています。残念ながら、Springがインジェクションしているように見えないので、EntityManagerにアクセスするとNullPointerExceptionが発生していました。私の設定はすべて@EnableWebMvcでアノテーションベースです。いくつかの検索の後、私は@TransactionalをDAOに、@EnableTransactionManagementを@Configurationクラスに追加しました。それから、DataSourceを持っていないというエラーが出ました。おそらく、@EnableTransactionManagementを持つクラスはTransactionManagementConfigurerを実装する必要があります。しかし、DataSourceの作成方法と、なぜpersistence.xmlから取得できないのかがわかりません。JPA with Spring MVC Annotationsによって設定されました

私はDAOにEntityManagerを注入しようとするとどんな助けにも大変感謝しています。

マイ@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(); 
} 

} 

マイ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が正しく注入されています。ただし、トランザクションは機能していません。私はRESOURCE_LOCALアプローチを使用しようとするとエラーになるので、JTAが管理するトランザクションを見ています。私のDAOメソッドに@Transactionalを追加すると、トラブルシューティングを支援するために、ログファイルに詳細がなく「ロールバックマークが付いたトランザクション」エラーが表示されます。私が基本的な読み取り専用選択から注釈を削除した場合、選択は完全に正常に機能します(注釈を選択のみのメソッドに置くべきかどうかはわかりません)。しかし、私は明らかに、db writeを実行するメソッドでこれを動作させる必要があります。私はコードを介してデバッグする場合、それは完璧にデータを取得するようだ。ただし、メソッドから戻ると、javax.transaction.RollbackExceptionがスローされます。すべての私の理解から、AOPのポストメソッド処理で例外が発生したように見えます。私のアプリケーションで

マイ@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; 
} 

} 

答えて

9

私はTransactionManagerConfigurerインタフェースを実装していませんでした。私は次のコードを使ってJPAを設定します(Hibernateの実装で)。設定クラスで同じことができます。これは)

EDITをお手伝いします

@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クラスの例があります。

EDIT 2: 私は私のプロジェクトでのpersistence.xml ahve、それが空である:

<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の設定で任意の永続的なユニット名を指定していませんでした。次

+0

これは、Hibernate固有のクラスを明示的に参照することは、基本的な実装と結び付いているように思えます。 また、理想的には、データソースにJNDIルックアップを使用しますが、それをどうやって行うのかよく分かりません。私はこれをしていないと仮定していますか? – Marshmellow1328

+0

基本的な実装との結びつき - SpringなしでJPAを使用する場合でも、persistence.xmlに永続性プロバイダ設定を定義します。ここでは、それらを1つのメソッドentityManagerFactoryBean()のコードで定義します。しかし、あなたはそれらをxml設定ファイルに移すことができます) – dimas

+0

元の答えでJNDIルックアップを使ってDataSourceを取得する方法の例を追加しました。 – dimas

1

は、XMLベースの構成を使用していても、役立つかもしれない:

https://github.com/springinpractice/sip13/blob/master/helpdesk/src/main/resources/spring/beans-repo.xml

それは春データJPAを使用しますが、あなたがそれを行う必要はありません。

@PersistenceContext private EntityManager entityManager; 

を使用してください(。しかし、それは箱から出して非常に有能なのDAOを提供して春データJPAを考える)

サイドノート:DAOをするために、@Componentオーバー@Repositoryを好みます。両方ともコンポーネントスキャンのために機能しますが、@Repositoryが目的の使用方法をよりよく説明しています。

関連する問題