web-dev-qa-db-ja.com

HibernateException:現在のスレッドのトランザクション同期セッションを取得できませんでした

_@Service_注釈付きクラスを使用しようとすると、次の例外が発生します。

_org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
    at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.Java:134) ~[spring-orm-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.Java:1014) ~[hibernate-core-4.3.6.Final.jar:4.3.6.Final]
    at webapp.base.repository.GenericDaoImpl.saveOrUpdate(GenericDaoImpl.Java:59) ~[base-0.0.1-SNAPSHOT-classes.jar:na]
    at com.example.repository.PageViewDaoImpl.saveOrUpdate(PageViewDaoImpl.Java:19) ~[site-0.0.1-SNAPSHOT.jar:na]
    at com.example.repository.PageViewDaoImpl.saveOrUpdate(PageViewDaoImpl.Java:14) ~[site-0.0.1-SNAPSHOT.jar:na]
    at com.example.service.PageViewServiceImpl.savePageView(PageViewServiceImpl.Java:26) ~[site-0.0.1-SNAPSHOT.jar:na]
    at com.example.interceptor.PageViewInterceptor.preHandle(PageViewInterceptor.Java:29) ~[site-0.0.1-SNAPSHOT.jar:na]
    at org.springframework.web.servlet.HandlerExecutionChain.applyPreHandle(HandlerExecutionChain.Java:130) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.Java:938) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.Java:877) ~[spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.Java:966) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.Java:857) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.Java:620) [servlet-api-3.0.jar:na]
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.Java:842) [spring-webmvc-4.1.1.RELEASE.jar:4.1.1.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.Java:727) [servlet-api-3.0.jar:na]
    at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:303) [Tomcat-catalina-7.0.52.jar:7.0.52]
    at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:208) [Tomcat-catalina-7.0.52.jar:7.0.52]
    at org.Apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.Java:748) [Tomcat-catalina-7.0.52.jar:7.0.52]
    at org.Apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.Java:488) [Tomcat-catalina-7.0.52.jar:7.0.52]
    at org.Apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.Java:411) [Tomcat-catalina-7.0.52.jar:7.0.52]
    at org.Apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.Java:338) [Tomcat-catalina-7.0.52.jar:7.0.52]
    at org.Apache.catalina.core.StandardHostValve.custom(StandardHostValve.Java:466) [Tomcat-catalina-7.0.52.jar:7.0.52]
    at org.Apache.catalina.core.StandardHostValve.status(StandardHostValve.Java:337) [Tomcat-catalina-7.0.52.jar:7.0.52]
    at org.Apache.catalina.core.StandardHostValve.throwable(StandardHostValve.Java:427) [Tomcat-catalina-7.0.52.jar:7.0.52]
    at org.Apache.catalina.core.StandardHostValve.invoke(StandardHostValve.Java:200) [Tomcat-catalina-7.0.52.jar:7.0.52]
    at org.Apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.Java:98) [Tomcat-catalina-7.0.52.jar:7.0.52]
    at org.Apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.Java:950) [Tomcat-catalina-7.0.52.jar:7.0.52]
    at org.Apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.Java:116) [Tomcat-catalina-7.0.52.jar:7.0.52]
    at org.Apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.Java:408) [Tomcat-catalina-7.0.52.jar:7.0.52]
    at org.Apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.Java:1040) [Tomcat-coyote-7.0.52.jar:7.0.52]
    at org.Apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.Java:607) [Tomcat-coyote-7.0.52.jar:7.0.52]
    at org.Apache.Tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.Java:313) [Tomcat-coyote-7.0.52.jar:7.0.52]
    at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1145) [na:1.7.0_65]
    at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:615) [na:1.7.0_65]
    at Java.lang.Thread.run(Thread.Java:745) [na:1.7.0_65]
_

アプリケーションを初期化する方法は複雑なので、追加情報を取得するために完全なベースコードへのリンクを提供する必要があります: https://github.com/dtrunk90/webapp-base 。これをMavenオーバーレイとして使用しています。

そしてここに必要なコードがあります:

初期化子(webapp-baseから):

