복붙노트

[SPRING] Hibernate에서 불필요한 쿼리 - MySql

SPRING

Hibernate에서 불필요한 쿼리 - MySql

나는 spring / hibernate / mysql을 사용 중이며 현재 spring-hibernate.xml에 다음 설정을 사용하고있다.

나는 "select @@ session.tx_read_only"및 "select @@ session.tx_isolation"쿼리가 실제 데이터에 대한 select 문 다음에 DB로 전송되는 것을 지속적으로보고 있습니다.

이러한 각각의 쿼리는 20-25ms 시간을 추가하며 Oauth 로그인의 DB에 대해 70 개의 쿼리가 실행됩니다. 어떻게 그들을 제거 할 수 있습니까?

statelessSessions를 시도하고 쿼리가 사라졌으며 응용 프로그램 쿼리에 대한 쿼리의 수를 줄일 수 있었지만 statelessSessions를 사용하면 첫 번째 수준의 캐시를 제공하지 않으며 데이터 별칭 효과에 취약하다는 사실을 읽었습니다.

"select @@ session.tx_read_only"을 피하고 여러 번 실행중인 @@ session.tx_isolation을 선택하십시오. (추출에 대한 DB에 액세스하기 위해 일반 DAO를 사용합니다) findById, findAll, getNamedQueryAndNamedParam 메소드를 사용하고 있습니다. ...

spring-hibernate.xml

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    <property name="driverClass" value="com.mysql.jdbc.Driver" />
    <property name="jdbcUrl" value="${JDBC_CON_STRING}" />
    <property name="user" value="${USER_NAME}" />
    <property name="password" value="${USER_PASSWORD}" />
</bean>

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="com.model" />
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.format_sql">true</prop>
            <prop key="hibernate.hbm2ddl.auto">false</prop>
            <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
            <prop key="hibernate.cache.use_query_cache">true</prop>
            <prop key="hibernate.cache.use_second_level_cache">true</prop>
            <prop key="hibernate.cache.provider_configuration_file_resource_path">ehcach.xml</prop>
            <prop key="hibernate.auto_close_session">true</prop>
    </property>
    <property name="mappingResources">
        <list>
            <value>named-queries.xml</value>
            <value>native-named-queries.xml</value>
        </list>
            </property>
</bean>

<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
<property name="dataSource" ref="dataSource" />
</bean>

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

<bean id="testClassDao" class="com.dao.GenericHibernateDao">
    <property name="clazz" value="com.model.TestClass" />
</bean>

GenericHibernateDao.java

@Repository
@Scope("prototype")
public class GenericHibernateDao<T, PK extends Serializable> implements GenericDao<T, PK> {

private Class<T> clazz;

@Autowired
private SessionFactory sessionFactory;

public void setClazz(final Class<T> clazzToSet) {
    this.clazz = clazzToSet;
}

protected Session getSession() {
    return sessionFactory.getCurrentSession();
}

protected Session getOpenSession() {
    return sessionFactory.openSession();
}

@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public T findById(PK id) {
    Object obj = null;
    obj = getSession().get(clazz, id);
    //obj = getStatelessSession().get(clazz, id);
    return (T) obj;
}

@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public List<T> findAll() {

    String queryString = "from " + clazz.getName();
    Query query = getSession().createQuery(queryString);
    query.setCacheable(true);
    List<T> list = query.list();
    return list;
}

@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public List<T> getNamedQuery(String queryName) {
    Query query = getSession().getNamedQuery(queryName);
    //Query query = getStatelessSession().getNamedQuery(queryName);
    query.setCacheable(true);
    List<T> results = query.list();
    return results;
}

@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public List<T> getNamedQueryAndNamedParam(String queryName, String paramName, Object value) {
    Query query = getSession().getNamedQuery(queryName).setString(paramName, value.toString());
    query.setCacheable(true);
    List<T> results = query.list();
    return results;
}
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public PK save(T persistenceObject) {
    Serializable save = getSession().save(persistenceObject);
    return (PK) save;
}

@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public void saveOrUpdate(T persistenceObject) {
    getSession().saveOrUpdate(persistenceObject);
}

public void saveOrUpdateBulk(Collection<T> persistenceObject) {
    Session session = getOpenSession();
    Transaction tx = session.beginTransaction();
    int i = 0;
    for (Iterator<T> iterator = persistenceObject.iterator(); iterator.hasNext();) {
        i++;
        session.saveOrUpdate(iterator.next());
        if (i % 100 == 0) {
            session.flush();
            session.clear();
        }
    }
    tx.commit();
    session.close();
}

@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public boolean delete(PK id) {
    Object findById = findById(id);
    if (findById != null) {
        getSession().delete(findById);
        return true;
    }
    return false;
}
}

해결법

  1. ==============================

    1.추가 쿼리를 제거하려면 AFAIK를 사용하여 @Transactional 주석에 대한 모든 수정자를 제거하십시오. 당신이 격리 수준을 READ_COMMITED로 제한하기 위해 지불하는 가격은 Hibernate가 데이터베이스가 더티 상태인지를 결정하기 위해 여분의 쿼리를 수행 할 필요가 있다는 것이다. 90 %의 경우,이 수식어는 불필요합니다. Hibernate는 이러한 제한 사항을 추가하지 않고도 데이터가 깨끗하게 유지되도록하는 데 매우 유용합니다.

    추가 쿼리를 제거하려면 AFAIK를 사용하여 @Transactional 주석에 대한 모든 수정자를 제거하십시오. 당신이 격리 수준을 READ_COMMITED로 제한하기 위해 지불하는 가격은 Hibernate가 데이터베이스가 더티 상태인지를 결정하기 위해 여분의 쿼리를 수행 할 필요가 있다는 것이다. 90 %의 경우,이 수식어는 불필요합니다. Hibernate는 이러한 제한 사항을 추가하지 않고도 데이터가 깨끗하게 유지되도록하는 데 매우 유용합니다.

    격리가 READ_COMMITTED인지 확인하는 것이 절대적으로 필요한 경우 추가 쿼리에 대해서는 아무 것도 할 수 없습니다.

    이러한 쿼리를 제거하기 위해 StatelessSession으로 이동하는 것은 정확하게 당신이 지적한 이유에 대한 나쁜 생각입니다. 실제로, StatelessSession을 사용하는 유일한 타당한 이유는 삽입이 발생하는 동안 읽을 수없는 데이터의 대량 일괄 삽입에 대한 것입니다.

  2. from https://stackoverflow.com/questions/24276196/unnecessary-queries-in-hibernate-mysql by cc-by-sa and MIT license