mysql - 为什么事务完成后 hibernate session 没有关闭

标签 mysql spring hibernate transactional

我使用 Spring + hibernate 进行数据库访问(mysql)。对于只读方法,我需要将底层连接状态更改为只读,以便我可以将读取操作发送给从属(在主从中)。

在下面的代码中,我使用 hibernate session 在 getEmployer 方法中将底层连接更改为只读。这部分工作正常。 我假设在 getEmployer 方法执行后, session 将关闭(因为它由 @Transactional 注释)。因此,当调用下面的 saveEmployer 方法时,将启动一个新 session 。因此 saveEmployer 中的 connection.isReadOnly() 应该返回 false。但是当我调用 saveEmployer 方法时(在调用 getEmployer 方法之后),connection.isReadOnly 结果是 true .

我相信 session 不会在 getEmployer 方法执行后关闭。我的理解是,当方法用@Transactional注解时,session会在事务提交后关闭。我在这里做错了什么吗?为什么 saveEmployer 方法中的 connection.isReadOnly()true?谢谢。

@Service
class public EmployerServiceImpl implements EmployerService{
    @Inject EmployerRepository employerRepository;
    @PersistenceContext
    EntityManager em;

    @Transactional
    public void getEmployer(long id){
        Session session = em.unwrap(Session.class);
        session.doWork(new Work(){
            @Override
            public void execute(Connection connection) throws SQLException{
                connection.setReadOnly(true);
            }
        });
        ......
        this.employerRepository.get(id);
    }

    @Transactional
    public void saveEmployer(){
        Session session = em.unwrap(Session.class);
        session.doWork(new Work(){
            @Override
            public void execute(Connection connection) throws SQLException{
               log.warn("connection status = " + connection.isReadOnly());
            }
        });
        ......
        this.employerRepository.save(employer);
    }
}

这里是根上下文中dataSource的java配置

@Bean
public DataSource springJpaDataSource()
{
    JndiDataSourceLookup lookup = new JndiDataSourceLookup();
    return lookup.getDataSource("jdbc/SpringJpa");
}

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean()
{
    Map<String, Object> properties = new Hashtable<>();
    properties.put("javax.persistence.schema-generation.database.action",
            "none");
    properties.put("hibernate.search.default.directory_provider",
            "filesystem");
    properties.put("hibernate.search.default.indexBase", "../searchIndexesApplyJob");

    HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
    adapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect");

    LocalContainerEntityManagerFactoryBean factory =
            new LocalContainerEntityManagerFactoryBean();
    factory.setJpaVendorAdapter(adapter);
    factory.setDataSource(this.springJpaDataSource());
    factory.setPackagesToScan("com.peer.site.entities", "com.peer.site.message",
            "com.peer.site.converters");
    factory.setSharedCacheMode(SharedCacheMode.ENABLE_SELECTIVE);
    factory.setValidationMode(ValidationMode.NONE);
    factory.setJpaPropertyMap(properties);
    return factory;
}

@Bean
public PlatformTransactionManager jpaTransactionManager()
{
    return new JpaTransactionManager(
            this.entityManagerFactoryBean().getObject()
    );
}

最佳答案

也许使用 @Transactional(readonly = true) 更容易工作 like explained here而不是在 native session 中手动设置此值。

如果 session 将被 Spring 重用取决于(可能是嵌套的)事务划分和/或您的调用在哪个线程中执行。它可以被同一个线程重用(存储在一个 ThreadLocal 中)。 Here您可以找到更多信息。

关于mysql - 为什么事务完成后 hibernate session 没有关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43617798/

相关文章:

php - 具有 1 对 1 关系的 SQL 删除

java - Maven-properties-filtering-like 用于 Java 注释?

postgresql - JPA:如何从其他表中删除用户和所有引用?

mysql - 将 id 替换为数据库中的名称

mysql - Redis和mysql的qps是多少

java - Apache 客户端缓存 jar

java - 双向多对一映射

java - 通过spring mvc在hibernate中使用@ElementCollection检索表会导致表的多个实例

mysql - 如何使用连接在不使用 max 函数的情况下显示每个部门的最高工资

java - 使用私有(private)构造函数对 spring 组件进行单元测试,无需注入(inject)