I`m using Spring Data JPA with embedded H2 database. I have two sql files:
schema.sql
CREATE TABLE SINGER (
ID INT NOT NULL AUTO_INCREMENT,
FIRST_NAME VARCHAR(60) NOT NULL,
LAST_NAME VARCHAR(60) NOT NULL,
BIRTH_DATE DATE,
CONSTRAINT UQ_SINGER UNIQUE (FIRST_NAME, LAST_NAME),
PRIMARY KEY (ID)
);
CREATE TABLE ALBUM(
ID INT NOT NULL AUTO_INCREMENT,
SINGER_ID INT,
TITLE VARCHAR(100) NOT NULL,
RELEASE_DATE DATE,
CONSTRAINT UQ_ALBUM UNIQUE (TITLE),
CONSTRAINT FK_ALBUM FOREIGN KEY (SINGER_ID) REFERENCES SINGER (ID),
PRIMARY KEY (ID)
);
data.sql
INSERT INTO SINGER (FIRST_NAME, LAST_NAME, BIRTH_DATE) VALUES ('John', 'Mayer', '1977-10-16');
INSERT INTO SINGER (FIRST_NAME, LAST_NAME, BIRTH_DATE) VALUES ('Eric', 'Clapton', '1945-03-30');
INSERT INTO SINGER (FIRST_NAME, LAST_NAME, BIRTH_DATE) VALUES ('Jorn', 'Butler', '1975-04-01');
INSERT INTO ALBUM (SINGER_ID, TITLE, RELEASE_DATE) VALUES (1, 'The Search For Everything', '2017-01-20');
INSERT INTO ALBUM (SINGER_ID, TITLE, RELEASE_DATE) VALUES (1, 'Battle Studies', '2009-11-17');
INSERT INTO ALBUM (SINGER_ID, TITLE, RELEASE_DATE) VALUES (2, 'From The Cradle', '1994-09-13');
Database configuration:
#Bean
public DataSource dataSource() {
try {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.H2)
.addScripts("db/schema.sql", "db/data.sql")
.build();
} catch (Exception ex) {
log.error("Cannot create DataSource", ex);
return null;
}
}
The problem is: schema.sql is executed while data.sql not. All test (find all data, find by id, insert, update, delete) passes successfully
Logs
INFO [main] org.springframework.jdbc.datasource.init.ScriptUtils:510 - Executed SQL script from class path resource [db/schema.sql] in 47 ms.
INFO [main] org.springframework.jdbc.datasource.init.ScriptUtils:444 - Executing SQL script from class path resource [db/data.sql]
DEBUG [main] org.springframework.jdbc.datasource.init.ScriptUtils:476 - 1 returned as update count for SQL: INSERT INTO SINGER (FIRST_NAME, LAST_NAME, BIRTH_DATE) VALUES ('John', 'Mayer', '1977-10-16')
DEBUG [main] org.springframework.jdbc.datasource.init.ScriptUtils:476 - 1 returned as update count for SQL: INSERT INTO SINGER (FIRST_NAME, LAST_NAME, BIRTH_DATE) VALUES ('Eric', 'Clapton', '1945-03-30')
DEBUG [main] org.springframework.jdbc.datasource.init.ScriptUtils:476 - 1 returned as update count for SQL: INSERT INTO SINGER (FIRST_NAME, LAST_NAME, BIRTH_DATE) VALUES ('Jorn', 'Butler', '1975-04-01')
DEBUG [main] org.springframework.jdbc.datasource.init.ScriptUtils:476 - 1 returned as update count for SQL: INSERT INTO ALBUM (SINGER_ID, TITLE, RELEASE_DATE) VALUES (1, 'The Search For Everything', '2017-01-20')
DEBUG [main] org.springframework.jdbc.datasource.init.ScriptUtils:476 - 1 returned as update count for SQL: INSERT INTO ALBUM (SINGER_ID, TITLE, RELEASE_DATE) VALUES (1, 'Battle Studies', '2009-11-17')
DEBUG [main] org.springframework.jdbc.datasource.init.ScriptUtils:476 - 1 returned as update count for SQL: INSERT INTO ALBUM (SINGER_ID, TITLE, RELEASE_DATE) VALUES (2, 'From The Cradle', '1994-09-13')
INFO [main] org.springframework.jdbc.datasource.init.ScriptUtils:510 - Executed SQL script from class path resource [db/data.sql] in 16 ms.
DEBUG [main] org.springframework.jdbc.datasource.DataSourceUtils:340 - Returning JDBC Connection to DataSource
It seems like data.sql is executed successfully, but I doesn`t see the data (in test methods) as long as I insert some.
UPDATE: I have following test methods (all they pass successfully, but in testFindAll() I don`t see any data):
#Test
void testFindAll() {
List<Singer> singers = singerRepository.findAll();
assertNotNull(singers);
displayAllSingers(singers);
}
#Test
void testInsert() {
Singer singer = createSinger();
singerRepository.insert(singer);
assertNotNull(singer.getId());
displayAllSingers(singerRepository.findAll());
}
You don`t need to worry about SingerRepository implementation, it works properly (in testInsert() you can see singerRepository.findAll() and it works, I see inserted singer).
Related
I am trying to delete the duplicates that I am getting in my database using DELETE function of my SQL with LIMIT 1 but it is showing me the "LIMIT" syntax error .
myDatabase.execSQL("CREATE TABLE IF NOT EXISTS users (name VARCHAR , age INT(3))");
myDatabase.execSQL("INSERT INTO users (name, age) VALUES ('Vaishant', 21)");
myDatabase.execSQL("INSERT INTO users (name, age) VALUES ('Tommy',4)");
myDatabase.execSQL("DELETE FROM users WHERE name = 'Vaishant' LIMIT 1");
Can someone tell me why I am getting this error and how to correct it ?
SQLite does not support LIMIT in a DELETE statement.
Use a subquery that returns the rowid of a row that contains the name that you search for:
String sql = "DELETE FROM users WHERE rowid = (SELECT rowid FROM users WHERE name = 'Vaishant' LIMIT 1)";
myDatabase.execSQL(sql);
If you want to delete the duplicate names and keep only 1, then you can do this:
DELETE FROM users
WHERE NOT EXISTS (SELECT 1 FROM users u WHERE u.name = users.name AND u.rowid < users.rowid)
or:
DELETE FROM users
WHERE rowid NOT IN (SELECT MIN(rowid) FROM users GROUP BY name)
In your delete statement you are using limit with Delete query. You should use it as below:
First add id column as primary key in your table
myDatabase.execSQL("CREATE TABLE IF NOT EXISTS users (ID INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR , age INT(3))");
change the query of delete as below
myDatabase.execSQL("DELETE FROM users
WHERE id IN
(SELECT id FROM
(SELECT id,
ROW_NUMBER() OVER (PARTITION BY name ORDER BY name) AS row_num FROM users )t
WHERE row_num > 1)");
I can't save result of select into database using JPA in Spring Boot application. The code that I use is below:
#Override
#Transactional
public void fetchAndSave() {
List<TestData> all = testDataRepository.findAllRecords();
testDataRepository.saveAll(all);
// let suppose I will save another data here that's why I need #Transactional for roll-back in case of exception
}
#Repository
public interface TestDataRepository extends JpaRepository<TestData, Long> {
#Query(value = "select raw_values.identificator AS id, raw_values.name as value from test.raw_values", nativeQuery = true)
List<TestData> findAllRecords();
}
When I call fetchAndSave with a property spring.jpa.show-sql=true I see in logs only select:
Hibernate: select raw_values.identificator AS id, raw_values.name as value from test.raw_values
In a case I don't use #Transactional I can see more requests to database in logs and values are saved:
Hibernate: select raw_values.identificator AS id, raw_values.name as value from test.raw_values
Hibernate: select testdata0_.id as id1_0_0_, testdata0_.value as value2_0_0_ from test.test_data testdata0_ where testdata0_.id=?
Hibernate: select testdata0_.id as id1_0_0_, testdata0_.value as value2_0_0_ from test.test_data testdata0_ where testdata0_.id=?
Hibernate: select testdata0_.id as id1_0_0_, testdata0_.value as value2_0_0_ from test.test_data testdata0_ where testdata0_.id=?
Hibernate: insert into test.test_data (value, id) values (?, ?)
Hibernate: insert into test.test_data (value, id) values (?, ?)
Hibernate: insert into test.test_data (value, id) values (?, ?)
I have a pretty simple table in database, DDL looks like:
create table test_data
(
id serial not null
constraint test_data_pk
primary key,
value varchar(256)
);
-- There are 3 records in table raw_values
create table table_name
(
identificator integer not null
constraint table_name_pk
primary key,
name varchar(256)
);
Can you help me to identify the reason of such behavior? I expect records to be saved into database when I use #Transactional.
The short answer for "why it does not save" is: because they are already saved.
The longer answer is Hibernate sees that these IDs has already present in DB, and it does not save them.
If you want to inset another three entities to DB, just create duplicates for these objects, with id=null and save them:
List<TestData> all = testDataRepository.findAllRecords();
List<TestData> copies = all.stream()
.map(testData -> new TestData(...)) //copy all the fields EXCEPT ID
.collect(toList());
testDataRepository.saveAll(copies);
I'm trying to use ActiveJDBC with HSQLDB:
Users.sql
CREATE TABLE users (
"ID" INTEGER GENERATED BY DEFAULT AS SEQUENCE seq NOT NULL PRIMARY KEY,
FIRST_NAME VARCHAR(100) NOT NULL,
LAST_NAME VARCHAR(100) NOT NULL
);
User.java
#IdName("ID")
public class User extends Model {....}
Main.java
User u = new User();
u.setFirstName("first_name");
u.setLastName("last_name");
u.save();
And when I try to save new row I have the following exception:
org.javalite.activejdbc.DBException: java.sql.SQLSyntaxErrorException: user lacks privilege or object not found: id, Query: INSERT INTO users (first_name, last_name) VALUES (?, ?), params: first_name,last_name
I think that problem in lower case in insert query. How I can fix this problem?
After googling for this HSQL exception message, I threw this code together that actually works. It uses ActiveJDBC, works with plain query and also works with instrumented model:
Base.open("org.hsqldb.jdbc.JDBCDriver", "jdbc:hsqldb:file:./target/tmp/hsql-test", "sa", "");
String create = "CREATE TABLE people (\n" +
" ID INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1) NOT NULL,\n" +
" FIRST_NAME VARCHAR(100) NOT NULL,\n" +
" LAST_NAME VARCHAR(100) NOT NULL\n" +
");";
Base.exec(create);
Base.exec("INSERT INTO people (first_name, last_name) VALUES (?, ?)", "John", "Doe");
System.out.println("===>" + Base.findAll("select * from people"));
Person p = new Person();
p.set("first_name", "Jane", "last_name", "Doe").saveIt();
System.out.println(Base.findAll("select * from people"));
System.out.println(Person.findAll());
Base.close();
As you can see, the code that creates a table is a bit different, especially around the ID column.
The model looks like this:
#IdName("ID")
public class Person extends Model {}
Basically, you had the following issues with your code:
Definition of ID column with double quotes
ID column needs to be defined as IDENTITY (do not hold my feet to the fire, I'm no HSQL expert, but t works)
The model needs to overwrite the #IdName("ID"), since ActiveJDBC defaults to lower case id, unless you change that in the table (why not?)
Keep in mind, that some things may not work, since HSQL is not on a list of supported databases.
I hope this helps!
CREATE TABLE users (
ID INTEGER GENERATED BY DEFAULT AS SEQUENCE seq NOT NULL PRIMARY KEY,
FIRST_NAME VARCHAR(100) NOT NULL,
LAST_NAME VARCHAR(100) NOT NULL
);
We got strange non-permanent error: MySQLIntegrityConstraintViolationException inside java transaction.
Imagine next code:
sql:
CREATE TABLE test (
ruleID INT(11) NOT NULL AUTO_INCREMENT,
name varchar(250),
PRIMARY KEY (ruleID)
) engine=InnoDB;
CREATE TABLE test2 (
ruleID INT(11) NOT NULL,
name varchar(250),
PRIMARY KEY (ruleID),
CONSTRAINT _FK1 FOREIGN KEY (ruleID)
REFERENCES test (ruleID)
ON DELETE CASCADE
) engine=InnoDB;
CREATE PROCEDURE proc1(
inout p_ruleID INT (11),
p_name varchar(250)
)
proc: begin
IF (p_ruleID < 1) THEN
INSERT INTO test (ruleID, name) values (null, p_name);
SELECT LAST_INSERT_ID() INTO p_ruleID;
else
UPDATE test
SET name = p_name
WHERE ruleID = p_ruleID;
SELECT p_ruleID;
END IF;
END //
CREATE PROCEDURE proc2(
p_ruleID INT (11),
p_name varchar(250)
)
BEGIN
DELETE FROM test2
WHERE ruleID = p_ruleID;
INSERT INTO test2(ruleID, name)
VALUES (p_ruleID, p_name);
END //
java:
Connection conn;
int id;
String name;
String subName;
...
conn.setAutoCommit(false);
id=1;
CallableStatement cs1 = conn.prepareCall("{call proc1(?,?)}");
cs1.setInt(1, id);
cs1.setString(2, name);
cs1.registerOutParameter(1, java.sql.Types.INTEGER);
cs1.execute();
int parentID = cs1.getInt(1);
cs1.close();
cs1 = conn.prepareCall("{call proc2(?,?)}");
cs1.setInt(1, parentID);
cs1.setString(2, subName);
cs1.execute();
...
So once during the "cs1.execute()" for "proc2" we got exception:
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:
Cannot add or update a child row:
a foreign key constraint fails (test2, CONSTRAINT '_FK1' FOREIGN KEY ('ruleID') REFERENCES 'test' ('ruleID') ON DELETE CASCADE)
We got it only once and can't repeat it.
One "guru" said - java transaction, performed by Connection, don't garanty the visibility of results between CallableStatementS.
Is it true? Or may be the truth is out there?
I am working on a project with MySQL database Java GUI.
This is my SQL script
CREATE TABLE takenservice (
ResvID INT UNSIGNED NOT NULL,
ServID INT UNSIGNED DEFAULT 0 NOT NULL,
ServUsedDate DATETIME NOT NULL
, PayStat VARCHAR(6) DEFAULT Unpaid NOT NULL,
ServRecBy VARCHAR(7) NOT NULL,
PayRecBy VARCHAR(7),
Quantity SMALLINT DEFAULT 1 NOT NULL,
PRIMARY KEY (ResvID, ServID, ServUsedDate));
Alter table takenservice
add constraint foreign key (ResvId) references reservation (ResvID);
Alter table takenservice
add constraint foreign key (ResvId) references reservation (ResvID);
I created the entity classes with Netbeans 7.0 and created 4 classes:
Service
Reservation
ServiceTaken
ServiceTakenPK
but I cant enter values to the table and it gives me an error that I am trying to enter null values in as primary keys.
I have found the bug actually in Netbeans forum which is http://netbeans.org/bugzilla/show_bug.cgi?id=105084.
and accordingly I have added the following methods to the class ServiceTaken
public int getResvID() {
return takenservicePK.resvID;
}
public int getServID() {
return takenservicePK.servID;
}
public Date getServUsedDate() {
return takenservicePK.servUsedDate;
upon inserting a new entry in the table I get this error :
Error Code: 1048
Call: INSERT INTO takenservice (PayRecBy, ServRecBy, Quantity, PayStat, ServUsedDate, ResvID, ServID) VALUES (?, ?, ?, ?, ?, ?, ?)
bind => [ddd, ddd, 0, ddd, null, null, null]
What I can do to fix this ? Please help me with this I am running out of time =/
Please try using
System.out.println(yourqueryexecution stmt);
then check whether the statement can be executed in the DB;
Find whether it sends all the values to the db;
hope this works..