我使用JPA和Hibernate进行持久化,并有Spring Boot的一些自动配置帮助。我正在运行一个JUnit测试,它在JPA Repository中保存了一些记录。然后它实例化一个新的Spring托管线程,并由ThreadPoolTaskExecutor运行。该线程将尝试获取先前添加的记录,但没有成功。
以下是测试和可运行线程的相关代码:
public class RtmpSpyingTests extends AbstractTransactionalJUnit4SpringContextTests {
@Autowired
ThreadPoolTaskExecutor rtmpSpyingTaskExecutor;
@Autowired
ApplicationContext ctx;
@Autowired
RtmpSourceRepository rtmpRep;
@Test
public void test() {
RtmpSource rtmpSourceSample = new RtmpSource("test");
rtmpRep.save(rtmpSourceSample);
rtmpRep.flush();
List<RtmpSource> rtmpSourceList = rtmpRep.findAll(); // Here I get a list containing rtmpSourceSample
RtmpSpyingTask rtmpSpyingTask = ctx.getBean(RtmpSpyingTask.class,
"arg1","arg2");
rtmpSpyingTaskExecutor.execute(rtmpSpyingTask);
}
}
public class RtmpSpyingTask implements Runnable {
@Autowired
RtmpSourceRepository rtmpRep;
String nameIdCh;
String rtmpUrl;
public RtmpSpyingTask(String nameIdCh, String rtmpUrl) {
this.nameIdCh = nameIdCh;
this.rtmpUrl = rtmpUrl;
}
public void run() {
// Here I should get a list containing rtmpSourceSample, but instead of that
// I get an empty list
List<RtmpSource> rtmpSource = rtmpRep.findAll();
}
}
因此,在我插入了rtmpSourceSample对象之后,我可以检查它是否已从测试方法中插入,它确实在rtmpSourceList列表中。然而,当我从线程中执行同样的操作时,我得到的是一个空列表。
这是我spring-context.xml配置文件中的JPA/HiberNate配置:
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MVCC=true" />
<property name="username" value="user" />
<property name="password" value="user" />
</bean>
<!-- Define the JPA transaction manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<constructor-arg ref="entityManagerFactory" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="vendorAdaptor" />
<property name="packagesToScan" value="guiatv.persistence.domain" />
</bean>
<bean id="abstractVendorAdaptor" abstract="true">
<property name="generateDdl" value="true" />
<property name="database" value="H2" />
<property name="showSql" value="false" />
</bean>
<bean id="entityManager"
class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="vendorAdaptor"
class="org.html" target="_blank">springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
parent="abstractVendorAdaptor">
</bean>
<context:annotation-config />
<tx:annotation-driven />
<context:component-scan base-package="guiatv.persistence" />
请注意,持久性单元。xml是不需要的,因为我使用的是Spring Boot。
最后,这是任务执行器 Bean 和可运行线程的 xml 配置:
<bean id="rtmpSpyingTaskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="5" />
<property name="queueCapacity" value="5" />
</bean>
<bean id="rtmpSpyingTask" class="guiatv.realtime.rtmpspying.RtmpSpyingTask"
scope="prototype">
<constructor-arg ref="rtmpSpyingTaskExecutor" />
</bean>
我一直在寻找有关这个有问题的 Spring 的持久性和线程组合的主题。到目前为止,我找到的解决方案之一是使用 @Transactional 方法创建一些@Service注释类,我应该从我的 run() 方法调用它。它对我不起作用。其他一些解决方案涉及使用 EntityManager 或其他一些依赖 Hibernate 的 bean,而不是直接查询 JPA 存储库。也行不通。
那么,有什么解决方案可以满足我的需求吗?谢谢!
解决方案(来自cproinger):
创建@Service注释类:
@Service
public class AsyncTransactionService {
@Autowired
RtmpSourceRepository rtmpRep;
@Transactional(readOnly = true)
public List<RtmpSource> getRtmpSources() {
return rtmpRep.findAll();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void insertRtmpSource(RtmpSource rtmpSource) {
rtmpRep.save(rtmpSource);
}
}
然后,我从JUnit测试和Runnable类自动连接AsyncTransactionService。为了从JUnit测试中插入记录,我调用insertRtmpSource(),然后通过调用getRtmpSources()从我的线程中获取记录。
我试着在没有@服务的情况下做这件事。这是通过在我的JUnit类上放置一个带注释的insertRtmpSource()方法,在我的Runnable类上放置一个getRtmpSources()方法,但是它不起作用。
感谢您的快速回复!
线程看不到记录,因为测试在尚未提交的事务中运行。因为事务被绑定到执行线程,所以被分叉的任务不使用相同的事务。为了实现这一点,插入必须在用@ Transactional(propagation = REQUIRES _ NEW)注释的方法中运行。请注意,那时事务性回滚将不起作用
我以前从未将Spring Data JPA与存储过程一起使用过,但我非常感谢这里的任何反馈/输入
问题内容: 我试图了解如何在使用Spring进行事务管理的Java应用程序中实现线程。我已经在Spring文档中找到TaskExecutor部分,并且ThreadPoolTaskExecutor看起来很适合我的需求。 ThreadPoolTaskExecutor 该实现只能在Java 5环境中使用,也是该环境中最常用的一种。它公开了用于配置java.util.concurrent.Thre
问题内容: 是否有人从Oracle存储过程成功访问了Web服务?如果是这样,那是Java存储过程吗?PL / SQL存储过程? 有什么原因为什么我不应该尝试从存储的proc访问WS? 这是我到目前为止发现的几个参考 数据库Web服务 从Java存储过程调用外部Web服务 为了澄清,这是针对SOAP调用的 问题答案: 首先,您要调用哪种Web服务?我假设是SOAP或REST。 对于REST Web服
我在vue文件中的“方法”中有这个 我得到以下错误:未捕获(在promise中)TypeError:无法读取未定义的属性'$store'
我正在尝试将应用程序在Azure上投入生产。此应用程序由一个webapp(运行Docker容器)组成,该应用程序应该与Azure存储帐户(blob)通信。 将Web应用的所有出站IP地址添加到我的存储帐户的防火墙设置后,我仍然没有访问Blob的权限。错误如下:“此请求无权执行此操作。” 然而,当我在本地运行我的应用程序,并将我的本地IP添加到这些相同的防火墙设置中时,它可以工作。当我没有将其添加到
问题内容: 我正在使用Spring Data(JPA)存储库来处理CRUD样板。 我这样定义我的存储库接口: 然后Spring自动为我生成上述接口的实现。我们得到的是代理,但我相信最终我们可以归结为。 如果 基础目标类是线程安全的, 则 A 是线程安全的。因此,问题是:线程安全吗? 问题答案: 通常,是的。假设是一个托管对象,我们将从Spring的工厂类(如果您使用Spring作为容器)或CDI托