有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在不同事务中保持相同的依赖关系

我有一个程序的一部分,其中以与另一个系统并行的方式实现了同步。每个同步进程都会打开新事务。同步对象将映射到某些数据并保持。 要映射对象的数据可以在同步之前持久化,也可以在同步时持久化

我的持久层提供了级联操作,所以我不关心所有依赖项的持久化

发行

在映射对象之前未持久化,在同步时间内,它将保存在不同的线程中,同时出现hibernate异常:

org.springframework.dao.DataIntegrityViolationException: A different object with the same identifier value was already associated with the session : [my.project.entity.CrmCaseLink#27];
nested exception is javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [my.project.entity.CrmCaseLink#27]

我试图解决这个问题,但毫无帮助

1

我尝试使用缓存,从中我可以为不同的线程获得相同的CrmCaseLink,但它并没有解决我的问题

2

我又试了一次

@CacheConfig(cacheNames = Constants.CRM_CASE_LINK_CACHE, cacheManager = Constants.GUAVA_CACHE_MANAGER)
@Service
public class CrmCaseLinkService {

    private static final Logger LOGGER = LogManager.getLogger(CrmCaseLinkService.class);
    @Autowired
    private CrmCaseLinkRepository crmCaseLinkRepository;

    @Cacheable(key = "#id")
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public synchronized CrmCaseLink findOne(Long id) {
        LOGGER.debug("trace loading crm case link by specified id: {}", id);
        return Optional.ofNullable(crmCaseLinkRepository.findOne(id))
                .orElseGet(() -> crmCaseLinkRepository.save(new CrmCaseLink(id)));
    }
}

问题:

为什么缓存在这里是错误的?我希望hiberate能够在不同的事务中管理相同的非持久化实体。我确信在单独的Springbean中使用新事务的缓存解决方案是无可争议的解决方案,但它对我也没有帮助

其他细节

java8、spring、spring数据jpa、postgres、hibernate5、jetty容器


共 (1) 个答案

  1. # 1 楼答案

    问题的原因解释

    我认为出现这个问题是因为在提供的解决方案中使用了分离的实体对象。如您所见,我为synchronized singleton方法创建了新事务

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public synchronized CrmCaseLink findOne(Long id) {
        LOGGER.debug("trace loading crm case link by specified id: {}", id);
        return Optional.ofNullable(crmCaseLinkRepository.findOne(id))
                .orElseGet(() -> crmCaseLinkRepository.save(new CrmCaseLink(id)));
    }
    

    如果数据库存储中缺少新对象,则保留新对象。但是从另一个事务中使用public synchronized CrmCaseLink findOne来获取CrmCaseLink并将其映射到其他对象上。要成功映射和持久化其他实体,我必须使用attachedCrmCaseLink

    解决方案代码示例

    我以下一种方式更改了代码:

    1. 数据库查找和持久化是不同的方法
    2. 必须在新的传输中同步和处理持久化方法
    3. 删除缓存,因为映射需要附加的实体,不同的事务使用此服务加载CrmCaseLink

    代码示例:

    @Service
    public class CrmCaseLinkManager implements CrmLinkManager {
        @Autowired
        private CrmCaseLinkRepository crmCaseLinkRepository;
    
        @Override
        public CrmCaseLink findOne(Long id) {
            return crmCaseLinkRepository.findOne(id);
        }
    
        @Override
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public synchronized void save(Long id) {
            if (crmCaseLinkRepository.exists(id)) {
                return;
            }
            crmCaseLinkRepository.save(new CrmCaseLink(id));
        }
    }
    

    使用from的代码部分演示了如何从实现的服务中获取必要的附加实体:

    T getOrCreateCrmLink(Long id, CrmLinkManager<T> crmLinkManager) {
        T crmLink = crmLinkManager.findOne(id);
        if (crmLink == null) {
            crmLinkManager.save(id);
            crmLink = crmLinkManager.findOne(id);
        }
        return crmLink;
    }