FINAL EDIT
The reason why I didn't see any logs is that I was using an old version of log4j. Hibernate hbm2ddl uses slf4j for logging and so all the logs were ignored by log4j 1. Now I upgraded to log4j2 that has a slf4j bridge and I see all the errors in the log.
Godd new is that from here I can pick the conversion errors one by one and fix them, bad news (for me) is that they are a lot!
Thanks to everyone!
FINAL EDIT END
I've a very complex java7+Spring3.2.0+hibernate3 web application that works with a Postgresql database. A client now imposed as requirement to use Oracle as a database for a project. I'm having trouble figuring out the Schema use in Oracle.
The Postgresql database is divided in about 10 different schemas, plus separated schemas for the audit records. I define tables and schemas in the annotation. I.e.:
#Entity
#Table(name = "language", schema = "live")
#Audited
#AuditTable(value="language_aud", schema="live_aud")
public class Language implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Integer id;
etc...
This works quite well in Postgres. To create the database I create manually the schemas first:
CREATE SCHEMA live;
And then start the application with hibernate.hbm2ddl.auto=create. This works like a charm and the database is correctly built.
Now moving to Oracle I have problems with the schema definition. I tried the CREATE SCHEMA statement with no succes but then found out that in Oracle schema=user (very strange to me but there must be a reason). So I created all the users to match the Schema structure. I.e.:
CREATE USER live IDENTIFIED BY 'password';
** EDIT **
But this still doesn't work, when I run the application the tables are not created by hibernate (I fixed the previous exception adding try/catch to postProcess methods, they failed as the database was not created)
I can get the connection correctly with Oracle, I use the parameter:
jdbc.driver=oracle.jdbc.driver
jdbc.url=jdbc:oracle:thin:#//localhost:1521/XE
jdbc.username=system
jdbc.password='password'
hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
What I am doing wrong? do I have to create the schemas in a different way? or is the system user not to have the right privileges?
The application is shared by many clients so a requirement I have is to try to avoid to change completely the structure removing the schemas. In a perfect world the application should be database indipendant so work with any database.
Thank you for any help you can give and please ask if you need more info.
Mattia
In oracle id is not auto generated. You have to manage it manually or use a sequence.
Do not use
#GeneratedValue(strategy = GenerationType.AUTO)
Try this
#Id
#SequenceGenerator(name="language_generator", sequenceName="language_sequence")
#GeneratedValue(generator="language_generator")
#Column(name = "id")
private Integer id;
Make sure you do this for all your models
** EDIT **
Try this when creating the Oracle user:
SQL> CREATE USER live IDENTIFIED BY 'password'
2 QUOTA UNLIMITED ON SYSTEM
3 QUOTA UNLIMITED ON SYSAUX;
SQL> GRANT CREATE SESSION TO live;
SQL> GRANT CREATE TABLE TO live;
SQL> GRANT SELECT_CATALOG_ROLE TO live;
SQL> GRANT EXECUTE_CATALOG_ROLE TO live;
SQL> EXECUTE DBMS_STREAMS_AUTH.GRANT_ADMIN_PRIVILEGE(grantee => 'live');
SQL> GRANT UNLIMITED TABLESPACE TO live;
SQL> GRANT RESOURCE TO live;
Lock it down when you move to production. As in take away some of the privileges like ability to drop tables etc. PS do not call your model user. Just as a precaution.
Related
I want to save the data exactly in in-memory mode using h2 as database.
So I have application.properties file with configurations like:
spring.h2.console.enabled=true
spring.jpa.show-sql=true
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username=...
spring.datasource.password=...
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.session.jdbc.initialize-schema=always
using specific parameters:
DB_CLOSE_DELAY=-1 - to keep the database open/to keep the content of an in-memory database as long as the virtual machine is alive
DB_CLOSE_ON_EXIT=FALSE - to disable database closing on exit
as mentioned in documentation of H2 database.
At the same time, I'm using Entity for saving in database:
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
#Entity(name = "address_entity")
#Table(name = "addresses")
public class GeolocationAddress {
public GeolocationAddress(GeolocationAddressDTO geolocationAddressDTO) {
this.displayName = geolocationAddressDTO.getDisplayName();
this.lat = geolocationAddressDTO.getLat();
this.lon = geolocationAddressDTO.getLon();
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "address_id")
private Integer id;
private String displayName;
private String lat;
private String lon;
}
After sending the request, I'm getting in console information from Hibernate:
Hibernate: insert into addresses (address_id, display_name, lat, lon) values (null, ?, ?, ?)
Hibernate: insert into addresses (address_id, display_name, lat, lon) values (null, ?, ?, ?)
but after refreshing H2 database in Data Source using Ctrl+F5 combination or via:
key, I don't see there any data.
To research this behavior, I've checked formulations in documentation:
"For certain use cases (for example: rapid prototyping, testing, high
performance operations, read-only databases), it may not be required
to persist data, or persist changes to the data. This database
supports the in-memory mode, where the data is not persisted."
and from some articles, e.g.:
"By design, the in-memory database is volatile, and data will be lost
when we restart the application."
or this one:
"H2 is an in memory database. Its not a persisted database.
H2 is a great tool for learning because you need zero setup."
but I still don't fully understand, can I save data in this mode while the application is running?
if I change to another mode, e.g.:
spring.datasource.url=jdbc:h2:file:./data/demo;DB_CLOSE_ON_EXIT=FALSE;AUTO_SERVER=TRUE
as mentioned here and here.
Then, yes, I see data in database after refreshing and data will be saved in format like:
but can I do the same with in-memory or not?
I would be grateful for any clarification on this.
UPD #1:
For instance, it's indicated here:
"Most in-memory database systems offer persistence, at least as an
option."
UPD #2:
From H2-console I see the data using in-memory mode, but from Intellij Idea - not:
UPD #3:
As mentioned #Turing85, I've tested url: jdbc:h2:tcp://localhost/mem:db1 to access the database over TCP/IP or TLS, but this link was invalid in Data Source.
After some investigation, I've found useful information:
":mem will not work for TCP connections. so remove :mem from
connection url"
So alternative way like: jdbc:h2:./data/testdb;AUTO_SERVER=TRUE;AUTO_SERVER_PORT=10990
also works.
UPD #4:
Probably, this answer also is related to my question.
As mentioned Turing85, Elliott Frisch and M. Deinum, in-memory database is isolated to the running Spring Boot app, that's why I need to use other modes, e.g.:
spring.datasource.url=jdbc:h2:file:./data/testdb;DB_CLOSE_ON_EXIT=FALSE;AUTO_SERVER=TRUE
or
spring.datasource.url=jdbc:h2:./data/testdb;AUTO_SERVER=TRUE;AUTO_SERVER_PORT=10990
I'm trying to test my Spring Boot repositories using DataJpaTest. I'm using MySQL, so all of my models are using IDENTITY for id generation:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
But as you can see from the screenshot below, when I run my tests, Hibernate sets "generated by default as identity" for the ids of all of my models except for User and Property:
This makes it so that I cannot create users (or properties) in my tests, since GenerationType.IDENTITY sets always sets the id to null before sending it to the db, which results in the following error:
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
Does anyone know why this is happening? And, of course, more important than the why is what can I do to fix it? :)
Update
To simplify the problem a bit and provide different errors for different things I've tried...
My DataJpaTests are using H2, which I guess is automagically generating the db structure from the code. My real DB is MYSQL, which is generated in a separate project.
Scenario 1:
When I set GenerationType to IDENTITY, the live DB works, but the test DB gives me could not execute statement; SQL [n/a]; constraint [null].
Scenario 2:
When I set GenerationType to AUTO, the test DB works, but the live DB gives me Table 'tablename.hibernate_sequence' doesn't exist.
Scenario 3:
Trying to make MYSQL work with GenerationType AUTO. I have found nothing in quite a lot of searching on how to tell Hibernate to default MYSQL to identity instead of table. I've found rather a lot saying to never use table and that overriding this is impossible without changing the Hibernate source code. This is a bunch of BS that makes me wonder what the Hibernate developers are smoking.
Scenario 4:
Trying to make H2 work with GenerationType IDENTITY. I've had some luck here with the following:
Putting spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MODE=MYSQL in a test.properties file.
Annotating my Test class with #TestPropertySource(locations= "classpath:test.properties") and #AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
This gets rid of the null constraint error, but instead I'm now getting The database returned no natively generated identity value. Presumably, this is because, while the actual SQL code had auto_increment for the id, whatever magic is being used to generate the table for H2 isn't getting it there.
Addendum: The thing that is really frustrating about all of this is that it works totally fine for most of the tables. Out of the more than 20 tables in my DB, all but two of them auto generate and increment their ids just fine using IDENTITY. It makes no sense at all that some of them would work and some of them wouldn't.
The problem was another model with #Table(name = "user") as an annotation. That model also had the Id column defined, but without a generated value. With the conflict, Hibernate chose that one to define the id.
MySql works better with
#GeneratedValue(strategy = GenerationType.AUTO)
its also better because it produces auto-increment primary key in most RDBMS
I want to have tables located in different database schemas. But unfortunately, I can't achieve this with Spring Boot. Here steps to reproduce it.
Create a new Spring Boot project on http://start.spring.io version 2.0.5 (with derby and PostgreSQL dependencies)
Create simple entity
#Entity
#Table(name = "my_table")
public class MyTable {
#Id Integer id;
}
Add only next property to the application.properties with value 'update' or 'create' (if you try 'create-drop' then you get another error described here: https://github.com/spring-projects/spring-boot/issues/7706#issuecomment-268798059). Now Derby datasource will be used by default.
spring.jpa.hibernate.ddl-auto=create
Run a generated test or main class. Be sure all works fine.
Modify the entity, add attribute schema to the #Table annotation. Now the entity looks like:
#Entity
#Table(name = "my_table", schema = "my_schema")
public class MyTable {
#Id Integer id;
}
Run a test (or main class). This time I get an error while Spring Boot initialization process "java.sql.SQLSyntaxErrorException: Schema 'MY_SCHEMA' does not exist":
Full log listing is available here: https://gist.github.com/asaushkin/8d767c92b2e7025dd359f7be43eefdd6
Check on PostgreSQL. This error reproduces on a PostgreSQL instance too. Without the 'schema' attribute Spring Boot app runs perfect, but as soon as this attribute appears on the #Table annotation the exceptions are thrown.
Full log is here: https://gist.github.com/asaushkin/dd0d677964556bf943c4f013d4785372
My question is: why are schemas not created by Spring Boot?
These options can't resolve this issue too:
spring.jpa.properties.javax.persistence.schema-generation.create-database-schemas=true
spring.jpa.properties.hibernate.hbm2dll.create_namespaces=true
Links
https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#configurations-hbmddl
https://docs.spring.io/spring-boot/docs/current/reference/html/howto-data-access.html#howto-configure-jpa-properties
Update (11 March 2019):
I've just check the current behavior of the issue. I wonder, but currently with Derby driver all works fine and the table is created with the specified schema. But in PostgreSQL an error continues exists.
Generated SQL (for PostgreSQL) is:
create table my_schema.my_table (id int4 not null, primary key (id))
Check that are you specifying the database dialect in the application.properties file or not for more check this thread.
Unable to get spring boot to automatically create database schema
I had the same problem with PostgreSQL and JPA (ERROR o.h.e.jdbc.spi.SqlExceptionHelper - ERROR: relation "schema.table" does not exist) and I figured out this solution.
In your entities classes, add escape characters \", between database element´s name. For instance:
Use this form:
#Table(name = "\"USUARIO\"", schema="\"INVENTARIODB\"")
Rather than a typical way
#Table(name = "USUARIO", schema="INVENTARIODB")
The same applies for columns names
#Column(name = "\"ID\"", nullable = false, updatable = false)
private Long id;
Rather than
#Column(name = "ID", nullable = false, updatable = false)
private Long id;
UPDATE:
I discovered the reason that was causing the problem. I used Valentina Studio to create my DB, if I use capital letters (MYTABLE), instead lower-case letters (mytable) to create my tables, I had to use double quotes inside SQL statements. This is because PostgreSQL is case sensitive. If you can´t change your database then use my last solution. Also is a good idea to enable spring.jpa.show-sql=true property, so you can see hibernate´s queries and know what´s going on.
Rename spring.jpa.properties.javax.persistence.schema-generation.create-database-schemas to spring.jpa.properties.javax.persistence.create-database-schemas. In other words, remove '.schema-generation'.
I just had the same problem not with PostgreSQL but H2 - schemas weren't being created. But, as I've discovered, the problem is not with H2 (or, likely, PostgreSQL) but, rather, Hibernate (it deviates from the standard, regarding that nomenclature). That likely means that this solution will work for you too.
I have the "master_seq" defined in 2 schemes. I have a table in schema_2 say table_2. Schema_1 has been provided insert grant on table_2 and its master_seq. The problem is, I am trying to insert a record in table_2 from schema_1 (From the spring boot app I am running) and it is using schema_1's master_seq whereas I want it should use schema_2's master_seq.
In short, I want to use master_seq of the schema where the table is.
Below is the code sample:
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="MASTER_SEQ")
#SequenceGenerator(name="MASTER_SEQ",sequenceName="MASTER_SEQ",allocationSize=1)
public Long getId() {
return id;
}
Do I need to use another schema name in code somehow? But schema name keeps on changing as per the different environment.
Thanks in advance
You can try accessing the sequence by appending the schema name to sequence name:
#SequenceGenerator(name="MASTER_SEQ",sequenceName="schema_2.MASTER_SEQ",allocationSize=1)
I have an issue testing a Hibernate application which queries multiple catalogs/schemas.
The production database is Sybase and in addition to entities mapped to the default catalog/schema there are two entities mapped as below. There are therefore three catalogs in total.
#Table(catalog = "corp_ref_db", schema = "dbo", name = "WORKFORCE_V2")
public class EmployeeRecord implements Serializable {
}
#Table(catalog = "reference", schema = "dbo", name="cntry")
public class Country implements Serializable {
}
This all works in the application without any issues. However when unit testing my usual strategy is to use HSQL with hibernate's ddl flag set to auto and have dbunit populate the tables.
This all works fine when the tables are all in the same schema.
However, since adding these additional tables, testing is broken as the DDL will not run as HSQL only supports one catalog.
create table corp_ref_db.dbo.WORKFORCE_V2
user lacks privilege or object not found: CORP_REF_DB
If there were only two catalogs then I think it would maybe be possible to get round this by changing the default catalog and schema in the HSQL database to that one explicitly defined:
Is there any other in-memory database for which this might work or is there any strategy for getting the tests to run in HSQL.
I had thought of providing an orm.xml file which specified the default catalog and schema (overiding any annotations and having all the defined tables created in the default catalog/schema) however these overrides do not seem to be observed when the DDL is executed i.e. I get the same error as above.
Essentially, then I would like to run my existing tests and either somehow have the tables created as they are defined in the mappings or somehow override the catalog/schema definitions at the entity level.
I cannot think of any way to achieve either outcome. Any ideas?
I believe H2 supports catalogs. I haven't used them in it myself, but there's a CATALOGS table in the Information Schema.
I managed to achieve something like this in H2 via IGNORE_CATALOGS property and version 1.4.200
However, the url example from their docs did not seem to work for me, so I added a statement in my schema.xml:
SET IGNORE_CATALOGS = true;