如果可以改动代码,可以直接更改获取Session的方式,如果不方便改动代码,就配置Bean。
直接获取Session
可以直接更改获取Session的代码:
@Autowired
private EntityManagerFactory entityManagerFactory;
public Session getSession() {
return entityManagerFactory.unwrap(SessionFactory.class).getCurrentSession();
// 或
//return entityManagerFactory.unwrap(SessionFactory.class).openSession();
}
getCurrentSession需配置current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext,且需要声明事务,openSession需要手动关闭Session。
SpringData JPA支持配置
Hibernate5.2.x以上版本:
@Configuration
@EnableTransactionManagement
public class HibernateConfig {
@Autowired
private DataSource dataSource;
@Autowired
private JpaProperties jpaProperties;
@Primary
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder) {
return builder.dataSource(dataSource)
.properties(jpaProperties.getProperties())
.packages("com.demo.entity") // 设置实体类
.build();
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactory(builder).getObject());
}
@Bean
public SessionFactory sessionFactory(@Qualifier("entityManagerFactory") EntityManagerFactory emf){
return emf.unwrap(SessionFactory.class);
}
}
Hibernate5.2版本改动较大,建议旧版代码使用5.2以下版本,可以在pom.xml中指定Hibernate的版本:
<properties>
// other...
<hibernate.version>5.0.12.Final</hibernate.version>
</properties>
<dependencies>
// other...
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
</dependencies>
配置SessionFactory:
@Configuration
@EnableTransactionManagement
public class HibernateConfig {
@Autowired
private EntityManagerFactory entityManagerFactory;
@Bean
public SessionFactory sessionFactory() {
if (entityManagerFactory.unwrap(SessionFactory.class) == null) {
throw new NullPointerException("factory is not a hibernate factory");
}
return entityManagerFactory.unwrap(SessionFactory.class);
}
}
使用方法:
@Autowired
private SessionFactory sessionFactory;
非SpringData JPA支持配置
@Configuration
public class HibernateConfig {
@Autowired
private DataSource dataSource;
@Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
localSessionFactoryBean.setDataSource(dataSource);
Properties properties = new Properties();
properties.put("hibernate.dialect","org.hibernate.dialect.MySQL5Dialect");
properties.put("hibernate.show_sql", "true");
properties.put("hibernate.hbm2ddl.auto","none");
properties.put("hibernate.current_session_context_class","org.springframework.orm.hibernate5.SpringSessionContext");
localSessionFactoryBean.setPackagesToScan("com.demo.entity");
localSessionFactoryBean.setHibernateProperties(properties);
return localSessionFactoryBean;
}
}
使用方法:
@Autowired
private SessionFactory sessionFactory;
getCurrentSession非事务读数据库
旧版SpringMVC代码使用getCurrentSession来获取Session,这样不用手动去关闭Session,但是这种方式访问数据库都必须配置事务,不配置事务会出现错误:Could not obtain transaction-synchronized Session for current thread。然而所有方法都配置事务,如果使用了数据库读写分离中间件(如阿里的PolarDB),则无法分流到只读数据库。这种情况下可配置OpenSessionInViewFilter来使Controller在没有配置事务的情况下读取数据库。
@WebFilter(filterName="openSessionFilter",urlPatterns="/*")
@Order(1)
public class OpenSessionFilter implements Filter {
private final OpenSessionInViewFilter filter;
public OpenEntityManagerInViewFilter() {
filter = new OpenSessionInViewFilter();
filter.setSessionFactoryBeanName("sessionFactory");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
filter.init(filterConfig);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
filter.doFilter(request, response, chain);
}
@Override
public void destroy() {
filter.destroy();
}
}
在启动类添加注解@ServletComponentScan
@ServletComponentScan(basePackages = {"com.demo.filter"})
@SpringBootApplication
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}