Skip to main content

JHipster, JPA, and MySQL database character set

After I generated my entities and got all the basic functionality of a JHipster application running, I started working on a multi-table join query that I want to use for reporting.  I don't want to query individual records and then aggregate my query results into a report using java; this is inefficient, and a single query can do all of the work for me, keeping the database doing what it does best.  So I wrote the query, and I then had to figure out how best to use this query in the JHipster framework.

The best option seems to be using JPA's native SQL API and mapping results to a custom data object.  I can inject an EntityManager, and that allows me to call createNativeQuery().  I can then call setParameter() for each parameter needed by referencing my parameters by name like this:

Query
select foo
from bar
where some_column = :columnParam

API
nativeQuery.setParameter("columnParam", <valueToUse>)

So far, so good.  When I make this call at runtime, however, I get this error:

org.springframework.orm.jpa.JpaSystemException: could not extract ResultSet; nested exception is org.hibernate.exception.GenericJDBCException: could not extract ResultSet
...
...
Caused by: java.sql.SQLException: Illegal mix of collations (utf8_general_ci,IMPLICIT) and (utf8mb4_general_ci,COERCIBLE) for operation '='

Some googling suggests that this is an old/known problem for MySQL, though it is new to me.  The problem is that the code and configuration generated by JHipster runs spring boot such that it assumes a collation / character set that supports utf8mb4, which is a more complete utf8 set that can represent emojis, etc.  While I have no need for this, I don't want to walk down a backwards road in the learning process.

Fortunately, after searching around a lot, I came to a fairly simple answer: re-create the database (JHipster helped with this by configuring and using liquibase to generate database contents on startup -- hurray!) using the desired collation and character set for the database in MySQL.  For me, that ended up being:

Character set: utf8mb4 -- UTF-8 Unicode
Collation: utf8mb4_general_ci

After I made this change, the query started working successfully.

Comments

Popular posts from this blog

Spring Security - Authority vs Role

I have spent a lot of time recently trying to understand the difference between Authority and Role in Spring Security.  This is a brief review of what I found. When creating a UserDetailsService or overriding configure(AuthenticationManagerBuilder auth) in the security config class that extends WebSecurityConfigurerAdapter, I basically get complete control over what I populate inside of the UserDetails that is used/returned.  This is important because the UserDetails interface really only cares about how to return one thing: Collection<? extends GrantedAuthority> getAuthorities(); A GrantedAuthority just seems like a glorified String wrapper that names some thing.  The question is... what is that thing? This is where the subtle difference between Authority and Role comes into play. I think that Role is an older thought/construct that automatically gets plugged into Authority if we just create a user with a Role.  But completely forget about the code and classes for a mi

JHipster, Liquibase, MySQL, and initializing data, including booleans!

When generating a data model from JHipster JDL, we will often declare entities with Boolean fields.  I have so far abandoned H2 as a database because of liquibase issues, and both my dev and production databases will be MySQL.  This is relevant to the Boolean field desire there is a long history in software development of how to store Boolean data types in a SQL database whose standards classically do not support Boolean. In the current JHipster/Liquibase incarnation, tables in MySQL are generated for us, which is really nice.  The Boolean data types are stored as BIT  (1).  This is not a problem so far -- most developers seem to agree now that as a best practice, we should store values in databases as false = 0 and true = 1, and a BIT(1) is a great, simple way to do that. An issue arises when we try to use liquibase to set/update our database to the desired starting state.  For my project, I've chosen gradle instead of maven as a build tool, and gradle has a plugin for liquiba

SQL, Booleans, JPA, and Hibernate

For a long time, SQL and Booleans have not gotten along.  Standards for SQL never really addressed the need for boolean data -- it was assumed that some other data type could easily just step in and address this need.  The result was a lot of different data models for boolean values.  Here are some examples. TRUE or FALSE T or F Y or N 1 or 0 <any value> vs NULL The internet shows the debate has gone on , even as SQL standards have changed .  Coming from a professional background with Oracle, I struggled with this across my teams because everyone had a different opinion, which led to a lot of time wasted due to debate. This said, I appreciate working with native queries in hibernate's JPA implementation against MySQL.  MySQL supports a BIT data type I recently discussed .  When we represent data in MySQL with BIT and restrict the length to just 1 (ie 1 bit), Hibernate JPA magically knows to query and return this data as a Boolean in the data returned by getResul