I am working on a Spring-MVC application for which we are planning to create API's which can be consumed by external users into their own platform. To do so, the user must create an 'app' on our platform and then the accesstoken can be retrieved which can be used to access data by user, and make modifications to it.
Now, to do so, what I am doing is, I have created a table called as 'appdetails'. The user has to authorize the app, by passing in client-id, secret and I am returning an access-token, which can be used to directly work on data-set of the user who owns the app.
But doing a check everytime if the object being requested, belongs to the owner of app is proving more database calls for each request. How can I effectively minimize these calls. Here is how the database looks like. Please note, I am only putting relevant fields and I am using PostgreSQL. Explanation below image.
So, now when an user wants to access/POST a canvas object. I am receiving the canvas object and the access-token. But now I have to verify, if the groupid to which it has to be associated is the same as what the app-owner is admin for. More calls are required in Section, note. Here is the SQL code if anyone wants.
CREATE TABLE appDetails (
appid NUMERIC NOT NULL,
clientsecret VARCHAR NOT NULL,
clientid VARCHAR NOT NULL,
accesstoken VARCHAR NOT NULL,
CONSTRAINT appid PRIMARY KEY (appid)
);
CREATE TABLE person (
id INTEGER NOT NULL,
email VARCHAR NOT NULL,
appid NUMERIC NOT NULL,
CONSTRAINT id PRIMARY KEY (id)
);
CREATE TABLE groupaccount (
groupid INTEGER NOT NULL,
groupname VARCHAR NOT NULL,
id INTEGER NOT NULL,
CONSTRAINT groupid PRIMARY KEY (groupid)
);
CREATE TABLE groupmembers (
memberid INTEGER NOT NULL,
groupid INTEGER NOT NULL,
CONSTRAINT memberid PRIMARY KEY (memberid, groupid)
);
CREATE TABLE canvas (
canvasid VARCHAR NOT NULL,
groupid INTEGER NOT NULL,
memberid INTEGER NOT NULL,
CONSTRAINT canvasid PRIMARY KEY (canvasid)
);
CREATE TABLE section (
sectionid VARCHAR NOT NULL,
canvasid VARCHAR NOT NULL,
CONSTRAINT sectionid PRIMARY KEY (sectionid)
);
CREATE TABLE note (
noteid VARCHAR NOT NULL,
sectionid VARCHAR NOT NULL,
CONSTRAINT noteid PRIMARY KEY (noteid)
);
ALTER TABLE person ADD CONSTRAINT appDetails_person_fk
FOREIGN KEY (appid)
REFERENCES appDetails (appid)
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;
ALTER TABLE groupaccount ADD CONSTRAINT person_groupaccount_fk
FOREIGN KEY (id)
REFERENCES person (id)
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;
ALTER TABLE groupmembers ADD CONSTRAINT groupaccount_groupmembers_fk
FOREIGN KEY (groupid)
REFERENCES groupaccount (groupid)
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;
ALTER TABLE canvas ADD CONSTRAINT groupaccount_canvas_fk
FOREIGN KEY (groupid)
REFERENCES groupaccount (groupid)
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;
ALTER TABLE canvas ADD CONSTRAINT groupmembers_canvas_fk
FOREIGN KEY (memberid, groupid)
REFERENCES groupmembers (memberid, groupid)
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;
ALTER TABLE section ADD CONSTRAINT canvas_section_fk
FOREIGN KEY (canvasid)
REFERENCES canvas (canvasid)
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;
ALTER TABLE note ADD CONSTRAINT section_note_fk
FOREIGN KEY (sectionid)
REFERENCES section (sectionid)
ON DELETE NO ACTION
ON UPDATE NO ACTION
NOT DEFERRABLE;
Also, are there any technologies I can use to maintain Rate of consumption of API. The simplest I could think of was adding a counter in appdetails. I hope the question is clear, if not, kindly let me know. I will explain further.
Related
I would like to seek your insights regarding the error I'm encountering with my postgresql commands.
Basically, what I want to achieve is to create a "booking" entity with one to one relationship to another table called "booking details". But flyway won't migrate my schema with the following error:
Caused by: org.flywaydb.core.internal.sqlscript.FlywaySqlScriptException:
Migration V0__Initial.sql failed
--------------------------------
SQL State : 42S02
Error Code : 42102
Message : Table "BOOKING_DETAILS" not found; SQL statement:
ALTER TABLE booking ADD CONSTRAINT FK_BOOKING_ON_BOOKING_DETAILS FOREIGN KEY (booking_details_id) REFERENCES booking_details (booking_entity_id) [42102-214]
Line : 16
Statement : ALTER TABLE booking ADD CONSTRAINT FK_BOOKING_ON_BOOKING_DETAILS FOREIGN KEY (booking_details_id) REFERENCES booking_details (booking_entity_id)
Here is my postgresql commands:
DROP SEQUENCE IF EXISTS booking_transaction_sequence;
DROP TABLE IF EXISTS booking;
CREATE SEQUENCE IF NOT EXISTS booking_transaction_sequence START WITH 1000 INCREMENT BY 100;
CREATE TABLE booking (
id BIGINT NOT NULL,
booking_number VARCHAR(255),
booking_status VARCHAR(255),
processed_by VARCHAR(255),
created_at TIMESTAMP WITHOUT TIME ZONE,
booking_details_id BIGINT,
CONSTRAINT pk_booking PRIMARY KEY (id)
);
ALTER TABLE booking ADD CONSTRAINT FK_BOOKING_ON_BOOKING_DETAILS FOREIGN KEY (booking_details_id) REFERENCES booking_details (booking_entity_id);
DROP SEQUENCE IF EXISTS booking_details_transaction_sequence;
DROP TABLE IF EXISTS booking_details;
CREATE SEQUENCE IF NOT EXISTS booking_details_transaction_sequence START WITH 1000 INCREMENT BY 100;
CREATE TABLE booking_details (
booking_entity_id BIGINT NOT NULL,
sender_name VARCHAR(255),
item_details VARCHAR(255),
pickup_address VARCHAR(255),
rider_name VARCHAR(255),
delivery_address VARCHAR(255),
cancellation_reason VARCHAR(255),
CONSTRAINT pk_booking_details PRIMARY KEY (booking_entity_id)
);
ALTER TABLE booking_details ADD CONSTRAINT FK_BOOKING_DETAILS_ON_BOOKINGENTITY FOREIGN KEY (booking_entity_id) REFERENCES booking (id);
I would highly appreciate any inputs regarding this. Thank you.
I tried using the "extend" method on my BookingDetails entity to BookingEntity. This run my java springboot application but for some reason I can't fetch data with internal error 500 in postman. So I change my sql commands with the one-to-one relationship mapping but I got the above errors.
Just out of interest - how you're planning to insert new entries given the schema? In order to create booking you'd need to have booking_details created and vice versa.
The error message indicates that the table "BOOKING_DETAILS" is not found when you're trying to create a foreign key constraint in the "booking" table.
You need to make sure that the "booking_details" table is created before creating the foreign key constraint in the "booking" table. You can do this by reordering your migration script to create the "booking_details" table before creating the "booking" table with the foreign key constraint.
Additionally, check that the table name and column name used in the foreign key constraint statement are correct and match the names used in the "booking_details" table.
Solution: put this command on the last part of the sql so that the two tables must be created first before it can be altered.
"ALTER TABLE booking ADD CONSTRAINT FK_BOOKING_ON_BOOKING_DETAILS FOREIGN KEY (booking_details_id) REFERENCES booking_details (booking_entity_id);"
I use Spring Boot and Flyway with this initialization script:
CREATE TABLE ADDRESS(
ID bigserial NOT NULL PRIMARY KEY
);
CREATE TABLE ROLE(
ID bigserial NOT NULL PRIMARY KEY
);
CREATE TABLE PERSON(
ID bigserial NOT NULL PRIMARY KEY,
FIRST_NAME VARCHAR(255),
LAST_NAME VARCHAR(255),
ADDRESS bigserial NOT NULL REFERENCES ADDRESS (ID),
ROLE bigserial REFERENCES ROLE (ID) -- notice here is no 'not null'
);
All the relationship between the tables is that:
Each PERSON has 0-1 ROLE. So, each ROLE belongs to 0-n PERSON. Hence, this relationship is nullable.
Each PERSON has 1 ADDRESS. So, each ADDRESS belongs to 1-n PERSON. Hence, this relationship is not-null.
As soon as I start the application (I have also tried to post the query straight to the PostgreSQL database schema), there is somehow generated constraint not-null between the PERSON and ROLE tables.
Using DataGrip, I select SQL Scripts -> Generate DDL to Query Console and get the DDL for the tables (see below, new lines and roles definitions omitted for sake of brevity).
To my surprise, the NOT NULL is there although I haven't defined such constraint. How to get rid of it aside from altering table?
create table if not exists address
(
id bigserial not null
constraint address_pkey primary key
);
create table if not exists role
(
id bigserial not nullconstraint role_pkey primary key
);
create table if not exists person
(
id bigserial not null
constraint person_pkey primary key,
first_name varchar(255),
last_name varchar(255),
address bigserial not null
constraint person_address_fkey references address,
role bigserial not null -- why is 'not null' here?
constraint person_role_fkey references role
);
The version of PostgreSQL I use (through SELECT version()) is:
PostgreSQL 10.13, compiled by Visual C++ build 1800, 64-bit
"8.1.4. Serial Types":
The data types smallserial, serial and bigserial are not true
types, but merely a notational convenience for creating unique
identifier columns (similar to the AUTO_INCREMENT property supported
by some other databases). In the current implementation, specifying:
CREATE TABLE tablename (
colname SERIAL
);
is equivalent to specifying:
CREATE SEQUENCE tablename_colname_seq AS integer;
CREATE TABLE tablename (
colname integer NOT NULL DEFAULT nextval('tablename_colname_seq')
);
ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;
Note the NOT NULL.
Don't use bigserial for the foreign key. That doesn't make much sense. Simply use bigint.
CREATE TABLE IF NOT EXISTS person
(...
role bigint REFERENCES role);
Possible solution 1:
Changing Biserial to Bigint does not remove the null constraint set to foreign key column when running flyway in springboot to write into postgres DB (at least for my case)
postgres:11.3-alphine 3.4
flyway: 8.0.5
To be secure, need to add scripts to alter columns to be nullable
ALTER TABLE mytable ALTER COLUMN mycolumn DROP NOT NULL;
Change Postgres column to nullable
Possible solition 2:
When Spring boot set JPA Hibernate ddl configuration to create, create-drop, update, flyway DB migration script will be updated by JPA entities properties. NOT NULL constraints can be added by JPA entities.
Change JPA Hibernate ddl configuration to none or validate will ensure only flyway script is used to create schema.
JPA Hibernate ddl configuration
Here is my tables definition
CREATE TABLE IF NOT EXISTS `store` (
`store_id` INT NOT NULL AUTO_INCREMENT,
`store_name` VARCHAR(1024) NOT NULL,
`store_user` INT NOT NULL,
`store_address` INT NOT NULL,
`store_type` INT NOT NULL,
`created_date` DATETIME NOT NULL,
`updated_date` DATETIME NOT NULL,
PRIMARY KEY (`store_id`)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `store_address` (
`address_id` INT NOT NULL AUTO_INCREMENT,
`address_line_1` VARCHAR(1024) NOT NULL,
`address_line_2` VARCHAR(1024) NOT NULL,
`address_line_3` VARCHAR(1024) NULL,
`city` VARCHAR(45) NOT NULL,
`locality` VARCHAR(100) NOT NULL,
`pincode` CHAR(6) NOT NULL,
`latitude` DECIMAL(8,6) NULL,
`longitude` DECIMAL(9,6) NULL,
`state` VARCHAR(45) NOT NULL,
`created_date` DATETIME NOT NULL,
`updated_date` DATETIME NOT NULL,
PRIMARY KEY (`address_id`),
CONSTRAINT `FK_STR_STR_ADR`
FOREIGN KEY (`address_id`)
REFERENCES `store` (`store_address`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
I am trying to have a 1-1 mapping between store and its address. Considering the DDL is ok, while generating JPA entities Store.java look like this:
#Entity
#Table(name="store")
public class Store
{
#Basic
#Column(name="created_date", nullable=false)
private Date createdDate;
#OneToOne(fetch=FetchType.LAZY, mappedBy="store", cascade=CascadeType.MERGE)
private StoreAddress storeAddress;
#Basic
#Column(name="store_address", columnDefinition="INT")
private int storeAddress2;
/////
Why is there a field storeAddress2 in Store.java? I think this is failing my insertion of a store. Any help?
Considering the DDL is ok [...]
The DDL is not OK, it is erroneous. As the tables are presently structured, the foreign key constraint is backward. store_address.address_id is the referenced key; the constrained column -- that is, the foreign key column -- should be store.store_address.
Moreover, be aware that putting the address into its own table and establishing a NOT NULL foreign key referencing it means that every store must have an address recorded, yet a store address does not have to correspond to any store. If you want the address to be optional then make store.store_address nullable, though that still permits addresses to exist that do not correspond to a store.
Alternatively, even though JPA prefers a forward mapping from parent to child such as you have presented, it is possible to map it in the other direction, so that store addresses cannot exist in the DB without a corresponding store, but stores do not have to have addresses recorded. In the DDL, that would correspond to deleting store.store_address, and creating store_address.store_id as a foreign key referencing store.store_id.
Update:
Here is some DDL to clarify my comments about the FK constraint. This is how an FK relationship between store and store_address should be written, given the column definitions as presented in the question:
CREATE TABLE IF NOT EXISTS `store` (
`store_id` INT NOT NULL AUTO_INCREMENT,
`store_address` INT NOT NULL,
-- ...
PRIMARY KEY (`store_id`),
CONSTRAINT `FK_STR_STR_ADR`
FOREIGN KEY (`store_address`)
REFERENCES `store_address` (`address_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION
)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `store_address` (
`address_id` INT NOT NULL AUTO_INCREMENT,
-- ...
PRIMARY KEY (`address_id`)
-- the FK constraint does NOT go here
)
ENGINE = InnoDB;
Note also that as I already wrote, this does not enforce a 1-1 relationship in the DB. If you want that then you could put a UNIQUE constraint on store.store_address, but it might be better to instead link the PKs of store and store_address. That way you can also prevent orphan store_address rows from being allowed. That could look like this:
CREATE TABLE IF NOT EXISTS `store` (
`store_id` INT NOT NULL AUTO_INCREMENT,
-- ... no store_address ...
PRIMARY KEY (`store_id`)
-- ... no FK constraint here ...
)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `store_address` (
-- addresses do not have independent IDs:
`store_id` INT NOT NULL,
-- ...
PRIMARY KEY (`store_id`),
CONSTRAINT `FK_STR_STR_ADR`
FOREIGN KEY (`store_id`)
REFERENCES `store` (`store_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION
)
ENGINE = InnoDB;
That does permit a store to exist without a corresponding address, which may be sensible, even though you say you don't want that.
Really, though, if a store must not exist without exactly one corresponding address, and a store address must not exist without a store, then why are you mapping these as separate tables? It gains you nothing except, maybe, less manual adjustment to automatically-generated entity classes. It's definitely a loss in the performance and DB complexity arenas.
Note, too, that JPA has annotations for mapping two closely-associated entities to the same table, if you insist that the addresses should be separate entities from their associated stores. Look into the #Embeddable and related annotations.
I want to design a page tracker database table, but I am facing few issues with it.
create table pageTracker(
ID bigint(20) NOT NULL,
TrackerID bigint(20) NOT NULL,
SessionID varchar(100) NOT NULL,
pageViews bigint,
pageVisits bigint,
primary key(ID)
);
If I update pageviews and pageVisits corresponding to specific SessionID I can not query pageViews and pageVisits within specific time interval.
create table pageTracker(
ID bigint(20) NOT NULL,
TrackerID bigint(20) NOT NULL,
SessionID varchar(100) NOT NULL,
pageViews bigint,
pageVisits bigint,
time TimeStamp,
primary key(ID)
);
But if I add extra column time, if I want to insert each pageViews and pageVisits as new entry for specific time it creates huge number of entry in the table.
Is there any efficient way to do it?
I am assuming that you want to update pageViews and pageVisits everytime against a SessionID. In this case first insert will have say:
Session ID = 23R4E11, pageViews = 1, pageVisits = 1
Now if same user revisits same page, you will update existing row as:
Session ID = 23R4E11, pageViews = 2, pageVisits = 1
In this case to maintain all the updates, you can create one more table called as pageTrackerHistory and then write trigger which can insert entry in pageTrackerHistory table whenever update is made on pageTracker table.
By doing this your operational table pageTracker contains minimal rows and pageTrackerHistory table contains huge audit records.
Hope this will give you some direction. :-)
I've two tables that has defined as below; From user table, hospitalId and poliklinikId both references table relhospol, and if any row is deleted from relhospol, (if any user is related with it), I want to set the hospitalId and poliklinikId null, DDL says that. When i delete a row from SQLite Manager it nulls the User's hospitalId and PoliklinikId, However when i try to remove a row from application level (Java), it only removes from relhospol, it does not set null (hospitalId, PoliklinikId) What is the missing point ?
JDBC Driver: SQLite-jdbc-3.7.2
CREATE TABLE [USER] (
[ID] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
[GROUPID] INTEGER CONSTRAINT [FK_USER_GID] REFERENCES [GROUP]([ID]) ON DELETE SET NULL ON UPDATE CASCADE,
[HOSPITALID] INTEGER,
[POLIKLINIKID] INTEGER,
[NAME] VARCHAR(50) NOT NULL,
[LOGINID] VARCHAR(15) NOT NULL,
[EMAIL] VARCHAR(50) NOT NULL,
[PASSWORD] VARCHAR(32) NOT NULL,
CONSTRAINT [FK_USER_RELHOSPOL] FOREIGN KEY([HOSPITALID], [POLIKLINIKID]) REFERENCES [RELHOSPOL]([HOSPITALID], [POLIKLINIKID]) ON DELETE SET NULL ON UPDATE CASCADE);
CREATE UNIQUE INDEX [AS] ON [USER] ([LOGINID]);
CREATE UNIQUE INDEX [AS1] ON [USER] ([EMAIL]));
CREATE TABLE [RELHOSPOL] (
[HOSPITALID] INTEGER CONSTRAINT [FK_RELHOSPOL_HOS] REFERENCES [HOSPITAL]([ID]) ON DELETE SET NULL ON UPDATE CASCADE,
[POLIKLINIKID] INTEGER CONSTRAINT [FK_RELHOSPOL_POL] REFERENCES [POLIKLINIK]([ID]) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT [sqlite_autoindex_RELHOSPOL_1] PRIMARY KEY ([HOSPITALID], [POLIKLINIKID]));
You can't set NULL a primary key:
CREATE TABLE [RELHOSPOL] (
[HOSPITALID] INTEGER CONSTRAINT [FK_RELHOSPOL_HOS] REFERENCES [HOSPITAL]([ID]) ON DELETE SET NULL ON UPDATE CASCADE,
[POLIKLINIKID] INTEGER CONSTRAINT [FK_RELHOSPOL_POL] REFERENCES [POLIKLINIK]([ID]) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT [sqlite_autoindex_RELHOSPOL_1] PRIMARY KEY ([HOSPITALID], [POLIKLINIKID]));
You are trying to remove a row from which table? Can you post the DELETE SQL?
Ok I've changed the RELHOSPOL's definition as below; When i delete row from RELHOSPOL from the SQL Manager with executing a DELETE command, it nulls the necessary rows at the USER table. Whenever I delete a row from application with the method written below, it only deletes row from RELHOSPOL, and does not SET NULL the necessary rows at USER table
CREATE TABLE [RELHOSPOL] (
[ID] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
[HOSPITALID] INTEGER,
[POLIKLINIKID] INTEGER);
CREATE UNIQUE INDEX [UNIQUE_RELHOSPOL] ON [RELHOSPOL] ([HOSPITALID], [POLIKLINIKID]);
Delete Method is :
public void deletePoliklinikFromHospital(int hospitalId, int poliklinikId) throws SQLException{
String query = "DELETE FROM [RELHOSPOL] WHERE (HOSPITALID = ? AND POLIKLINIKID = ?)";
try {
PreparedStatement statement = db.prepareStatement(query);
statement.setInt(1, hospitalId);
statement.setInt(2, poliklinikId);
statement.executeUpdate();
} catch (SQLException e) {
throw new SQLException(e.getMessage());
}
}
It is just a guess, but maybe you are not aware, that you have to enable foreign key support with PRAGMA foreign_keys = ON; everytime you connect to the database? If this is not done, your statements will be parsed, but not enforced. This could explain, why it is working from SQLite Manager.
One should also be aware, that old versions of Sqlite (<3.6.19) will tolerate the syntax but too will not enforce anything.
As sidenote:
As #Neuquino writes the ON DELETE SET NULL statements for table RELHOSPOL don't seem to make sense.