【问题标题】:JPA DAO pattern doesn't commitJPA DAO 模式不提交
【发布时间】:2014-02-03 16:46:32
【问题描述】:

我在“独立 Java SWING 应用程序”中有下一个配置。 我有问题:我的服务运行没有错误,执行DAO删除方法,但没有提交删除:

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}"/>

在我项目的main()中,初始化spring上下文,得到一个'service'加载器类:

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

我的 SpringServiceLoader:

@Service
public class SpringServiceLoader{

    @Autowired
    private CalendarService calendarService;

我的serviceInterface的方法标记为@Transactional

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

服务调用dao删除方法的实现

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


@Autowired
private DaysDaoImpl daysDao;

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

}

最后是道结构:

@Repository
public class DaysDaoImpl extends GenericDaoImpl< Days > {

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

GenericDao 类:

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));

}
}

我的实体类:

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

@EmbeddedId
private DaysId id;

(....)

我也尝试了 HQL 查询而不是调用基本的 CRUD 方法,但我得到了错误:

TransactionRequiredException:执行更新/删除查询

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

如果我尝试让 em 事务手动开始/提交,错误将变为:

不允许在共享 EntityManager 上创建事务

谢谢

【问题讨论】:

  • 将@Transactional注解从接口移动到CalendarioServiceImpl会发生什么?
  • 没什么,我认为我的配置有一些错误,因为@Transacional 在任何课程中都不起作用。我尝试将注释放在 DAO 和 ServiceImpl 中,但行为是相同的
  • 发布实际调用deleteDays 方法(或其他事务方法)的代码。小建议,不要用GenericDao 重新发明轮子,而是使用Spring Data JPA。

标签: java spring jpa spring-transactions


【解决方案1】:

终于找到了解决办法。 标记为@Transactional 的CalendarService 的接口工作,问题是SpringServiceLoader 和CalendarService 都被定义为@Service。

我已将 CalendarService 重命名为 @Component 原型,即自动连接到标记为 @Service 原型的 SpringServiceLoader,现在事务自动正常工作。

感谢大家的支持! 我去看看Spring Data

【讨论】:

    【解决方案2】:

    使用

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

    获取实体。然后调用

    em.remove(entity);
    

    或者将这条记录缩短为一行。

    更新(感谢@M.Deinum)

    【讨论】:

    • 服务层而不是 dao 层应该是事务边界。所以不要把注解放在dao上。
    【解决方案3】:

    解决此问题的一个非常简单的方法是将@Transactional 添加到您的 main() 方法中。

    【讨论】:

    • 谢谢解答,问题是我的main()方法类在spring上下文之外,因为是SWING应用。 ¿我可以将不是 Spring 托管 bean 的类设置为 @Transactional 吗?
    • @user3179334 哦,所以你需要将注解 @Transactional 从方法移到 CalendarioService
    猜你喜欢
    • 2011-01-07
    • 2023-03-03
    • 1970-01-01
    • 2015-08-08
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 2013-04-19
    相关资源
    最近更新 更多