1
votes

I have the next configuration in a 'Standalone Java SWING application'. I have the problem: my service runs without errors, execute the DAO delete method, but doesn't commit the delete:

Persistence.xml

<persistence-unit name="springappPU" transaction-type="RESOURCE_LOCAL">
</persistence-unit>

spring-config.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:p="http://www.springframework.org/schema/p"
   xmlns:context="http://www.springframework.org/schema/context"
   xmlns:tx="http://www.springframework.org/schema/tx"

   xsi:schemaLocation=" http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-      3.0.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-3.0.xsd
                        http://www.springframework.org/schema/tx
                        http://www.springframework.org/schema/tx/spring-tx.xsd">

<context:annotation-config/>
<context:component-scan base-package="gestionclinicaecocitas">
</context:component-scan>
<tx:annotation-driven transaction-manager="transactionManager" />

<!-- holding properties for database connectivity /-->
<context:property-placeholder location="classpath:jdbc.properties"/>

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  <property name="driverClassName" value="${jdbc.driverClassName}"/>
  <property name="url" value="${jdbc.url}"/>
  <property name="username"  value="${jdbc.username}"/>
  <property name="password" value="${jdbc.password}"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory"/>


<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource"
p:jpaVendorAdapter-ref="jpaAdapter">
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
<property name="persistenceUnitName" value="springappPU"></property>
</bean>

<bean id="jpaAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
p:database="${jpa.database}"
p:showSql="${jpa.showSql}"/>

In the main() of my project, initialize the spring context, and get a 'service' loader class:

ClassPathXmlApplicationContext  ac= new ClassPathXmlApplicationContext("spring-config.xml");
ac.getBean(SpringServiceLoader.class);

My SpringServiceLoader:

@Service
public class SpringServiceLoader{

    @Autowired
    private CalendarService calendarService;

The method of my serviceInterface marked as @Transactional

public interface CalendarioService {
@Transactional
    public void deleteDays();
}

The implementation of the service calling dao delete method

@Service("calendarService")
public class CalendarioServiceImpl implements CalendarioService{


@Autowired
private DaysDaoImpl daysDao;

@Override
public void deleteDays{
        daysDao.deleteById(1);
}

}

And finally the Dao structure:

@Repository
public class DaysDaoImpl extends GenericDaoImpl< Days > {

public DaysDaoImpl(){
  setClazz(Days.class );
}

GenericDao class:

import java.io.Serializable;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

public abstract class GenericDaoImpl< T extends Serializable> {//implements GenericDao<T>{

@PersistenceContext
protected EntityManager em;
private Class< T > clazz;


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

(.....)   

public void deleteById( Long entityId ){
    this.em.remove(this.em.getReference(clazz, entityId));

}
}

My entity class:

@Entity
@Table(name="calendar_days")
public class Days implements java.io.Serializable {

@EmbeddedId
private DaysId id;

(....)

I've also tryed an HQL query instead of calling a basic CRUD method and I get the error:

TransactionRequiredException: Executing an update/delete query

 Query query = this.em
            .createQuery("delete from Days d where d.id.date < :fecha");
    query.setParameter("fecha", fecha);
    query.executeUpdate();

If I try to get the em transaction to make a begin/commit manually, the error changes to:

Not allowed to create transaction on shared EntityManager

Thanks

3
What happens when you move the @Transactional annotation from the interface to CalendarioServiceImpl? - Ori Dar
Nothing, I think i have some erros in configuration, because @Transacional doesn't work in any class. I've tried to put the annotation in the DAO and in the ServiceImpl but the behaviour is the same - arturo.galan
Post the code that is actually invoking the deleteDays method (or other transactional method). Small suggestion, instead of reinventing the wheel with your GenericDao use Spring Data JPA. - M. Deinum

3 Answers

0
votes

Finally I found a solution. The interface of the CalendarService marked as @Transactional works, the problem was that both SpringServiceLoader and CalendarService were defined as @Service.

I have rename the CalendarService to @Component stereotype, that is autowired to SpringServiceLoader marked as @Service stereotype, and now the transactions works fine automatically.

Thanks everybody for the support! I'll take a look to Spring Data

0
votes

Use

T entity = em.find(persistentClass, id);

to get the entity. And then call

em.remove(entity);

Or shorten this record in one line.

UPDATE (thanks to @M.Deinum)

-1
votes

A very simple way to fix this is add @Transactional to you main() method.