尝试使用 HibernateTransactionManager,但事务服务抛出 HibernateException

trying to use HibernateTransactionManager, but transactional services throw HibernateException

我正在尝试将 Spring 4 项目转换为使用 HibernateTransactionManager 来管理事务,但事务服务抛出此异常:

org.hibernate.HibernateException: createSQLQuery is not valid without active transaction

我在 google 上搜索过,80 个不同的人有 80 种不同的方法。我已经尝试了所有这些方法,要么它们不起作用,要么它们需要使用 EntityManager 而不是 Hibernate Sessions。由于我正在转换使用 Hibernate 会话的现有代码,如果我能让它们工作,事情会容易得多。我如何摆脱这个异常?

数据源配置:

@Configuration
public class DataSourceConfig {
    @Bean
    public DataSource dataSource() {
        // return a Hikari connection pool as the data source
        try {
            HikariDataSource bean = new HikariDataSource();
            // set connection pool and JDBC properties
            return bean;
        } catch (Exception e) {
            throw new RuntimeException("could create data source", e);
        }
    }
}

会话工厂配置:

@Configuration
public class SessionFactoryConfig {
    @Autowired
    private DataSource dataSource;

    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        // create a session factory
        try {
            LocalSessionFactoryBean bean = new LocalSessionFactoryBean();
            // set Hibernate properties
            bean.setDataSource(dataSource);
            bean.setPackagesToScan(packagesToScan);
            bean.setHibernateProperties(properties);
            bean.afterPropertiesSet(); // tried without this line as well
            return bean;
        } catch (Exception e) {
            throw new RuntimeException("could not create session factory", e);
        }
    }
}

交易配置:

@Configuration
@EnableTransactionManagement
@ComponentScan("com.mydomain.*")
public class TransactionConfig {
    @Autowired
    private SessionFactory sessionFactory;

    @Bean
    public PlatformTransactionManager transactionManager() {
        HibernateTransactionManager bean = new HibernateTransactionManager(sessionFactory);
//      bean.setHibernateManagedSession(true); // similar exception when set
        bean.afterPropertiesSet(); // tried without this line as well
        return bean;
    }
}

服务:

@Service
@Transactional // tried using only the @Transactional on the method
public class TestTransactionService {
    @Autowired
    private SessionFactory sessionFactory;

    @Transactional // tried using only the @Transactional on the class
    public String get(String key) {
        Session session = sessionFactory.getCurrentSession();
        // the below line throws the exception!
        SQLQuery q = session.createSQLQuery("SELECT value FROM test_transaction WHERE key = :key");
        q.setParameter("key", key);
        q.addScalar("value", StringType.INSTANCE);
        String out = (String)q.uniqueResult();
        return out;
    }
}

有什么想法吗?我希望如此,因为我出去了。

埋在我们的设置中的是这个 innocent-looking 一个,自从我们项目的初始 git 签入以来就在那里,所以我无法找出是谁把它放进去的(他们很幸运):

hibernate.current_session_context_class = thread

因为没人知道这个设置是干什么用的,所以以后就没人敢碰了。这破坏了 Spring 托管交易,并且没有业务在那里。

让我们作为一个教训,男孩和女孩们:如果你想让一些东西发挥作用,不要只是 fiddle 在你不知道它们是什么的情况下进行设置。它会回来咬你的屁股——有时是几年后。然后我会来找你并得到你。