【发布时间】:2018-10-26 04:26:29
【问题描述】:
我面临以下问题:
我有一个实体:
@Table(name = "host",
uniqueConstraints =
{
@UniqueConstraint(name = "uq_host_0",
columnNames = {"orgName", "hostName"})}
)
class Host {
private String id;
private String hostName;
private String orgName;
//gets
//sets
//constructors
//...
}
此实体在 orgName + hostName 字段上具有唯一性约束。
以及实体对应的Repository:
public interface HostRepository extends JpaRepository<Host, String> {
Page<Host> findByOrgId(String orgId, Pageable pageable);
Host findOneByOrgNameIdAndId(String orgName, String id);
Host findOneByOrgNameAndHostName(String orgName, String hostName);
//..
}
我想用 findOrCreate 方法创建一个服务:
- 如果主机不存在则创建新主机
- 如果主机确实存在,则返回主机
考虑到 hostName + orgName 字段的唯一性约束。
这个方法应该假设它可以在同一应用程序的多个不同实例以及不同线程中执行。
目前我想出了两个解决方案:
-
使用 Propagation = RequiresNew 使用单独的方法进行创建
@Service public class HostService { @Autowired private HostRepository hostRepository; @Transactional public Host findOrCreate(Host host) { try { return create(host); } catch(ConstraintViolationException e) { //means the host has already been created by other transaction return hostRepository.findFirstByOrgNameAndHostName(host.getHostName(), host.getOrgName()); } } @Transactional(propagation = Propagation.REQUIRES_NEW) public Host create(Host host) { //constraint violation may be thrown hostRepository.save(host); } } -
在一种方法中执行所有逻辑,但隔离级别 = 可序列化:
@Service public class HostService { @Autowired private HostRepository hostRepository; @Transactional(isolation = Isolation.SERIALIZABLE) public Host findOrCreate(Host host) { Optional<Host> existing = Optional.ofNullable(hostRepository.findOneByOrgNameAndHostName(host.getOrgName(), host.getHostName())); if(existing.isPresent()) { return existing; } return hostRepository.save(host); }}
在我看来,这两个选项都可以在并发环境中工作,而第一个选项更可取,因为工作速度更快。但是,我担心我可能会错过水下岩石。
以前有人遇到过这个问题吗?
如果是这样,我非常感谢您提供除上述之外的任何建议或替代解决方案,
谢谢,干杯
【问题讨论】:
标签: spring hibernate spring-data spring-data-jpa spring-transactions