As WCE’s app is settling down, I’ve been itching to write a backend for my personal use. It’s just a simple database app to keep track of my tennis racquets. This can be done with Python which I’m very confortable with, and probably Django to go with it. Then, this is really a weekend project.
So, I decided to go with most unconfortable environment. Java + Spring. TBH, I was a bit impressed about Spring. When Java EE, Java Beans came out, I thought it’s a real hustle to write Java backend. You have to do so much boilerplate coding just to get things going. Looking at Spring, I can see that Spring is the thing that should have been for backend development.
So, I started writing in Java and Spring on Mac. I got totally wedged. I don’t know much about Spring, or MyBatis, or any of it. And realized – oh wait, this isn’t much different from RealWorld backend. I can probably start from the mother of all examples. Download front and backend repo, build, and it just works on Linux. Used this as a starting point, and see what it takes to make this work with PostgreSQL is a good way to go. This is my 2nd day of using Java and Spring. So, the struggles ensued. This post is about just that. But, without struggle, you cannot learn anything.
Using PostgreSQL JDBC driver
It is definitely not just a matter of setting database connection URL to PostgreSQL. First, you need to install JDBC driver. On Ubuntu, this would be
sudo apt install libpostgresql-jdbc-java
Then, tell gradle to use it.
diff --git a/build.gradle b/build.gradle
index 62d7690..7ff7df7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -48,7 +48,7 @@ dependencies {
compile('org.springframework.boot:spring-boot-starter-security')
compile('joda-time:joda-time:2.10')
compileOnly('org.projectlombok:lombok')
- runtime('com.h2database:h2')
+ runtime('org.postgresql:postgresql:9.4.1212')
testCompile 'io.rest-assured:rest-assured:3.1.1'
testCompile 'io.rest-assured:spring-mock-mvc:3.1.1'
testCompile 'org.springframework.security:spring-security-test'
URL for PostgreSQL
Point URL to the database. I didn’t want to run the PostgreSQL instance on my laptop, so it’s running on “nefertiti” which is my Linux desktop in house.
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,4 +1,9 @@
spring.jackson.deserialization.UNWRAP_ROOT_VALUE=true
+#
+spring.datasource.url=jdbc:postgresql://nefertiti:5432/my_db
+spring.datasource.username=my_db_user
+spring.datasource.password=my_db_password
+#
image.default=https://static.productionready.io/images/smiley-cyrus.jpg
jwt.secret=nRvyYC4soFxBdZ-F-5Nnzz5USXstR1YylsTd-mA0aKtI9HUlriGrtkf-TiuDapkLiUCogO3JOK7kwZisrHp6wA
jwt.sessionTime=86400
@@ -11,3 +16,6 @@ mybatis.mapper-locations=mapper/*.xml
logging.level.io.spring.infrastructure.mybatis.readservice.ArticleReadService=DEBUG
# Uncomment the following line to enable and allow access to the h2-console
#spring.h2.console.enabled=true
+#
+spring.flyway.baseline-on-migrate=true
+spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.flyway.baseline-on-migrate=true
So, what’s the last two lines added. spring.flyway.baseline-on-migrate=true
tells flyway it’s okay to create DB schema migration table when it doesn’t exist. Without this, the schema migration doesn’t take off – aka – no flyway. Oh, I’m actually not using flyway but I’m planning to use it.
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
This tells hibernate to not use blob/clob. I probably have to come back to this. Right now, this makes a column to use varchar in place of blob. This is def. not what I want. I have to come back and figure this out to use binary array type of PostgreSQL.
With this, the backend starts, and I can see the backend created necessary tables from the DB migration.
With a lot of googling, it took me a day to get this point but it’s working, and limping. Went to play tennis, ruined my car tire (unfortunate,hate New England winter) and a lot of bad words are said to the pavement.
Select statement with limit does not work
Running the backend from IntelliJ, running query is not happy. It’s a SQL syntax error coming out when retriving the articles from the database. Breakpointing at the “bad SQL exception” gave me a WOT (how can Java people live with this?). Anyhow, the exception is “PostgreSQL does not support the LIMIT ?, ?”. I stepped through the code with debugger, and came to the conclusion that the SQL statement is coming from template, not actually auto-genned. Finally, I came to a conclusion that the source code somewhere is setting up the template SQL. Once I realized this, it took my literal 10 seconds to fix this up.
--- a/src/main/resources/mapper/ArticleReadService.xml
+++ b/src/main/resources/mapper/ArticleReadService.xml
@@ -55,7 +55,7 @@
</if>
</where>
order by A.created_at desc
- limit #{page.offset}, #{page.limit}
+ limit #{page.limit} offset #{page.offset}
</select>
<select id="countArticle" resultType="java.lang.Integer">
select
@@ -93,7 +93,7 @@
<foreach index="index" collection="authors" item="id" open="(" separator="," close=")">
#{id}
</foreach>
- limit #{page.offset}, #{page.limit}
+ limit #{page.limit} offset #{page.offset}
</select>
<select id="countFeedSize" resultType="java.lang.Integer">
select count(1) from articles A where A.user_id in
@@ -105,4 +105,4 @@
<resultMap id="articleId" type="string">
<id javaType="string" column="articleId"/>
</resultMap>
-</mapper>
Conclusion
The demo app backend says it’s just a matter of setting URL to other database to use different JDBC driver. It’s pretty close to it, but not really. The source contains some dependancies to SQL dialect. PostgreSQL lacks blob/clob so this probably needs to be patched up. For now, I can move forward with my racquet database app.
P.S.
I just run the unit tests and a bunch are failing. I guess I need to wear the hardhat a little longer.