【发布时间】:2016-10-19 17:34:16
【问题描述】:
我有一个库,其中包含一些我想在其他项目中重用的功能。我的问题是我的服务需要写入数据库。我希望我的库使用注入我的服务的项目的数据源。
这是我的服务的最小设置
@Stateless
public class CustomService {
//to be added in producer
private EntityManager em;
private Principal principal;
//default constructor
public CustomService() {}
//custom constructor called in provider
public CustomService(Principal p, EntityManager e) {
principal = p;
em = e;
}
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
@Transactional
public CustomJPAObject createObject(...params...) {
//create JPA Object
em.persist(customObject);
em.flush();
return customObject;
}
}
我创建了一个自定义注释来覆盖数据源
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.FIELD, ElementType.METHOD})
public @interface DynamicDS {
@Nonbinding String value() default "";
}
我还创建了一个 Singleton 作为 EntityManager Producer
@Singleton
public class CustomEMProducer {
private Map<String, EntityManagerFactory> emfMap = new HashMap<>();
@Produces @Dependent @DynamicDS
public EntityManager produceEntityManager(InjectionPoint injectionPoint) {
String dataSourceName = null;
for(Annotation qualifier: injectionPoint.getQualifiers()) {
if(qualifier instanceof DynamicDS) {
DynamicDS dds = (DynamicDS) qualifier;
dataSourceName = dds.value();
break;
}
}
EntityManagerFactory emf = emfMap.get(dataSourceName);
if (emf == null) {
emf = Persistence.createEntityManagerFactory(dataSourceName);
emfMap.put(dataSourceName, emf);
}
return emf.createEntityManager();
}
@PostConstruct
public void cleanup() {
emfMap.entrySet().stream().forEach(entry -> entry.getValue().close());
}
}
这是我的服务生产者的代码
@Stateless
public class CustomServiceProvider {
@Inject private Principal principal;
@Produces @Dependent @DynamicDS
public BackgroundJobService getBackgroundJobService(InjectionPoint injectionPoint) throws EntityManagerNotCreatedException {
Annotation dsAnnotation = null;
for(Annotation qualifier: injectionPoint.getQualifiers()) {
if(qualifier instanceof BackgroundJobDS) {
dsAnnotation = qualifier;
break;
}
}
if (dsAnnotation != null) {
EntityManager em = CDI.current().select(EntityManager.class, dsAnnotation).get();
CustomService service = new CustomService(principal, em);
return service;
}
throw new EntityManagerNotCreatedException("Could not Produce CustomService");
}
}
以下是我尝试注入新服务的地方
@Stateless
public class ProjectService {
@Inject @DynamicDS("project-ds") CustomerService service;
public CustomObject create(...params...) {
return service.createObject(...params...);
}
}
当我部署我的代码并尝试调用注入的服务时,我收到以下错误:
Caused by: javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.checkTransactionNeeded(AbstractEntityManagerImpl.java:1171)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1332)
...
看起来所有不同级别的提供者都在阻止 CustomService.createObject() 方法调用上的 @Transactional 传播事务。有没有人知道为什么这是实现我注入动态 EntityManager 目标的替代方法?
【问题讨论】:
标签: jpa jakarta-ee cdi