_public abstract class AbstractWebApplicationInitializer extends AbstractDispatcherServletInitializer {
    @Override
    protected String[] getServletMappings() {
        return new String[] {"/*"};
    }

    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding("UTF-8");
        encodingFilter.setForceEncoding(true);
        return new Filter[] {encodingFilter};
    }

    @Override
    protected WebApplicationContext createRootApplicationContext() {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();

        ConfigurableEnvironment environment = rootContext.getEnvironment();
        environment.setDefaultProfiles("production");

        PropertyUtil propertyUtil = PropertyUtil.getInstance(environment.getActiveProfiles());
        String[] basePackages = propertyUtil.getPropertySplitTrimmed("webapp", "basePackages");
        rootContext.scan(basePackages);

        return rootContext;
    }

    @Override
    protected WebApplicationContext createServletApplicationContext() {
        return new AnnotationConfigWebApplicationContext();
    }
}
_

イニシャライザー(私のwebappから):

_public class WebApplicationInitializer extends AbstractWebApplicationInitializer {
}
_

_@Configuration_(webapp-baseから):

_@Configuration
@EnableTransactionManagement
public class TransactionConfiguration {
    @Bean
    public DataSource dataSource() throws IOException {
        Properties conProps = PropertyUtil.getInstance().getProperties("jdbc");
        if (conProps.containsKey("url")) {
            DriverManagerDataSource dataSource = new DriverManagerDataSource(conProps.getProperty("url"), conProps);
            dataSource.setDriverClassName(conProps.getProperty("driverClassName"));
            return dataSource;
        }

        return null;
    }

    @Bean
    public SessionFactory sessionFactory() throws IOException {
        DataSource dataSource = dataSource();
        if (dataSource != null) {
            LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(dataSource);
            sessionBuilder.scanPackages(PropertyUtil.getInstance().getPropertySplitTrimmed("hibernate", "packagesToScan"));
            sessionBuilder.addProperties(PropertyUtil.getInstance().getProperties("hibernate"));
            return sessionBuilder.buildSessionFactory();
        }

        return null;
    }

    @Bean
    public HibernateTransactionManager transactionManager() throws IOException {
        SessionFactory sessionFactory = sessionFactory();
        if (sessionFactory == null) {
            return null;
        }

        return new HibernateTransactionManager(sessionFactory);
    }
}
_

_@Configuration_(私のウェブアプリから):

_@Configuration
public class MainConfiguration extends WebMvcConfigurerAdapter {
    @Autowired
    private PageViewInterceptor pageViewInterceptor; // Is annotated with @Component

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(pageViewInterceptor);
    }
}
_

_@Service_:

_@Service
public class PageViewServiceImpl implements PageViewService {
    @Autowired
    private PageViewDao pageViewDao;

    @Override
    public void savePageView(long ip, String visitPage, String userAgent) {
        PageView obj = new PageView();
        obj.setVisitDate(new Date());
        obj.setUserAgent(userAgent);
        obj.setPage(visitPage);
        obj.setIp(ip);

        pageViewDao.saveOrUpdate(obj);
    }
}
_

_@Repository_:

_@Repository
public class PageViewDaoImpl extends GenericDaoImpl<PageView, Long> implements PageViewDao {
    @Override
    public void saveOrUpdate(PageView obj) {
        if (!obj.isBot()) {
            super.saveOrUpdate(obj);
        }
    }
}

public abstract class GenericDaoImpl<T extends Identifier<I>, I extends Serializable> implements GenericDao<T, I> {
    @Autowired
    private SessionFactory sessionFactory;

    public SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            throw new IllegalStateException("SessionFactory has not been set on DAO before usage");
        }

        return sessionFactory;
    }

    @Transactional
    public void saveOrUpdate(T obj) {
        getSessionFactory().getCurrentSession().saveOrUpdate(obj);
    }
}
_

次に、PageViewServiceを自動配線して、そのメソッドを使用します。

ここで同じ問題に関するいくつかの質問があることは知っていますが、すでに何かを確認しました。

現在のスレッドのトランザクション同期セッションを取得できませんでした

  • _@EnableTransactionManagement_が提供されます
  • サービスはインターフェースとして自動配線されます

HibernateException:現在のスレッドのトランザクション同期セッションを取得できませんでした

  • 使用するすべての場所で_@Transactional_を確認しましたgetSessionFactory().getCurrentSession()

