Сделка и откат весной с JPA - PullRequest
       3

Сделка и откат весной с JPA

1 голос
/ 26 сентября 2011

Привет друзья из StackOverflow, я не понимаю, как откатиться, я прочитал документацию Spring, но я до сих пор не понимаю.По сути, я собираюсь сохранить объект в БД (с первичным ключом вручную) до конца, объект вставлен в БД.Но когда вы сохраняете объект снова с тем же первичным ключом, я вызвал исключение, и это справедливо, нарушение ограничения уникальности.В этом случае я получаю откат транзакции и предупреждаю вас о проблеме, и продолжаю запускать программу

Это мой класс:

public class ServiceDaoImpl{

    @PersistenceContext (unitName="fb-persistence")
    protected EntityManager em;

    public void setEntityManager(EntityManager entityManager) {
        this.em = entityManager;
    }

    @Transactional(readOnly=false)
    public void write(Service entity){
        try {
            em.persist(entity);
            em.flush();
        } catch(Exception ex) {
            ex.printStackTrace();
        }
    }

    /*
    * .. other method
    */
}

И это стек ошибок:

javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1214)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1147)
    at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1153)
    at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:798)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
    at $Proxy27.flush(Unknown Source)
    at it.synclab.fb.jpa.dao.impl.GenericDaoImpl.write(GenericDaoImpl.java:236)
    at it.synclab.fb.jpa.dao.impl.EnteDaoImpl.write(EnteDaoImpl.java:1)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at $Proxy34.write(Unknown Source)
    at it.synclab.fb.jpa.test.ConfigTest.insertEnte(ConfigTest.java:47)
    at it.synclab.fb.jpa.test.ConfigTest.main(ConfigTest.java:32)
Caused by: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
    at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:268)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
    at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:795)
    ... 21 more
Caused by: java.sql.BatchUpdateException: ORA-00001: violata restrizione di unicità (FLUSSIBATCH.SYS_C008896)

и мои файлы конфигурации (persistence.xml и applicationContext.xml):

Это applicationContext.xml: ...

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="fb-persistence" />
    </bean>

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

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

    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />


    <bean name="serviceDaoImpl" class="it.synclab.fb.jpa.dao.impl.ServiceDaoImpl" />
...

This is the persistence.xml:
<persistence>
    <persistence-unit name="fb-persistence" transaction-type="RESOURCE_LOCAL">  
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <mapping-file>META-INF/orm.xml</mapping-file>
        <class>it.entity.Service</class>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
            <property name="hibernate.connection.driver_class" value="oracle.jdbc.driver.OracleDriver"/>  
            <property name="hibernate.show_sql" value="true"/>  
            <property name="hibernate.connection.username" value="############"/>  
            <property name="hibernate.connection.password" value="############"/>  
            <property name="hibernate.connection.url" value="jdbc:oracle:thin:@localhost:1521:XE"/> 
        </properties>
   </persistence-unit>
</persistence>
        at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:629)
        at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:9467)
        at oracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:211)
        at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
        at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
        ... 27 more
    Exception in thread "main" org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
        at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:476)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
        at $Proxy34.write(Unknown Source)
        at it.synclab.fb.jpa.test.ConfigTest.insertEnte(ConfigTest.java:47)
        at it.synclab.fb.jpa.test.ConfigTest.main(ConfigTest.java:32)
    Caused by: javax.persistence.RollbackException: Transaction marked as rollbackOnly
        at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:73)
        at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:467)
        ... 9 more

Почемудолжно быть сложно?Я просто не понимаю ... Я надеюсь, что некоторые из вас имели ту же проблему и решили

Ответы [ 2 ]

4 голосов
/ 26 сентября 2011

Я не знаю, правильно ли я понимаю ваш вопрос, но ваша проблема может быть в ServiceDaoImpl обработке исключений:

try {
     em.persist(entity);
     em.flush();
} catch(Exception ex) {
     ex.printStackTrace();
}

Это очень плохая практика (тм). Не ловите исключение, но позвольте ему всплывать из вашего метода. Таким образом:

  1. Механизм демаркации транзакции будет перехватывать исключение и помечать транзакцию как только откат
  2. Вы не будете игнорировать исключение (да, ловить и регистрировать почти так же плохо, как глотать)
  3. Скорее всего, исключение будет перехвачено на более высоком уровне и правильно зарегистрировано (с использованием SLF4J или подобного), и у вас не будет этого шаблона.

Итак, вкратце:

public class ServiceDaoImpl{

    @PersistenceContext (unitName="fb-persistence")
    private EntityManager em;

    @Transactional(readOnly=false)
    public void write(Service entity){
        em.persist(entity);
        em.flush();
    }

}

Обратите внимание, что вам не нужен сеттер для EntityManager, и поле может быть приватным.

0 голосов
/ 26 сентября 2011

Добавьте блок try catch в ваш метод записи и сгенерируйте исключение в случае ошибки.

Поместите атрибут rollbackFor или rollbackForClassname в аннотацию @Transactional для исключения, которое вы поднимаетеесли вы хотите контролировать события отката.

...