Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot locking code to get an unique id

Tags:

spring-boot

I wrote a controller that must return an unique String. The requirement is that two calling of this controller never return the same String, even after years and even if the code will scale to more VMs.

My question is if the following code is correct to achieve to declared purpose, or if you have any hint.

Controller:

@RestController
public class UtilityController {

    @Autowired
    UtilityServices utilityServices;

    @GetMapping("/uniqueIdentifier")
    @ResponseBody
    public String uniqueIdentifier() {
        return utilityServices.getUniqueIdentifier();
    }

Service:

@Service
public class UtilityServices {

    @Autowired
    private UniqueIdRepository uniqueIdRepository;

    @Transactional
    public String getUniqueIdentifier() {
       String uniqueId = RandomString.getSecureRandomString();
       while (uniqueIdRepository.existsById(uniqueId)) {
           uniqueId = RandomString.getSecureRandomString();
       }
       uniqueIdRepository.save(new UniqueId(uniqueId));
       return uniqueId;
    }
}

Entity:

@Entity
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@EqualsAndHashCode
@ToString
public class UniqueId implements Serializable {

    @Id
    private String uniqueId;   

}

Repository:

public interface UniqueIdRepository extends CrudRepository<UniqueId, String> {

}

That's all. I omit the code the RandomString class because it's not relevant in this context: I wrote a code based on SecureRandom, it is very likely that each time it returns a different String, but I have no guarantees about it. Let's assume that sooner or later my RandomString.getSecureRandomString() method can return the same String.

I'm not sure if the @Transactional annotation guarantees that the getUniqueIdentifier() method never throws an error.

like image 591
Francesco Galgani Avatar asked Mar 19 '26 05:03

Francesco Galgani


1 Answers

The much better idea at your case will be using UUID:

Thus, anyone can create a UUID and use it to identify something with near certainty that the identifier does not duplicate one that has already been, or will be, created to identify something else. Information labelled with UUIDs by independent parties can, therefore, be later combined into a single database or transmitted on the same channel, with a negligible probability of duplication.

@Service
public class UtilityServices {
    @Autowired
    private UniqueIdRepository uniqueIdRepository;

    @Transactional
    public String getUniqueIdentifier() {
       String uniqueId = String.format("%s-%s",
            RandomStringUtils.randomAlphanumeric(4),
            UUID.randomUUID().toString().replace("-", "")
       );
       // you could left this check 
       while (uniqueIdRepository.existsById(uniqueId)) {
           uniqueId = UUID.randomUUID().toString().replace("-", "");
       }
       uniqueIdRepository.save(new UniqueId(uniqueId));
       return uniqueId;
    }
}

BTW you could use @Data for Model:

@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
public class UniqueId implements Serializable {
    private static final long serialVersionUID = 0L;
    @Id
    private String uniqueId;   
}

And don't forget about serialVersionUID.

Useful references:

  • What is a serialVersionUID and why should I use it?
  • thanks to @M.Deinum for @Data details for entitites
like image 103
catch23 Avatar answered Mar 20 '26 18:03

catch23



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!