Spring Hibernate-現在のスレッドのトランザクション同期セッションを取得できませんでした

  • _@EnableTransactionManagement_が提供されます
  • 使用するすべての場所で_@Transactional_を確認しましたgetSessionFactory().getCurrentSession()

org.hibernate.HibernateException:現在のスレッドのトランザクション同期セッションを取得できませんでした

  • 役に立つ答えはありません。コントローラだけでなく、すべてのコンポーネントのコンポーネントをスキャンしたい
12
dtrunk

ログを見ると、トランザクション設定が誤って設定されていることがすぐにわかります。これは、スタックトレースにTransactionInterceptor呼び出しがないためです。

TransactionInterceptorは、Webコントローラーが実際のServiceメソッドを呼び出すときに、Spring Serviceプロキシによって呼び出されます。

  1. Spring hibernate4クラスを使用していることを確認してください。

    _org.springframework.orm.hibernate4.HibernateTransactionManager
    _
  2. _@Transactional_メソッドをオーバーライドしないでください。代わりにテンプレートパターンを使用してください。

  3. 代わりにJPATransactionManagerを使用してみてください。代わりに、現在のEntityManagerに_@PersistenceContext_アノテーションを挿入できます。これは、すべてのDAOメソッドでsessionFactory.getCurrentSession()を呼び出すよりもはるかにエレガントです。

7
Vlad Mihalcea

1つ

@Transactional@Serviceには@Repositoryを使用する必要があります。これにより、Springはトランザクションをサポートするプロキシを適用および作成できます。

あなたのコードでは、あなたの@Serviceクラスは@Transacionalをクラスレベルでもメソッドレベルでも持っていません

2番目

WebApplicationInitializerを実装するクラスはどこにありますか?私はあなたがクラスを拡張しているのを見ます。とにかく私のポイントは、次のようなものです:

@Override
public void onStartup(ServletContext container) {
    // Create the 'root' Spring application context
    AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
    rootContext.register(CentralServerConfigurationEntryPoint.class);

    // Manage the lifecycle of the root application context
    container.addListener(new ContextLoaderListener(rootContext));

    // Create the dispatcher servlet's Spring application context
    AnnotationConfigWebApplicationContext dispatcherServlet = new AnnotationConfigWebApplicationContext();
    dispatcherServlet.register(CentralWebConfigurationEntryPoint.class);

    // Register and map the dispatcher servlet
    ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherServlet));
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("/");

}

CentralServerConfigurationEntryPoint.classは、サーバー側で機能する必要のあるコンポーネントのみをスキャンする必要があります(@Service@Repository@Configurationは、トランザクション、休止状態、データソースなどの場合)

CentralWebConfigurationEntryPointは、クライアント/ Web側で機能する必要があるコンポーネントのみをスキャンする必要があります(@Controller@Configurationはフォーマッター、タイル、コンバーターなど)

私はあなたのコードを理解していません

@Override
protected WebApplicationContext createRootApplicationContext() {
    AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();

    ConfigurableEnvironment environment = rootContext.getEnvironment();
    environment.setDefaultProfiles("production");

    PropertyUtil propertyUtil = PropertyUtil.getInstance(environment.getActiveProfiles());
    String[] basePackages = propertyUtil.getPropertySplitTrimmed("webapp", "basePackages");
    rootContext.scan(basePackages);

    return rootContext;
}

@Override
protected WebApplicationContext createServletApplicationContext() {
    return new AnnotationConfigWebApplicationContext();
}

私のポイントは次のとおりです。あなたmustサーバーとWebサイドに2つのAnnotationConfigWebApplicationContextが必要です。

3
Manuel Jordan

この質問IDに対する非常に短い回答です。@ Transactionalをdaoクラスで使用し、構成クラスを@EnableTransactionManagementとしてマークして、Beanを作成するだけです。

**@Bean
public PlatformTransactionManager transactionManager() {
    DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource());
    return transactionManager;
}**

ここで、EnableTransactionManagementアノテーションで使用可能なコード例が表示されている場合は、HibernateTransactionManagerの代わりにDataSourceTransactionManagerを使用することをお勧めします。

0
Kuldeep Singh