如何在 spring 4 hibernate 5 中使用 Persistence EntityManager 和 SessionFactory?

How to use Persistence EntityManager along with SessionFactory in spring 4 hibernate 5?

我通过在我的 DAOImpl 文件中自动装配来使用 sessionFactory。 一切正常,直到我开始在某些 DAO 方法中遇到 "Too many database connections" 问题。在寻找可能的原因和解决方案后,我意识到我可能配置错误 applicationContext.xml 并且 我使用 EntityManager 的方式不正确

下面是我的applicationContext.xml文件内容:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="  
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd  
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd  
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

    <!-- Enables the Spring MVC @Controller programming model -->

    <!-- enables cors (cross origin request) for all urls -->
    <mvc:cors>
        <mvc:mapping path="/**" />
    </mvc:cors>

    <!-- <mvc:annotation-driven /> -->

     <mvc:annotation-driven>
        <mvc:message-converters>
            <!-- Use the HibernateAware mapper instead of the default -->
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper">
                    <bean class="com.typjaipur.core.objectmapper.HibernateAwareObjectMapper" />
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

    <context:component-scan base-package="com.typjaipur" />

    <bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="classpath:messages" />
        <property name="defaultEncoding" value="UTF-8" />
    </bean>

    <bean id="propertyPlaceholder" class="com.typjaipur.core.config.EnvironmentPropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:jdbc.properties</value>
                <value>classpath:core.properties</value>
                <value>classpath:mailer.properties</value>
            </list>
        </property> 
    </bean>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/" />
        <property name="suffix" value=".jsp" />
    </bean>

    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${driver}" />
        <property name="url" value="${url}" />
        <property name="username" value="${username}" />
        <property name="password" value="${password}" />
    </bean>

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan" value="com.typjaipur.model" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.max_fetch_depth">3</prop>
                <prop key="hibernate.default_batch_fetch_size">4</prop>
                <prop key="hibernate.jdbc.fetch_size">50</prop>
                <prop key="hibernate.jdbc.batch_size">20</prop>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
            </props>
        </property>
    </bean>

    <bean id="hibernateTransactionManager"
        class="org.springframework.orm.hibernate5.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <tx:annotation-driven transaction-manager="hibernateTransactionManager" />

    <mvc:interceptors>
        <bean class="org.springframework.orm.hibernate5.support.OpenSessionInViewInterceptor">
            <property name="sessionFactory">
                <ref bean="sessionFactory" />
            </property>
        </bean>
        <mvc:interceptor>
            <mvc:mapping path="/**" />
            <!-- excluded urls -->
            <mvc:exclude-mapping path="/" />
            <bean class="com.typjaipur.interceptor.ApiAuthenticationInterceptor" />
        </mvc:interceptor>
    </mvc:interceptors>


    <!-- Enables swgger ui -->
    <mvc:resources mapping="swagger-ui.html" location="classpath:/META-INF/resources/" />
    <mvc:resources mapping="/webjars/**"
        location="classpath:/META-INF/resources/webjars/" />

    <!-- Include a swagger configuration -->
    <bean name="/applicationSwaggerConfig" class="com.typjaipur.config.SwaggerConfig" />

    <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- one of the properties available; the maximum file size in bytes -->
        <!-- <property name="maxUploadSize" value="100000"/> -->
    </bean>
</beans>

下面是我如何使用 EntityManager 的 DAOImpl 代码示例,它也可以正常工作,但我觉得它可能不正确。

@Repository
public class BusinessDetailsDAOImpl extends BaseDAOImpl<BusinessDetails, Long> implements BusinessDetailsDAO {

    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public List<BusinessDetails> searchBusiness(BusinessSearchDTO businessSearchDTO, List<Long> businessIds) {

        EntityManager entityManager = sessionFactory.getCurrentSession().getEntityManagerFactory().createEntityManager();
        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<BusinessDetails> query = criteriaBuilder.createQuery(BusinessDetails.class);
        Root<BusinessDetails> businessDetails = query.from(BusinessDetails.class);

        List<Predicate> predicates = new ArrayList<Predicate>();
...//rest of code

我在这一点上很难避免sessionFactory,因为我在我的项目中一直使用它。无论如何,我可以通过它配置我的 xml 文件以允许我同时使用 EntityManagerSessionFactory 吗?

我看到了几个配置 EntityManager 的示例,但其中 none 在 xml 文件中添加了与 SessionFactory 相关的任何行。所以我对此很困惑。

使用 LocalContainerEntityManagerFactoryBean 创建 EntityManager 而不是使用 LocalSessionFactoryBean,因此您无需调用 sessionFactory.getCurrentSession().getEntityManagerFactory().createEntityManager() 来获取 entityManager :

  1. 在 spring 配置文件中将当前配置替换为:
<!-- Create a datasource -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">

    <property name="driverClassName" value="${driver}" />
    <property name="url" value="${url}" />
    <property name="username" value="${username}" />
    <property name="password" value="${password}" />

</bean>

<!-- Create an Hibernate to Jpa adapter -->
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">

    <property name="generateDdl" value="true" />
    <property name="showSql" value="false" />
    <property name="database" value="MYSQL" />

</bean>

<!-- persistenceUnitManager is optional -->
<bean id="persistenceUnitManager" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">

    <property name="defaultDataSource" ref="dataSource"/>

</bean>

<!-- create entityManagerFactory -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">

    <property name="persistenceUnitManager" ref="persistenceUnitManager"/>
    <property name="jpaVendorAdapter" ref="jpaVendorAdapter" />

    <property name="jpaProperties">
        <props>
            <prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
        </props>
    </property>

</bean>

<!-- and create transactionManager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
  1. 像这样使用它:
@Repository
public class BusinessDetailsDAOImpl extends BaseDAOImpl<BusinessDetails, Long> implements BusinessDetailsDAO {

    @PersistenceContext
    protected EntityManager entityManager; 

    @Override
    public List<BusinessDetails> searchBusiness(BusinessSearchDTO businessSearchDTO, List<Long> businessIds) {

        // use directly entityManager instead of sessionFactory.getCurrentSession().getEntityManagerFactory().createEntityManager();

        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

        // ...

}

编辑:更新您的配置如下:

<property name="jpaProperties">
    <props>
        <prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
        <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>

        <!-- add this line -->
        <prop key="hibernate.enable_lazy_load_no_trans">true</prop>
    </props>
</property>