I'm using Spring boot, and I Run this model.
package com.example.demo.Models;
import jakarta.persistence.*;
#Entity
#Table(name = "user")
public class UserModel {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(unique = true, nullable = true)
private Long id;
private String name;
private String email;
private Integer priority;
/* Here are all the setters and getters*/
}
application.properties:
spring.datasource.url=jdbc:postgresql://localhost:5432/dbdemo
spring.datasource.username=postgres
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
Everything fine with Java.
Process finished with exit code 0
But in the console of my docker image of Postgres I get the following error:
ERROR: syntax error at or near "user" at character 14
STATEMENT: create table user(id bigserial not null, email varchar(255), name varchar(255), priority integer, primary key (id))
I'm not sure how to solve it, I'd appreciate any help.
create table public.user ( id serial not null,
email varchar(255),
name varchar(255),
priority integer,
primary key (id))
add the schema name before the table name
You need to specify the schema name in table and id fields like this:
#Table(name = "anomaly", schema = "schema_name")
public class Anomaly {
#Id
#SequenceGenerator(name = "id", allocationSize = 1, schema = "schema_name")
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long anomalyId;
user is a reserved word in Postgresql thats why it show an error
use a different word like "users" "usersId".
Related
Simple issue here: I'm running Spring Boot 2.2.5 on a mySQL database with MySQL5Dialect. Everything was peachy until I've added #ManyToOne annotation to Slide entity referencing the User entity - now Hibernate can't create tables because it creates the users table and then tries to alter slides table which it hasn't created yet. What did I do wrong?
User:
#Entity
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#ToString
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private boolean enabled;
private String token;
private String username;
private String password;
private String role;
private String name;
private String surname;
private String email;
private boolean emailVisible;
private String phone;
private boolean phoneVisible;
private int cohortNumber;
private String company;
private String position;
private String linkedIn;
private String function;
private String bio;
private String membership;
private Date membershipSince;
private Date membershipUntil;
}
Slide:
#Entity
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#ToString(exclude = "editor")
#Table(name = "slides")
public class Slide {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private boolean visible;
private int order;
private Date edited;
#ManyToOne
#JoinColumn(name = "editor_id")
private User editor;
private String title;
private String text;
private String picture;
}
Hibernate config specifics:
spring.jpa.hibernate.ddl-auto = update
spring.datasource.initialization-mode=always
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
And the error:
Hibernate: create table users (id integer not null auto_increment, bio varchar(255), cohort_number integer not null, company varchar(255), email varchar(255), email_visible bit not null, enabled bit not null, function varchar(255), linked_in varchar(255), membership varchar(255), membership_since datetime, membership_until datetime, name varchar(255), password varchar(255), phone varchar(255), phone_visible bit not null, position varchar(255), role varchar(255), surname varchar(255), token varchar(255), username varchar(255), primary key (id)) engine=MyISAM
Hibernate: alter table slides add constraint FKobqxptfxg36ls278o63ouq369 foreign key (editor_id) references users (id)
2020-08-11 14:27:48.201 WARN 8224 --- [ restartedMain] o.h.t.s.i.ExceptionHandlerLoggedImpl : GenerationTarget encountered exception accepting command : Error executing DDL "alter table slides add constraint FKobqxptfxg36ls278o63ouq369 foreign key (editor_id) references users (id)" via JDBC Statement
...
Caused by: java.sql.SQLSyntaxErrorException: Table '32293814_alumnicemba.slides' doesn't exist
Found the problem:
private int order;
"order" is not allowed as a field name here and Hibernate was encountering an error when trying to create the slides table but not logging that error. I've renamed the field to "sorting" and it works now.
We faced a problem in production which we could not reproduce so far. The error message is org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "token_pkey"
While it is clear what this error message is telling us, this error happened only once or better said during a time window of about 1 hour and until now and we cannot reproduce it.
We use Postgres 11.5 and did scale this Spring Boot App from 1 Node to 3 Nodes (and back to 1 Node). We are running this on Heroku. My current hypothesis is, that JPA does some caching of the next/last primary key value with #GeneratedValue(strategy = GenerationType.IDENTITY) and therefore if one node inserts a new row, the other node could still have the old value? If that is true, how can it be avoided?
Here is the code. Can you spot any problems with it?
create table token
(
id bigserial primary key,
user_id bigint unique references user_ (id),
access_token varchar(255),
code varchar(255),
expires_time_stamp bigint,
refresh_token varchar(255),
event_sync_token varchar(255)
);
Java JPA Entity Class
#Entity
public class Token {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "user_id", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
private User user;
private String code;
private String accessToken;
private String refreshToken;
private Long expiresTimeStamp;
private String eventSyncToken;
}
Method creating the Token
public void initTokensFromCode(String code) {
// ... skipped some non relevant lines
Token token = googleTokenRepository.findByUserId(authenticationService.getCurrentUser().getId())
.orElse(new Token());
token.setUser(authenticationService.getCurrentUser());
token.setCode(code);
token.setAccessToken((String) jsonObject.get("access_token"));
token.setRefreshToken(refresh_token);
token.setExpiresTimeStamp(expiresTimestamp((long) jsonObject.get("expires_in")));
repository.save(token);
}
Repository (org.springframework.data.repository.CrudRepository)
public interface TokenRepository extends CrudRepository<Token, Long> {
Optional<Token> findByUserId(#Param("user_id") long userId);
}
I use JPA in a Spring application configured to use embedded H2 database.
I have a User entity defined like this:
#Entity
#SequenceGenerator(name = "myseq", sequenceName = "MY_SEQ", initialValue = 1000, allocationSize = 1)
public class User {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "myseq")
private Long id;
#Column(name = "USERNAME")
private String userName;
#Column(name = "PASSWORD_ENCODED")
private String passwordEncoded;
#ManyToMany
#JoinTable(name = "USER_ROLES", joinColumns = #JoinColumn(name = "USER_ID", referencedColumnName = "ID"), inverseJoinColumns = #JoinColumn(name = "ROLE_ID", referencedColumnName = "ID"))
private Set<Role> roles;
}
//getters
}
Context is defined like this:
#Configuration
#EnableWebMvc
#EnableWebSecurity
#EnableAutoConfiguration
#EnableJpaRepositories(basePackages = "my.package")
#EntityScan(basePackages = "my.package")
#ComponentScan(basePackages = "my.package" )
public class AuthenticationWebAppContext extends WebSecurityConfigurerAdapter {
}
I can see from the log generated that MY_SEQ is generated. However, initialValue and allocationSize are completely ignored and the sequence is not assigned to the id field of USER
17:22:29.236 [main] DEBUG org.hibernate.SQL - create sequence my_seq start with 1 increment by 1
17:22:29.237 [main] DEBUG org.hibernate.SQL - create table role (id bigint generated by default as identity, name varchar(255), primary key (id))
17:22:29.248 [main] DEBUG org.hibernate.SQL - create table user (id bigint not null, password_encoded varchar(255), username varchar(255), primary key (id))
So, when a row insert is attempted by data.sql file, I got the following error:
Caused by: org.h2.jdbc.JdbcSQLException: NULL not allowed for column "ID"; SQL statement:
INSERT INTO user (USERNAME, PASSWORD_ENCODED) VALUES ('user1', '<some_giberish>') [23502-194]
What I am missing?
Your JPA set-up is correct but you have to keep in mind that the persistence provider will only take care of generating the id for you (additional query to the database for the next value of the sequence) when inserting through Hibernate or JPA API.
This will not happen when you perform the insertions 'by hand' in the data.sql file. You would have to invoke the sequence manually there:
INSERT INTO user (ID, USERNAME, PASSWORD_ENCODED)
VALUES (NEXTVAL('my_seq')'user1', '<some_giberish>')
Edit
This property: spring.jpa.hibernate.use-new-id-generator-mappings or hibernate.id.new_generator_mappings=true (if your not using spring boot) would allow for initialValue feature support.
I'd like to use unidirectional relationship for my JPA instances (Hibernate 4.3.10)
RegionalCountry -> RegionalArea1 -> RegionalArea2
#Entity
public class RegionalCountry {
#Id
#Column(unique = true, nullable = false, updatable = false, length = 36)
private String uuid = UUID.randomUUID().toString();
private String countryName;
private String countryCode;
#OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
private List<RegionalArea1> regionalArea1;
...//getters&setters
}
#Entity
public class RegionalArea1 {
#Id
#Column(unique = true, nullable = false, updatable = false, length = 36)
private String uuid = UUID.randomUUID().toString();
private String area1Name;
private String area1Code;
#OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
private List<RegionalArea2> regionalArea2;
...//getters&setters
}
#Entity
public class RegionalArea2 {
#Id
#Column(unique = true, nullable = false, updatable = false, length = 36)
private String uuid = UUID.randomUUID().toString();
private String area2Name;
private String area2Code;
...//getters&setters
}
Then I want to use Spring JpaRepository to fetch the country and its regional area instances by country code:
public interface RegionalCountryRepository extends JpaRepository<RegionalCountry, UUID> {
public RegionalCountry findOneByCountryCode(String countryCode);
}
When I call
regionalCountryRepository.findOneByCountryCode(countryCode);
SQLException occurs: Unknown column 'regionalar0_.regional_country' in 'field list'
the same exception is for regionalCountryRepository.findAll();
Is there a way to use unidirectional relationship between regional instances and do not get this error?
Surprisingly, unit tests with embedded db work well for the code above, but when we deal with the real MySQL database the exception occurs.
#Test
public void testFindByCountryCode() {
southernArea = new RegionalArea1();
southernArea.setArea1Code("00");
southernArea.setArea1Name("SOUTHERN");
chejuDoArea = new RegionalArea1();
chejuDoArea.setArea1Code("00");
chejuDoArea.setArea1Name("CHEJU-DO");
korea = new RegionalCountry();
korea.setCountryName("Korea, Republic of");
korea.setCountryCode("KOR");
korea.setRegionalArea1s(Arrays.asList(southernArea, chejuDoArea));
repository.save(korea);
RegionalCountry countryFetched = repository.findOneByCountryCode("KOR");
Assert.assertNotNull(countryFetched);
}
Update: the schema is the following
CREATE TABLE REGIONAL_AREA2(
UUID VARCHAR(36) NOT NULL,
AREA2CODE VARCHAR(255),
AREA2NAME VARCHAR(255)
);
CREATE TABLE REGIONAL_AREA1(
UUID VARCHAR(36) NOT NULL,
AREA1CODE VARCHAR(255),
AREA1NAME VARCHAR(255)
);
CREATE TABLE REGIONAL_AREA1_REGIONAL_AREA2(
REGIONAL_AREA1_UUID VARCHAR(36) NOT NULL,
REGIONAL_AREA2_UUID VARCHAR(36) NOT NULL
);
CREATE TABLE REGIONAL_COUNTRY(
UUID VARCHAR(36) NOT NULL,
COUNTRY_CODE VARCHAR(255),
COUNTRY_NAME VARCHAR(255)
);
CREATE TABLE REGIONAL_COUNTRY_REGIONAL_AREA1(
REGIONAL_COUNTRY_UUID VARCHAR(36) NOT NULL,
REGIONAL_AREA1_UUID VARCHAR(36) NOT NULL
);
There may be several reasons:
I do not see any mapping from your class variables to table field regional_country. Please make sure to use annotation #Column to specify the correct table field which the variable maps to. For instance, if variable countryCode maps to table field country_code, you should annotate like this: #Column(name = "country_code") private int countryCode;
For variables private String countryName; private String countryCode; if they have a mapping field in your db schema, please use #Column to annotate them
It would be helpful if you provide more information about your question: e.g., your db schema.
I try to reproduce your problem using just Hibernate Session without any JpaRepository. I have to change mapping for all collection associations from List to Set cause of the "cannot simultaneously fetch multiple bags" error
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<RegionalArea1> regionalArea1;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<RegionalArea2> regionalArea2;
Everything works fine without any errors. May be, It will help you too. If It will no help:
Hibernate thinks that the REGIONAL_COUNTRY_REGIONAL_AREA1 join table has the regional_country column, but this table has the REGIONAL_COUNTRY_UUID. So try to specify join column names by #JoinTable annotation, or recreate database schema, or change the naming strategy, if you specify it.
SQL generated by Hibernate for search country by country code
select
this_.f_uuid as f_uuid1_3_2_,
this_.f_country_code as f_countr2_3_2_,
this_.f_country_name as f_countr3_3_2_,
regionalar2_.fk_regional_country as fk_regio1_4_4_,
regionalar3_.f_uuid as fk_regio2_4_4_,
regionalar3_.f_uuid as f_uuid1_0_0_,
regionalar3_.f_area1code as f_area2_0_0_,
regionalar3_.f_area1name as f_area3_0_0_,
regionalar4_.fk_regional_area1 as fk_regio1_1_5_,
regionalar5_.f_uuid as fk_regio2_1_5_,
regionalar5_.f_uuid as f_uuid1_2_1_,
regionalar5_.f_area2code as f_area2_2_1_,
regionalar5_.f_area2name as f_area3_2_1_
from
spring_regional_countries this_
left outer join
spring_regional_countries_regional_area1s regionalar2_
on this_.f_uuid=regionalar2_.fk_regional_country
left outer join
spring_regional_area1s regionalar3_
on regionalar2_.fk_regional_area1=regionalar3_.f_uuid
left outer join
spring_regional_area1s_regional_area2s regionalar4_
on regionalar3_.f_uuid=regionalar4_.fk_regional_area1
left outer join
spring_regional_area2s regionalar5_
on regionalar4_.fk_regional_area2=regionalar5_.f_uuid
where
this_.f_country_code=?
Thanks for all answers but the problem was in REGIONAL_COUNTRY_REGIONAL_AREA1 table column names. Postfix _UUID at the end of the column name confuses MySQL.
It's possible to fix this problem renaming columns of intermediate datatables
DROP TABLE IF EXISTS REGIONAL_AREA1_REGIONAL_AREA2;
DROP TABLE IF EXISTS REGIONAL_AREA1_REGIONAL_AREA2;
CREATE TABLE REGIONAL_AREA1_REGIONAL_AREA2(
REGIONAL_AREA1 VARCHAR(36) NOT NULL,
REGIONAL_AREA2 VARCHAR(36) NOT NULL
);
CREATE TABLE REGIONAL_COUNTRY_REGIONAL_AREA1(
REGIONAL_COUNTRY VARCHAR(36) NOT NULL,
REGIONAL_AREA1 VARCHAR(36) NOT NULL
);
I've created the following scenario:
#javax.persistence.Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class MyEntity implements Serializable{
#Id
#GeneratedValue
protected Long id;
...
#ElementCollection
#CollectionTable(name="ENTITY_PARAMS")
#MapKeyColumn (name = "ENTITY_KEY")
#Column(name = "ENTITY_VALUE")
protected Map<String, String> parameters;
...
}
As well as:
#javax.persistence.Entity
public class Sensor extends MyEntity{
#Id
#GeneratedValue
protected Long id;
...
// so here "protected Map<String, String> parameters;" is inherited !!!!
...
}
So running this example, no tables are created and i get the following message:
WARNUNG: Got SQLException executing statement "CREATE TABLE ENTITY_PARAMS (Entity_ID BIGINT NOT NULL, ENTITY_VALUE VARCHAR(255), ENTITY_KEY VARCHAR(255), Sensor_ID BIGINT NOT NULL, ENTITY_VALUE VARCHAR(255))": com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Duplicate column name 'ENTITY_VALUE'
I also tried overriding the attributes on the Sensor class...
#AttributeOverrides({
#AttributeOverride(name = "ENTITY_KEY", column = #Column(name = "SENSOR_KEY")),
#AttributeOverride(name = "ENTITY_VALUE", column = #Column(name = "SENSOR_VALUE"))
})
... but the same error.
EDIT:
Okay, I'd found out that with the Inheritance strategy "JOINED" as well as with "SINGLE_TABLE" everything works fine.
Also it seems that it has nothing to do with the EclipseLink version - I tried 1.3 and 2.0.1.
END_EDIT
Can anybody help me?
Okay, I've just found out what was wrong!
In such a scenario I'd built you should couldn't use the #CollectionTable(name="ENTITY_PARAMS") annotation.
So, by just using...
#ElementCollection
#MapKeyColumn (name = "PARAM_KEY")
#Column(name = "PARAM_VALUE")
private Map parameters;
Every works fine, and the resulting tables (in MySQL) are:
CREATE TABLE Sensor_PARAMETERS (
Sensor_ID BIGINT NOT NULL,
PARAM_VALUE VARCHAR(255),
PARAM_KEY VARCHAR(255)
)
and
CREATE TABLE Entity_PARAMETERS (
Entity_ID BIGINT NOT NULL,
PARAM_VALUE VARCHAR(255),
PARAM_KEY VARCHAR(255)
)
So, without that attribute everything works fine....
Hope, nobody needs this post. Even if: "Congratulation, you found the answer!" ;-)