【问题标题】:Hibernate does not flush persistence context before selectionHibernate 在选择之前不会刷新持久性上下文
【发布时间】:2020-03-09 04:43:48
【问题描述】:

我正在尝试使用 spring 事务支持来用户休眠。我已经将会话工厂配置为 bean(见下文)并创建了一个 DAO 类。我也在使用 spring 测试支持——使用 @Transactional 注释运行测试类,哪个(据我了解)应该允许我在单个事务中调用多个 dao 操作。我读到休眠应该在提交之后或执行选择之前刷新其持久性上下文。我对后者抱有希望。但我的大部分测试失败是因为(根据日志)hibernate 在插入之后和选择之前没有刷新它的持久性上下文。

这里是spring配置的spring部分:

@Configuration
@PropertySource("/db.properties")
@EnableTransactionManagement
@ComponentScan(basePackages = "repository")
public class DataAccessConfiguration {

 @Bean
    public SessionFactory sessionFactory() throws IOException {
        LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
        sessionFactoryBean.setDataSource(pool());
        sessionFactoryBean.setPackagesToScan("domain");
        sessionFactoryBean.setHibernateProperties(hibernateProperties());
        sessionFactoryBean.afterPropertiesSet();
        return sessionFactoryBean.getObject();
    }

    private Properties hibernateProperties() {
        Properties hibernateProp = new Properties();
        hibernateProp.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
        hibernateProp.put("hibernate.format_sql", true);
        hibernateProp.put("hibernate.use_sql_comments", true);
        hibernateProp.put("hibernate.show_sql", true);
        hibernateProp.put("hibernate.max_fetch_depth", 3);
        hibernateProp.put("hibernate.jdbc.batch_size", 10);
        hibernateProp.put("hibernate.jdbc.fetch_size", 50);
        hibernateProp.put("hibernate.hbm2ddl.auto", "update");
        return hibernateProp;
    }

    @Bean
    @Profile("hibernate")
    public PlatformTransactionManager transactionManager() throws IOException {
        HibernateTransactionManager manager = new HibernateTransactionManager(sessionFactory());
        manager.setDataSource(pool());

        return manager;
    }

    @Bean
    @Profile("jdbc")
    PlatformTransactionManager jdbcTransactionManager(){
        DataSourceTransactionManager manager = new DataSourceTransactionManager();
        manager.setDataSource(pool());

        return manager;
    }
}

我正在使用两个平台事务管理器——一个用于 jdbc,另一个用于休眠。我尝试删除 jdbc 管理器,只留下休眠(没有工作)。

这里是dao类:

@Repository
@Profile("hibernate")
public class UserDaoHibernate implements UserDao {

    private final SessionFactory sessionFactory;

    public UserDaoHibernate(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @Override
    public void insert(User user) {
        sessionFactory.getCurrentSession().save(user);
    }

    @Override
    public void addRole(User user, Role role) {
        NativeQuery addRoleQuery = sessionFactory.getCurrentSession()
                .createNativeQuery("INSERT INTO roles(user_name, user_role) VALUES(:user_name,:user_role)");
        addRoleQuery.setParameter("user_name",user.getUsername());
        addRoleQuery.setParameter("user_role", role.toString().toUpperCase());
        addRoleQuery.executeUpdate();
    }

    @Override
    public boolean hasRole(User user, Role role) {
        NativeQuery hasRoleQuery = sessionFactory.getCurrentSession()
                .createSQLQuery("SELECT * FROM roles WHERE user_name = :user_name AND user_role = :user_role");
        hasRoleQuery.setParameter("user_name", user.getUsername());
        hasRoleQuery.setParameter("user_role", role.toString().toUpperCase());
        return hasRoleQuery.getResultList().size() == 1;
    }

}

测试类失败的测试代码在这里:

@ContextConfiguration(classes = {DataAccessConfiguration.class})
@Rollback
@ExtendWith(SpringExtension.class)
@ActiveProfiles("hibernate")
@Transactional
public class UserDaoTest {

    @Autowired
    private UserDao sut;

    private User user = new User("NEW_USERNAME123", "NEW_PASSWORD123", LocalDate.now().minusYears(20),
            "FIRST_NAME", "LAST_NAME");

    @Test
    public void shouldAddNewRoleToUser(){
        sut.insert(user);
        assertFalse(sut.hasRole(user,Role.MEMBER));

        sut.addRole(user, Role.MEMBER);

        assertTrue(sut.hasRole(user,Role.MEMBER));
    }

}

这是我在运行测试方法后得到的输出(不包括事务 cmets):

Hibernate: 
    select
        nextval ('USER_ID_SEQUENCE')
Hibernate: 
    /* dynamic native SQL query */ SELECT
        * 
    FROM
        roles 
    WHERE
        user_name = ? 
        AND user_role = ?
Hibernate: 
    /* dynamic native SQL query */ INSERT 
    INTO
        roles
        (user_name, user_role) 
    VALUES
        (?,?)
Nov 13, 2019 3:05:31 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 0, SQLState: 23503
Nov 13, 2019 3:05:31 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: ERROR: insert or update on table "roles" violates foreign key constraint "fk_roles_user_id"
  Detail: Key (user_name)=(NEW_USERNAME123) is not present in table "users_table".

当我以编程方式提交会话时 sessionFactory.getCurrentSession().getTransaction().commit();在插入结束时一切正常。

【问题讨论】:

    标签: java spring hibernate


    【解决方案1】:

    尝试制作插入方法@Transactional或使用sessionFactory.getCurrentSession().flush()

    【讨论】:

      【解决方案2】:

      您应该使用 @Transactional 注释“shouldAddNewRoleToUser()”方法,并检查您是否在应用程序中为事务配置了 Spring 会话上下文。

      【讨论】:

      • @Transactional 在测试类上,根据文档,应该使所有方法也具有事务性。
      • 使用@Transactional 注释测试方法会导致测试在默认情况下在测试完成后自动回滚的事务中运行。如果测试类使用@Transactional 注释,则该类层次结构中的每个测试方法都将在事务中运行。未使用@Transactional(在类或方法级别)注释的测试方法将不会在事务中运行。此外,使用 @Transactional 注释但传播类型设置为 NOT_SUPPORTED 的测试将不会在事务中运行。
      • 默认情况下,测试完成后测试事务会自动回滚;但是,事务提交和回滚行为可以通过 @Commit@Rollback 注释在类级别和方法级别以声明方式进行配置。您可以在此处阅读 spring 文档 [docs.spring.io/spring/docs/current/javadoc-api/org/…
      • 我确实添加了它,尽管我不清楚为什么我需要它,但它没有做任何事情。你能解释一下为什么你认为我需要在测试方法上使用 @Transactional 吗? @Transactional 在类方法上,这意味着“在类级别,此注释默认应用于声明类及其子类的所有方法。”。我知道它有效,因为我使用 spring jdbc 运行相同的测试。这里的问题不在事务中,或者至少我在那里看不到它,但是在那个休眠中,由于某种我不明白的原因,在选择之前没有刷新它的上下文。
      • 以编程方式刷新上下文工作,但它应该默认这样做。
      【解决方案3】:

      到目前为止,我发现的关于我的问题的唯一信息是How does AUTO flush strategy works

      显然,自动刷新模式并不能保证在每次查询之前都刷新(至少不使用休眠自己的 API)。我不能 100% 确定这是不是我的情况,我会尝试找出答案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-11-22
        • 1970-01-01
        • 1970-01-01
        • 2011-12-23
        • 2014-11-16
        • 2015-11-22
        • 2013-10-31
        • 1970-01-01
        相关资源
        最近更新 更多