Should I lock the table when creating user? - mysql

I want to create a user into User table.
These are my process.
continue when email and nickname are not exist
creates a user
I think if I didn't lock the User table while creating a user then email and nickname can be duplicated.
Any ideas?

Avoid locks where possible. Instead, use a unique index, and simply insert the user. If the user or email exists, your query will return an error similar to:
Error Code: 1062. Duplicate entry 'john.doe#example.org' for key 'unique_email'
This should be done with 2 separate indexes. One for email, and one for users. This has the following advantages, and almost zero disadvantages:
It enforces database consistency. At no point will 2 users have the same email address, nor the same username.
It avoids unnecessary locks.
It avoids technical debt. Let's say down the line you add a user importer. In the importer you fail to check for duplicate accounts, or add in locks, or forget to check if the username or email exists. Your importer will work, and your database will now contain entries that duplicate each other.

I'd try to create a combined unique key on email and nickname
CREATE UNIQUE INDEX some_index_name ON user_table(email , nickname)
Edit: To address the comments below, we should as well create 2 more unique indexes for email and username, to make sure 2 users with separate emails can share the same username and vice versa.

Related

Best practice store email unique MySQL and Validate JS

I have a table where email is a unique key, the point is... when the user get deleted in the manage form, I do an update, inserting "1" in a column called "deleted", doing this I keep the data and the history of that user... But if I have to add a new user with the same email, Bang MySQL catches me
So.. my question is, the best practice is?
Do a remove in table when user get deleted, losing the history of that user
Remove the unique key in the column email, and keep the validate only in JS for prevent duplicates emails
Another one...
Thanks for your time
You can restrict emails to being unique only if not deleted with a virtual column:
create table user (
email varchar(320),
deleted tinyint,
undeleted_email varchar(320) as (if(deleted,null,email)) unique
);
fiddle
You could reverse the logic and instead of storing a nullable deletion mark, store an active mark. Use a check constraint (in MySQL 8+) or a trigger (in lower MySQL versions which don't enforce check constraints) to restrict the possible values of the active mark to one (non-NULL) value (and NULL). Then put the unique constraint on the e-mail address and the active mark combined. That way you can have multiple rows with the same e-mail address and a NULL active mark but maximally one with that address and a non-NULL active mark.
CREATE TABLE user
(id integer,
email varchar(256),
active tinyint,
PRIMARY KEY (id),
CHECK (active = 1),
UNIQUE (email,
active));
db<>fiddle
But as a non technical side note, check, if you're legally allowed to keep the history of a user when they delete their account according to the data protection laws applying to you. They may have the right to expect that everything is deleted when they delete their account.
And you could also consider, no to create a new account, if a user comes back, but instead offer them to reactivate their old account.

MySQL database with multiple user types

I'm designing a MySQL database with some tables for a clinic and I need three different user types: admin, medic and patient.
What I did was to create a table called users where its columns are precisely the common fields shared by admins, medics and patients (there is of course a primary key called id_user which auto increments every time a user is added).
Then I created three tables regarding the specific data for each user type: admin, medic and patient in which I have a field called id_user which is a foreign key to id_user in the table users.
When I tried to establish the foreign key constraint for the three user type tables, phpMyAdmin doesn't allow me to set ON DELETE as "SET NULL" (I think that would make sense because if I delete a user from the users table then it should automatically set the fields as NULL in the medic, admin or patient tables, right?) and gives me the error "relation has not been added".
Doubt 1: What's happening here that I'm not aware of?
Doubt 2: Should I forget this way of relating tables and simply add the specific fields for each user type in the users table although some users will have some fields set as NULL?
Here is an image illustrating my database:
You should use Cascading Deletes instead of setting fields null, if you delete a user you want them gone if you null out the data you'll just have tables filled with nulls.
Also from what i understand you created 3 tables for each of the permission levels if this is the case you should maybe handle that in code with conditions checking the permissions level

User table structure for registration and login system with email

I want to know what is best table structure and indexes for users table (login by email and password) for best performance.
I don't want to use usernames.
I want to login with unique index (for better performance) with user email.
Maybe best performance will be unique index for email and password together.
Problem is that I want to be email indexed as unique for faster login.
But in this case bad user can prevent another user to register knowing his email.
The only idea I could think of some sort of unique email and password hash in one unique column. But I want know how its done the best.
Part of my user table index structure (DB is MySQL)
user_id - PRIMARY
email - UNIQUE
password
verified (after verify email)
Simple solution:
Send verification email with link to cancel registration (I didnt register)

Link field values and ID to another table?

How do I link or add the field with all my users called "username" from my main table to another table so I can run checks and compare values without having to add a ton of rows to my main table? This would be a much cleaner and more organized setup.
Table called login_users. This is my main table that stores their basic information
username email password
Anthony user#email.com
Josh user#email.com
Tsuyoshi user#email.com
Table 2 called badge_status. This table will hold their status with whether or not they have unlocked an achievement on my site. I want to bring in the usernames.
username badge1 badge2
Anthony locked unlocked
Josh unlocked locked
Tsuyoshi unlocked locked
Also, could table 2 automatically be updated with a new user when they sign up since all new sign ups are imported into the first table. As a side note, I am using phpmyadmin.
Thanks for any help with getting this set up. Very much appreciated.
I think you should normalize your data by using the following schema instead:
login_users [Table]
username
email
password
badges [Table]
BadgeId int PRIMARY KEY
BadgeName
... (any other relevant columns)
users_badges [Table]
username (foreign key constraint to username column on the login_users table)
BadgeId (foreign key constraint to BadgeId column on the badges table)
This will allow you add as many badges as you want without having to ever change your database schema or scripts.
I don't really understand why you are separating out these tables. In theory, there is a one-to-one relationship between the two. Your query "could table 2 automatically be updated with a new user when they sign up since all new sign ups are imported into the first table" further supports the argument why splitting these tables simply creates unnecessary overhead.
Other sources of overhead include overly complicated JOINs to get the data out and the need to add an additional unique constraint on badge_status.username as well as a foreign key.
If you truly wish to separate out these tables, I would suggest the following setup instead which makes querying for specific badges and adding new badges very easy:
login_users: username, email, password, ...
badges: id, name, description, ...
users_badges: username, badge_id, status, unlocked_date, ...

Create new user with email as a soft deleted user

I am using ActsAsParanoid for soft deleting users.After deleting(soft) a user, my client wants to create user with same email id.But it generating unique field error since email column is unique.So my question is can we set the uniqueness for email column only if the deleted_at column is null.
Pls reply if u dont understand my question.
I suppose you could change the uniqueness constraint of your users table to be:
UNIQUE (email, deletion_date)
This would effectively:
For standard (non-deleted) users, guarantee they have unique email addresses, since their deletion dates would presumably all be NULL.
For deleted users, not make any guarantee about email addresses, since they all have unique deletion dates.
For new users, allow them to use an email address that a deleted user has, since the new user will have a NULL deletion date, while the deleted user has a value there.
Ah, just change old email to something like
Me#yourmail.com_deleted
That way if you need to view the old email it's everything before the underscore deleted.
In other words here have new user create new account.
Probably have a mutator in the background add the underscore deleted on the old account.
Underscore deleted just an example.