I am trying to create a web application using Micronaut and need to get information from travelLog table using Spring JdbcTemplate and plain
SQL. I was using this tutorial https://www.greggbolinger.com/posts/using-springs-jdbctemplate-with-micronaut/ to solve this, but I faced the following problem:
30.869 [default-nioEventLoopGroup-1-2] ERROR i.m.h.s.netty.RoutingInBoundHandler - Unexpected error occurred: StatementCallback; bad SQL grammar [SELECT * FROM travelLog]; nested exception is org.postgresql.util.PSQLException: ERROR: relation "travellog" does not exist
Position: 15
org.springframework.jdbc.BadSqlGrammarException: StatementCallback; bad SQL grammar [SELECT * FROM travelLog]; nested exception is org.postgresql.util.PSQLException: ERROR: relation "travellog" does not exist
Position: 15
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:237)
at
Here is travelLog table Schema
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet id="01" author="julia">
<createTable tableName="travelLog"
remarks="A table to contain all travel logs">
<column name="id" type="int">
<constraints nullable="false" unique="true" primaryKey="true"/>
</column>
<column name="date" type="timestamp">
<constraints nullable="false"/>
</column>
<column name="regNumber" type="varchar">
<constraints nullable="false"/>
</column>
<column name="ownersName" type="varchar(50)">
<constraints nullable="false"/>
</column>
<column name="odometerValueBeg" type="int">
<constraints nullable="false"/>
</column>
<column name="odometerValueEnd" type="int">
<constraints nullable="false"/>
</column>
<column name="departurePlace" type="varchar(255)">
<constraints nullable="false"/>
</column>
<column name="destinationPlace" type="varchar(255)">
<constraints nullable="false"/>
</column>
<column name="description" type="varchar">
</column>
</createTable>
</changeSet>
</databaseChangeLog>
Here is JdbcTemplateFactory.java
#Factory
public class JdbcTemplateFactory {
#Inject
DataSource dataSource;
#Bean
#Singleton
JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource);
}
}
Here is TravelLogService.java
#Singleton
#Requires(beans = JdbcTemplate.class)
public class TravelLogService {
private final JdbcTemplate jdbcTemplate;
public TravelLogService(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
#Transactional
public void printUsernames() {
jdbcTemplate.query("SELECT * FROM travelLog", (rs) -> {
System.out.println(rs.getString("ownersName"));
});
}
To create and query case sensitive table, columns etc, names must be quoted like this:
SELECT * FROM "travelLog"
For liquibase settings check this answer https://stackoverflow.com/a/60654633/1854103
Also please consider change your naming conventions
Related
I want to add history to my entities and I am playing arround with hibernate Envers.
I have defined Handbook and Chapter classes with the coresponding 5 tables:
HANDBOOK, HANDBOOK_AUD, CHAPTER, CHAPTER_AUD and REVINFO.
If there is no connection between the 2 entities, everithing works fine, but when I add oneToMany relationship for HANDBOOK and CHPATER the application fails to start because of missing HANDBOOK_CHAPTER_AUD table.
Thinking about it is absolutely fine to have that JoinTable, but the problem is how should define it.
Handbook entity:
#Entity
#Audited
#Getter
#Setter
#NoArgsConstructor
public class Handbook {
#Id
#SequenceGenerator(name = "HANDBOOK_ID_SEQUENCE", sequenceName = "HANDBOOK_ID_SEQUENCE", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "HANDBOOK_ID_SEQUENCE")
private Long id;
private String title;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "HANDBOOK_ID")
#AuditJoinTable(name = "REV_HANDBOOK_CHAPTER")
private Set<Chapter> chapters;
}
Chapter entity:
#Entity
#Audited
#Getter
#Setter
#NoArgsConstructor
public class Chapter {
#Id
#SequenceGenerator(name = "CHAPTER_ID_SEQUENCE", sequenceName = "CHAPTER_ID_SEQUENCE", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CHAPTER_ID_SEQUENCE")
private Long id;
private String name;
#Column(name = "HANDBOOK_ID")
private Long handbookId;
}
Tables deffinition:
<createTable tableName="REVINFO">
<column name="rev" type="integer">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="revtstmp" type="bigint"/>
</createTable>
<!-- Hibernate Envers need this seq exact to increase the revision number for versioned entities-->
<createSequence sequenceName="HIBERNATE_SEQUENCE"
startValue="1"
incrementBy="1"/>
<createTable tableName="HANDBOOK">
<column name="ID" type="bigint">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="TITLE" type="varchar2(128 char)"/>
</createTable>
<createTable tableName="REV_HANDBOOK">
<column name="ID" type="bigint"/>
<column name="TITLE" type="varchar2(128 char)"/>
<column name="REV_ID" type="integer">
<constraints foreignKeyName="FK_HANDBOOK_REV"
references="REVINFO(REV)"/>
</column>
<column name="REV_TYPE" type="smallint"/>
</createTable>
<!-- CHAPTER TABLES -->
<createTable tableName="CHAPTER">
<column name="ID" type="bigint">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="NAME" type="varchar2(128 char)"/>
<column name="HANDBOOK_ID" type="integer">
<constraints foreignKeyName="FK_CHAPTER_HANDBOOK_ID"
references="HANDBOOK(ID)"/>
</column>
</createTable>
<createTable tableName="REV_CHAPTER">
<column name="ID" type="bigint"/>
<column name="NAME" type="varchar2(128 char)"/>
<column name="HANDBOOK_ID" type="integer">
<constraints foreignKeyName="FK_CHAPTER_AUD_HANDBOOK_ID"
references="HANDBOOK(ID)"/>
</column>
<column name="REV_ID" type="integer">
<constraints foreignKeyName="FK_CHAPTER_REV"
references="REVINFO(REV)"/>
</column>
<column name="REV_TYPE" type="smallint"/>
</createTable>
NOTE:
I have edited some namings according to the hibernate envers documentation:
org:
hibernate:
envers:
audit_table_prefix: REV_
audit_table_suffix: ~ # No suffix
revision_field_name: REV_ID
revision_type_field_name: REV_TYPE
I have found out a sollution based on the series of errors hibernate gave me after running the code. Here is how I defiend the revision join table:
<createTable tableName="REV_HANDBOOK_CHAPTER">
<column name="ID" type="bigint"/>
<column name="REV_ID" type="integer">
<constraints foreignKeyName="FK_REV_HANDBOOK_CHAPTER_REV"
references="REVINFO(REV)"/>
</column>
<column name="HANDBOOK_ID" type="bigint">
<constraints foreignKeyName="FK_REV_HANDBOOK_CHAPTER_HANDBOOK"
references="HANDBOOK(ID)"/>
</column>
<column name="REV_TYPE" type="smallint"/>
</createTable>
I have been using JHipster for a long time.
But suddenly, I faced this stupid exception, and I couldn't find any solution for it.
I have exactly one other project that works without any problem, but in this project Liquibase says that it does not recognize the loadData change type.
liquibase.parser.core.ParsedNodeException: Error parsing config/liquibase/changelog/00000000000000_initial_schema.xml: Unknown change type 'loadData'. Check for spelling or capitalization errors and missing extensions such as liquibase-commercial.
I would appreciate any help🙏
Full Stacktrace:
2022-10-19T13:19:45.872+02:00 ERROR 182498 --- [all-club-task-1] t.j.c.liquibase.AsyncSpringLiquibase : Liquibase could not start correctly, your database is NOT ready: liquibase.exception.SetupException: liquibase.parser.core.ParsedNodeException: Error parsing config/liquibase/changelog/00000000000000_initial_schema.xml: Unknown change type 'loadData'. Check for spelling or capitalization errors and missing extensions such as liquibase-commercial.
liquibase.exception.ChangeLogParseException: liquibase.exception.SetupException: liquibase.parser.core.ParsedNodeException: Error parsing config/liquibase/changelog/00000000000000_initial_schema.xml: Unknown change type 'loadData'. Check for spelling or capitalization errors and missing extensions such as liquibase-commercial.
at liquibase.parser.core.xml.AbstractChangeLogParser.parse(AbstractChangeLogParser.java:25)
at liquibase.Liquibase.getDatabaseChangeLog(Liquibase.java:380)
at liquibase.Liquibase.getDatabaseChangeLog(Liquibase.java:365)
at liquibase.Liquibase.lambda$update$1(Liquibase.java:222)
at liquibase.Scope.lambda$child$0(Scope.java:180)
at liquibase.Scope.child(Scope.java:189)
at liquibase.Scope.child(Scope.java:179)
at liquibase.Scope.child(Scope.java:158)
at liquibase.Liquibase.runInScope(Liquibase.java:2414)
at liquibase.Liquibase.update(Liquibase.java:209)
at liquibase.Liquibase.update(Liquibase.java:195)
at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:314)
at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:269)
at org.springframework.boot.autoconfigure.liquibase.DataSourceClosingSpringLiquibase.afterPropertiesSet(DataSourceClosingSpringLiquibase.java:46)
at tech.jhipster.config.liquibase.AsyncSpringLiquibase.initDb(AsyncSpringLiquibase.java:118)
at tech.jhipster.config.liquibase.AsyncSpringLiquibase.lambda$afterPropertiesSet$0(AsyncSpringLiquibase.java:93)
at tech.jhipster.async.ExceptionHandlingAsyncTaskExecutor.lambda$createWrappedRunnable$1(ExceptionHandlingAsyncTaskExecutor.java:79)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: liquibase.exception.SetupException: liquibase.parser.core.ParsedNodeException: Error parsing config/liquibase/changelog/00000000000000_initial_schema.xml: Unknown change type 'loadData'. Check for spelling or capitalization errors and missing extensions such as liquibase-commercial.
at liquibase.changelog.DatabaseChangeLog.handleChildNode(DatabaseChangeLog.java:391)
at liquibase.changelog.DatabaseChangeLog.load(DatabaseChangeLog.java:339)
at liquibase.parser.core.xml.AbstractChangeLogParser.parse(AbstractChangeLogParser.java:23)
... 19 common frames omitted
Caused by: liquibase.exception.ChangeLogParseException: liquibase.parser.core.ParsedNodeException: Error parsing config/liquibase/changelog/00000000000000_initial_schema.xml: Unknown change type 'loadData'. Check for spelling or capitalization errors and missing extensions such as liquibase-commercial.
at liquibase.parser.core.xml.AbstractChangeLogParser.parse(AbstractChangeLogParser.java:25)
at liquibase.changelog.DatabaseChangeLog.include(DatabaseChangeLog.java:671)
at liquibase.changelog.DatabaseChangeLog.handleChildNode(DatabaseChangeLog.java:383)
... 21 common frames omitted
Caused by: liquibase.parser.core.ParsedNodeException: Error parsing config/liquibase/changelog/00000000000000_initial_schema.xml: Unknown change type 'loadData'. Check for spelling or capitalization errors and missing extensions such as liquibase-commercial.
at liquibase.changelog.ChangeSet.toChange(ChangeSet.java:525)
at liquibase.changelog.ChangeSet.handleChildNode(ChangeSet.java:454)
at liquibase.changelog.ChangeSet.load(ChangeSet.java:382)
at liquibase.changelog.DatabaseChangeLog.createChangeSet(DatabaseChangeLog.java:715)
at liquibase.changelog.DatabaseChangeLog.handleChildNode(DatabaseChangeLog.java:370)
at liquibase.changelog.DatabaseChangeLog.load(DatabaseChangeLog.java:339)
at liquibase.parser.core.xml.AbstractChangeLogParser.parse(AbstractChangeLogParser.java:23)
... 23 common frames omitted
My databaseChangeLog file:
<?xml version="1.0" encoding="utf-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">
<changeSet id="00000000000000" author="jhipster">
<createSequence sequenceName="sequence_generator" startValue="1050" incrementBy="50"/>
</changeSet>
<!--
JHipster core tables.
The initial schema has the '00000000000001' id, so that it is over-written if we re-generate it.
-->
<changeSet id="00000000000001" author="jhipster">
<createTable tableName="jhi_user">
<column name="id" type="${uuidType}">
<constraints primaryKey="true" nullable="false"/>
</column>
<column name="login" type="varchar(50)">
<constraints unique="true" nullable="false" uniqueConstraintName="ux_user_login"/>
</column>
<column name="password_hash" type="varchar(60)"/>
<column name="email" type="varchar(191)">
<constraints unique="true" nullable="true" uniqueConstraintName="ux_user_email"/>
</column>
<column name="image_url" type="varchar(256)"/>
<column name="activated" type="boolean" valueBoolean="false">
<constraints nullable="false" />
</column>
<column name="lang_key" type="varchar(10)"/>
<column name="activation_key" type="varchar(20)"/>
<column name="reset_key" type="varchar(20)"/>
<column name="created_by" type="varchar(50)">
<constraints nullable="false"/>
</column>
<column name="created_date" type="timestamp"/>
<column name="reset_date" type="timestamp">
<constraints nullable="true"/>
</column>
<column name="last_modified_by" type="varchar(50)"/>
<column name="last_modified_date" type="timestamp"/>
</createTable>
<createTable tableName="jhi_authority">
<column name="name" type="varchar(50)">
<constraints primaryKey="true" nullable="false"/>
</column>
</createTable>
<createTable tableName="jhi_user_authority">
<column name="user_id" type="${uuidType}">
<constraints nullable="false"/>
</column>
<column name="authority_name" type="varchar(50)">
<constraints nullable="false"/>
</column>
</createTable>
<addPrimaryKey columnNames="user_id, authority_name" tableName="jhi_user_authority"/>
<addForeignKeyConstraint baseColumnNames="authority_name"
baseTableName="jhi_user_authority"
constraintName="fk_authority_name"
referencedColumnNames="name"
referencedTableName="jhi_authority"/>
<addForeignKeyConstraint baseColumnNames="user_id"
baseTableName="jhi_user_authority"
constraintName="fk_user_id"
referencedColumnNames="id"
referencedTableName="jhi_user"/>
<addNotNullConstraint columnName="password_hash"
columnDataType="varchar(60)"
tableName="jhi_user"/>
<loadData
file="config/liquibase/data/user.csv"
separator=";"
tableName="jhi_user"
usePreparedStatements="true">
<column name="id" type="${uuidType}"/>
<column name="activated" type="boolean"/>
<column name="created_date" type="timestamp"/>
</loadData>
<dropDefaultValue tableName="jhi_user" columnName="created_date" columnDataType="${datetimeType}"/>
<loadData
file="config/liquibase/data/authority.csv"
separator=";"
tableName="jhi_authority"
usePreparedStatements="true">
<column name="name" type="string"/>
</loadData>
<loadData
file="config/liquibase/data/user_authority.csv"
separator=";"
tableName="jhi_user_authority"
usePreparedStatements="true">
<column name="user_id" type="${uuidType}"/>
</loadData>
</changeSet>
<changeSet author="jhipster" id="00000000000002" context="test">
<createTable tableName="jhi_date_time_wrapper">
<column name="id" type="BIGINT">
<constraints primaryKey="true" primaryKeyName="jhi_date_time_wrapperPK"/>
</column>
<column name="instant" type="timestamp"/>
<column name="local_date_time" type="timestamp"/>
<column name="offset_date_time" type="timestamp"/>
<column name="zoned_date_time" type="timestamp"/>
<column name="local_time" type="time"/>
<column name="offset_time" type="time"/>
<column name="local_date" type="date"/>
</createTable>
</changeSet>
</databaseChangeLog>
I spoke with #nvoxland about this yesterday, and he said that he answered a very similar question on the Liquibase forum.
The short version: you need to update to the most current Liquibase release and then try again. If that doesn't work, then you should add open.csv to the dependency.
I prepare liquibase scripts to generate my tables and relationships.
ChangeLog which create relationships:
<changeSet id="1" author="xyz">
<createTable tableName="drivers_and_tickets">
<column name="driver_id" type="varchar(36)">
<constraints nullable="false" />
</column>
<column name="ticket_id" type="varchar(36)">
<constraints nullable="false" />
</column>
</createTable>
<addForeignKeyConstraint constraintName="fk_drivers"
baseTableName="drivers_and_tickets" baseColumnNames="driver_id"
referencedTableName="drivers" referencedColumnNames="id" />
<addForeignKeyConstraint constraintName="fk_tickets"
baseTableName="drivers_and_tickets" baseColumnNames="ticket_id"
referencedTableName="tickets" referencedColumnNames="id" />
</changeSet>
<changeSet id="2" author="xyz">
<createTable tableName="tickets_and_offences">
<column name="ticket_id" type="varchar(36)">
<constraints nullable="false" />
</column>
<column name="offence_id" type="varchar(36)">
<constraints nullable="false" />
</column>
</createTable>
<addForeignKeyConstraint constraintName="fk_tickets_from_offences"
baseTableName="tickets_and_offences" baseColumnNames="ticket_id"
referencedTableName="tickets" referencedColumnNames="id" />
<addForeignKeyConstraint constraintName="fk_offences"
baseTableName="tickets_and_offences" baseColumnNames="offence_id"
referencedTableName="offences" referencedColumnNames="id" />
</changeSet>
And it ok, app is starting without any errors.
I use hibernate too, so I prepared entites:
public class DriverEntity {
#Id
#GeneratedValue(generator = "system-uuid")
#GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;
private String name;
private String surname;
private String email;
#OneToMany(mappedBy="driver")
private List<TicketEntity> tickets;
public class TicketEntity {
#Id
#GeneratedValue(generator = "system-uuid")
#GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;
private LocalDate date;
#OneToMany(mappedBy="ticket")
private Set<OffenceEntity> offences;
#ManyToOne
#JoinColumn(name="driver_id")
private DriverEntity driver;
and next when I call repository findAllDrivers I am getting error:
"Unknown column 'tickets0_.driver_id' in 'field list'" .
When I was using hibernate.ddl-auto mapping like that in entities was enough to create tables and getting records from database.
Edit:
I have checked how it looks in my DB and do not know what is wrong
I have an entity with a group of fields in primary key.
Like this :
#Entity
#Table(name = "pv_object")
#NamedQuery(name = "PreviousObject.findAll", query = "SELECT p FROM PreviousObject p")
public class PreviousObject implements Serializable {
#EmbeddedId
private FieldsDTO fieldsdto;
//
}
FieldsDTO class contains 2 String and 2 Integer.
I have and I use Liquidbase on my project in a XML file, but, I don't know how to represent this ID of 4 fields in liquidbase.
Thanks for your help :)
In <addPrimaryKey you can configure columnNames by all your columns that compose your primary key
<changeSet author="liquibase-docs" id="addPrimaryKey-example">
<addPrimaryKey
columnNames="id, name"
constraintName="pk_person"
schemaName="public"
tableName="person"
tablespace="A String"/>
</changeSet>
Assign the same primaryKeyName to them.
<createTable tableName="pv_object">
<column name="x" type="bigint">
<constraints nullable="false" primaryKey="true" primaryKeyName="PK_pv_object"/>
</column>
<column name="y" type="bigint">
<constraints nullable="false" primaryKey="true" primaryKeyName="PK_pv_object"/>
</column>
</createTable>
or add separately
<addPrimaryKey tableName="REPRESENTATIVE" columnNames="REPRESENTED_USER_ID,REPRESENTATIVE_ID"
constraintName="REPRESENTED_REPRESENTATIVE_PK" />
I have two entity Person and Address. And Person can have multiple Address.
<createTable tableName="ADDRESS">
<column name="id" type="bigint(20)" autoIncrement="true">
<constraints primaryKey="true" nullable="false" />
... //columns
</column>
</createTable>
<createTable tableName="PERSON">
<column name="id" type="bigint(20)" autoIncrement="true">
<constraints primaryKey="true" nullable="false" />
... //columns
</column>
</createTable>
<addForeignKeyConstraint
constraintName="fk_constraint_worker_phone_number"
referencedTableName="CONTACT_NUMBER" baseColumnNames="ContactNumbers"
baseTableName="WORKER" referencedColumnNames="id" />
I want 3rd table (like hibernate generate in #OneToMany mapping).
How to do this with liquibase-springboot?
If the relation is truly a OnToMany, you don't need a 3rd table. Simply, add PrimaryKeyJoinColumn.
If the address can be reused for many persons, it's a ManyToMany relation.
You can use #ManytoMany and add information about you joined table un #jointable
Well, in case of liquibase we have to create the 3rd table manually and have to apply the necessary constraints.
Create the table which manages the mapping :
<createTable tableName="PERSON_ADDRESS">
<column name="PERSON_ID" type="BIGINT">
<constraints primaryKey="true" nullable="false" />
</column>
<column name="ADDRESS_ID" type="BIGINT">
<constraints primaryKey="true" nullable="false" />
</column>
</createTable>
Apply the constraints:
1) Ensure that Persons id is unique in the mapping table
2) A foreign key relationship between ADDRESS's id and PERSON_ADDRESS's PERSON_ID
3) A foreign key relationship between PERSON's id and PERSON_ADDRESS's ADDRESS_ID
<addUniqueConstraint
columnNames="PERSON_ID" tableName="PERSON_ADDRESS"
constraintName="UK_PHONE_NUMBERS_ID" />
<addForeignKeyConstraint
constraintName="FK_ADDRESS_PERSON_ADDRESS"
referencedTableName="ADDRESS"
baseColumnNames="ADDRESS_ID"
baseTableName="PERSON_ADDRESS" referencedColumnNames="id" />
<addForeignKeyConstraint
constraintName="FK_PERSON_PERSON_ADDRESS"
referencedTableName="PERSON"
baseColumnNames="PERSON_ID"
baseTableName="PERSON_ADDRESS" referencedColumnNames="id" />