没有关于Spring Data的事务性EntityManager,@ Transaction不起作用

时间:2015-09-15 08:30:00

标签: java spring transactions spring-data spring-data-jpa

简而言之,我在尝试调用从 BaseRepository 扩展的接口中定义的方法时获得No transactional EntityManager available; nested exception is javax.persistence.TransactionRequiredException: No transactional EntityManager available

首先,我将公开与数据库相关的Spring配置。 这是我的spring-database.xml,包含与db相关的东西:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xmlns:context="http://www.springframework.org/schema/context" 
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/data/jpa
    http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

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

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <!-- <property name="location" value="classpath:application.properties" /> -->
        <property name="ignoreUnresolvablePlaceholders" value="false"/>
        <property name="ignoreResourceNotFound" value="false"/>     
        <property name="locations">
            <list>
                <value>classpath:application.properties</value>
            </list>
        </property>    
    </bean>



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

        <property name="dataSource" ref="dataSource" />
        <property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence" />

        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
        </property>

        <property name="packagesToScan" >
            <list>
                <value>com.cmc.articauno.dao.entidades</value>
            </list>
        </property>

        <property name="jpaProperties">
            <props>

                <prop key="hibernate.default_schema">${database.schema}</prop>        
                <prop key="hibernate.dialect">${database.hibernate.dialect}</prop>         
                <prop key="hibernate.show_sql">${database.hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${database.hibernate.format_sql}</prop>

            </props>
        </property>
    </bean>



    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">

        <property name="driverClass" value="${database.driverClassName}" />
        <property name="jdbcUrl" value="${database.connectionUrlSchema}" />
        <property name="user" value="${database.username}" />
        <property name="password" value="${database.password}" />

        <property name="maxPoolSize" value="${database.maxPoolSize}" />
        <property name="minPoolSize" value="${database.minPoolSize}" />
        <property name="maxStatements" value="${database.maxStatements}" />
        <property name="testConnectionOnCheckout" value="${database.testConnection}" />

    </bean>




    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
        <property name="dataSource" ref="dataSource"/>
    </bean>



    <tx:annotation-driven 
        transaction-manager="transactionManager" 
        proxy-target-class="true" />



    <jpa:repositories 
        transaction-manager-ref="transactionManager"
        base-package="com.my.app.dao.repository" 
        factory-class="com.my.app.dao.repository.base.BaseRepositoryFactoryBean" />



    <!-- jpa auditor aware -->
    <jpa:auditing auditor-aware-ref="customAuditorAware" />


</beans>

我使用基于接口的Spring Data存储库,我的所有存储库都扩展自 BaseRepository

BaseRepository.java

@NoRepositoryBean
public interface BaseRepository <T extends BaseEntity, ID extends Serializable> extends JpaRepository<T, ID>
{   

    public T findByIdentificador(String identificador);

    public boolean deleteByIdentificador(String identificador);

    public boolean deleteByIdentificador(String identificador, boolean permanentDelete);

    boolean existsByIdentificador(String identificador);

}

上面的接口有一个实现:

BaseRepositoryImpl

@NoRepositoryBean
public class BaseRepositoryImpl<T extends BaseEntity, ID extends Serializable> 
    extends SimpleJpaRepository<T, ID>
    implements BaseRepository<T, ID>

{

    private EntityManager entityManager;
    private final Class<T> clazz;
    private String entityName;


    public BaseRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
        super(domainClass, entityManager);
        this.entityManager = entityManager;
        this.clazz = domainClass;       
        this.entityName = this.clazz.getSimpleName();
    }


    @Override
    public T findByIdentificador(String identificador) {
        List<T> result = new ArrayList<T>();
        String jsql = String.format("select t from %s t where t.identificador='%s' "
                + "and t.activo='"+DaoConstants.ACTIVO+"'", 
                clazz.getSimpleName(), identificador);
        Query query = entityManager.createQuery(jsql);
        result = query.getResultList(); 

        if (result != null && result.size() > 0 )
            return result.get(0);
        return null;
    }


    /* borrado logico */
    @Transactional
    @Override
    public boolean deleteByIdentificador(String identificador) {

        List<T> result = null;
        String jsql = String.format("update %s t set t.activo='0'  where t.identificador='%s'", 
                clazz.getSimpleName(), identificador);
        Query query = entityManager.createQuery(jsql);
        return query.executeUpdate() > 0; 
    }


    @Override
    public boolean existsByIdentificador(String identificador) {

        List<T> result = new ArrayList<T>();
        String jsql = String.format("select t from %s t where t.identificador='%s' "
                + "and t.activo='"+DaoConstants.ACTIVO+"'", 
                clazz.getSimpleName(), identificador);
        Query query = entityManager.createQuery(jsql);
        result = query.getResultList(); 

        return result != null && result.size() > 0;
    }



    /* hace borrado fisico */
    @Override
    @Transactional
    public boolean deleteByIdentificador(String identificador, boolean permanentDelete) {

        if (!permanentDelete)
            return false;

        List<T> result = null;
        String jsql = String.format("select t from %s t where t.identificador='%s'", 
                clazz.getSimpleName(), identificador);
        Query query = entityManager.createQuery(jsql);
        result = query.getResultList(); 

        if (result != null && result.size() > 0)  {
            T entBorrar = result.get(0);
            //entityManager.remove(entBorrar);
            entityManager.remove(entityManager.contains(entBorrar) ? entBorrar : entityManager.merge(entBorrar));
            entityManager.flush();
            return true;
        }
        return false;
    }

}

所有基础存储库都是因为我需要所有存储库的通用功能。后来所有的新回购都从基地延伸出来。我尝试使用的存储库是:

public interface RelPerFormRepository extends BaseRepository<RelPerFormEntity, Long>
{

    @Query("select t from RelPerFormEntity t where t.idAutPersona = ?1 and t.idFormulario = ?2 order by createdDate desc")  
    public List<RelPerFormEntity> findAllByPersonaAndFormulario(Long idPersona, Long idFormulario);

    @Modifying
    @Transactional
    @Query("delete from RelPerFormEntity r where r.idAutPersona = ?1 and r.idFormulario = ?2")
    public Long deletePreviousFormResponses(Long idAutPersona, Long idFormulario);


    @Transactional
    public void deleteByIdAutPersonaAndIdFormulario(Long idAutPersona, Long idFormulario);
}

@Transactional和@Modifying取消注释我得到了这个例外,但是如果我删除了注释,我会在问题的开头显示异常。

Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy86]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy86
    at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:212)
    at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:109)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:447)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:333)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:293)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:422)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.postProcessObjectFromFactoryBean(AbstractAutowireCapableBeanFactory.java:1719)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.getObjectFromFactoryBean(FactoryBeanRegistrySupport.java:113)
    ... 31 more

0 个答案:

没有答案