java - Thread safe input validation -


i'm building spring boot application allows registering, submitting of various data , etc requires validation. example have entity setup basic constraints:

@entity public class account extends baseentity {      public static final int max_length = 64;      @column(unique = true, nullable = false, length = max_length)     private string username;      @column(unique = true, nullable = false, length = max_length)     private string email;      ... } 

each time before creating new account, validation performed on service layer:

public account register(string username, string email, string rawpassword) {      if (!accountvalidator.validate(username, email, rawpassword)) {         return null;     }      account account = new account(username, email, passwordencoder.encode(rawpassword));     try {         return accountrepository.save(account);     } catch (dataintegrityviolationexception e) {         return null;     } } 

the validator snippet:

public boolean validate(string username, string email, string password) {      if (!validateusernamestructure(username)) {         return false;     }      if (!validateemailstructure(email)) {         return false;     }      if (!validatepasswordstructure(password)) {         return false;     }      // performs query on users see if no such email or username     // exists. before checking email , username set     // lowercase characters on service layer.     if (accountservice.doesemailorusernameexist(email, username)) {         return false;     }     return true; } 

now in case if lot of multiple requests , 1 of them manages past validation, encounter exception if username or email forced lowercase in first place. example want allow users register upper case/lower case username, email characters , etc. based on this question add additional field entity or add more complex constraint on database level, want without overflow data , in java code.

so example these 2 requests create new account milliseconds apart:

request 1: username=foo email=foo@foo.com  request 2: username=foo email=foo@foo.com 

during phase check duplicates (email , username set lower case, when saving keep case intact):

if (accountservice.doesemailorusernameexist(email, username)) {     return false; } 

however since requests close each other, first request might not have created new account yet check second account passes , 2 database entries.

so actual question be, how perform thread safe validation these kinds of actions in service layer without huge performance impact?

solution i've chosen example

when setting username , email, apply values lowercase counterparts , apply unique constraints on them well. way keep user set case 2 properties:

@entity public class account extends baseentity {      public static final int max_length = 64;      @column(unique = true, nullable = false, length = max_length)     private final string username;      @column(unique = true, nullable = false, length = max_length)     private string email;      @column(unique = true, nullable = false, length = max_length)     private final string normalizedusername;      @column(unique = true, nullable = false, length = max_length)     private string normalizedemail;      public account(string username, string email) {         this.username = username;         this.email = email;          this.normalizedusername = username.tolowercase();         this.normalizedemail = email.tolowercase();     }      ... } 

there no simple solution without of database because transactions isolated each other.

the alternative temporarily store usernames/emails in memory , complex synchronizations perform checks. things more complicated in clustered environments. ugly , hard maintain (and may impact performance if lock single synchronization point held long).

the standard , straightforward solution use database constraints.


Comments

Popular posts from this blog

php - Wordpress website dashboard page or post editor content is not showing but front end data is showing properly -

How to get the ip address of VM and use it to configure SSH connection dynamically in Ansible -

javascript - Get parameter of GET request -