MySQL and Wicket: perform multiple queries parallel - mysql

I have Wicket (8.6) application which access a MySQL (5.7) database. The mysql connection is established as follows in the spring-context.xml:
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"
destroy-method="close">
<property name="dataSourceClassName" value="com.mysql.cj.jdbc.MysqlDataSource" />
<property name="maximumPoolSize" value="5" />
<property name="maxLifetime" value="90000" />
<property name="idleTimeout" value="90000" />
<property name="connectionTimeout" value="90000" />
<property name="dataSourceProperties">
<props>
<prop key="url">jdbc:mysql://${db.url}/${db.name}?useGmtMillisForDatetimes=true&serverTimezone=UTC&useUnicode=true&characterEncoding=utf8</prop>
<prop key="user">${db.username}</prop>
<prop key="password">${db.password}</prop>
<prop key="prepStmtCacheSize">250</prop>
<prop key="prepStmtCacheSqlLimit">2048</prop>
<prop key="cachePrepStmts">true</prop>
<prop key="useServerPrepStmts">true</prop>
</props>
</property>
</bean>
I have the problem that I need to perform a very long SQL query which can easily take several minutes depending on the selected time range. I have expirienced that while the query is executed that the whole wicket application slows down to the point, that no other query is executed anymore. BTW: the long query is just a reading query. So it should not lock a table.
I would appreciate if anybody could help me to improve the connection between wicket and the mysql so that I can still run multiple queries while the long query is executed. I am not very familiar with the configuration of MySQL
Here are some settings from the my.cnf file:
skip-external-locking
innodb_file_per_table = 1
innodb_file_format = Barracuda
internal_tmp_disk_storage_engine=MyISAM
max_allowed_packet = 16M
thread_stack = 192K
thread_cache_size = 8
query_cache_limit = 1M
query_cache_size = 16M

The problem you experience is that you keep the HTTP connection during the long period of SQL Select operation.
Wicket allows at most one request to a Page instance. I.e. once you click the button/link Get data it will make an HTTP request to a particular page instance (identified by the page id parameter in the url, ?123&...) and until the SQL operation returns the user cannot make another request to the same page instance. The user can make requests to other page instances or create new ones though!
How to solve the problem ?
Change your button/link #onClick() callback method to make an asynchronous request to MySQL, i.e. in a new thread. This way the HTTP processing thread can continue and return an empty response.
Store the DB result in some temporary place, e.g. in-memory, in temporary DB table, ...
Show the data once it is available
An easy way is to use AbstractAjaxTimerBehavior to poll every few seconds for the DB result. Once the result is ready just render it by updating the model of some invisible Wicket Component, like DataTable, and show it via AjaxRequestTarget#add(table)
Use Wicket Native WebSocket to send the DB result as soon as possible. This way there is no need to store the result temporarily. You can even stream it

Related

Apache Ignite use table names instead of cachename in a query

i have an application made in java that queries a schema many times (about 1000) for each request made by the user.
This was initially designed in this way many years ago and currently the code refactor would be too risky for the complexity of the methods.
Anyway, in order to leverage the DB effort i thought to introduce an Ignite layer to cache the biggest part of the data queried that is basically static, so i would expect that many of those queries will be faster and not on the DB anymore.
I've configured ignite properly on the server to cache the tables I need, and everything's fine until I tried to query on DBEaver or Squirrel and i discovered that the name of the tables to query on the Ignite DB is what in the ignite configuration is called property name=cacheName".
I don't want to put the hands on the code to change the queries one by one, so i would assume there's a way to keep the queries as the same as those are on the Oracle DB.
Example
In oracle DB i have
<Schema_Name>.<Table_Name>
and my queries in the code are something like
"select * from <Table_Name> where x"
In Ignite schema instead i have
cacheName.<Table_Name>
so in order to query this my query should be transformed in something like
"select * from cacheName.<Table_Name> where x"
Seems like in Ignite the cacheName is considered as a Schema, the problem is that each single table has different schema in this way. Should I consider to refactor all the queries or is there a way to mantain the same query format?
my configuration is something like this
Taken from one table configuration
<bean class="org.apache.ignite.configuration.CacheConfiguration">
<property name="name" value="<TableName>Cache"/>
<property name="cacheMode" value="PARTITIONED"/>
<property name="atomicityMode" value="ATOMIC"/>
<property name="cacheStoreFactory">
<bean class="org.apache.ignite.cache.store.jdbc.CacheJdbcPojoStoreFactory">
<property name="dataSourceBean" value="dsOracle"/>
<property name="dialect">
<bean class="org.apache.ignite.cache.store.jdbc.dialect.OracleDialect">
</bean>
</property>
<property name="types">
<list>
<bean class="org.apache.ignite.cache.store.jdbc.JdbcType">
<property name="cacheName" value="<TableName>Cache"/>
<property name="keyType" value="package.obfuscated.key"/>
<property name="valueType" value="package.obfuscated.type"/>
<property name="databaseSchema" value="<DBSchemaName>"/>
<property name="databaseTable" value="<TableName>"/>
<property name="keyFields">
<list>
<bean class="org.apache.ignite.cache.store.jdbc.JdbcTypeField">
.
.
.
[list of table fields]
.
.
Thanks a lot
In your cache definition, you can set the SQL Schema:
var cacheConfiguration = new CacheConfiguration<PersonKey,Person>()
.setName("PERSON_CACHE")
.setSqlSchema("MY_SCHEMA")
.setCacheMode(CacheMode.PARTITIONED)
.setIndexedTypes(PersonKey.class, Person.class);
var cache = ignite.<PersonKey,Person>getOrCreateCache(cacheConfiguration);
This creates a table that's visible in SQL as MY_SCHEMA.Person.

How to use hibernate.default_schema and hibernate.default_catalog

I am using Mysql and earlier in my hibernate configuration file I mentioned
<property name="hibernate.connection.url">jdbc:mysql://localhost/TestDB</property>
as the connection url where TestDB is the schema I am connecting to.
I want to specify the default schema in configuration file as
<property name="hibernate.connection.url">jdbc:mysql://localhost</property>
<property name="hibernate.default_schema">TestDB</property>
but it is not working in this way and It gives me an error saying that
java.sql.SQLException: No database selected
Can anyone help me with an example of how to use hibernate.default_schema , hibernate.default_catalog in hibernate configuration file?
You should use hibernate.default_catalog instead of hibernate.default_schema.
According to the MySql documentation the connection url should have the following format:
protocol//[hosts][/database][?properties]
where
database
The default database or catalog to open. If the database is not specified, the connection is made with no default database. In this case, either call the setCatalog() method on the Connection instance, or specify table names using the database name (that is, SELECT dbname.tablename.colname FROM dbname.tablename...) in your SQL statements. Opening a connection without specifying the database to use is, in general, only useful when building tools that work with multiple databases, such as GUI database managers.
Imagine we have the following MySql databases:
create database DB_A;
create database DB_B;
create table DB_A.TST_EMPLOYEE(
emp_id int primary key,
emp_name varchar(100)
);
create table DB_B.TST_EMPLOYEE(
emp_id int primary key,
emp_name varchar(100)
);
then we can specify the database connection in the hibernate.cfg.xml in the following way:
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306</property>
<property name="hibernate.default_catalog">DB_A</property>
<property name="hibernate.connection.username">your_user</property>
<property name="hibernate.connection.password">your_pass</property>
declare entities for DB_A.TST_EMPLOYEE and DB_B.TST_EMPLOYEE tables in the following way:
#Entity
#Table(name = "TST_EMPLOYEE")
public class EmployeeA
{
// ...
}
#Entity
#Table(name = "TST_EMPLOYEE", catalog = "DB_B")
public class EmployeeB
{
// ...
}
and then use them in the usual way. Also for the native queries you can use the {h-catalog} placeholder for the default catalog specified in the hibernate.default_catalog property.
P.S. I have to say that the catalog and schema notions can have quite different meaning from database to database. See this for the reference.

Insert some croatian letters in to mysql databse using spring hibernate

I have written hibernate query to save data in a mysql data table. UTF-8 is used inside code. The letter č is inserted into table as ?. I read several threads regarding this issue and tried following solutions.
Adding following line to the end of the jdbc url
?useEncoding=true&characterEncoding=UTF-8"
Adding following lines to the hibernate-config.xml file
**
"<prop key="hibernate.connection.useUnicode">true</prop>
<prop key="hibernate.connection.characterEncoding" >utf8</prop>
<prop key="hibernate.connection.charSet">utf8</pop>"
**
And also I have set the charset to utf8.
None of above didn't work. Are there any solution to resolve this issue?

Hibernate transaction and 'for update'

I'm trying to obtain the lock on some rows on my mysql database using the "for update" statement. To do that I create a Criteria in the middle of an Hibernate Transaction and set a lock on it.
crit = session.createCriteria(AppIosVersion.class)
.add(Restrictions.eq("version", version))
.setLockMode(LockMode.PESSIMISTIC_WRITE);
Using setLockMode the query is correctly sent to the database, this is what I see in mysql.log:
133 Query SET autocommit=0
133 Query SET autocommit=1
133 Query SET autocommit=0
133 Query select this_.Version as Version1_5_0_, this_.EditTimeStamp as EditTime2_5_0_, this_.IsActive as IsActive3_5_0_ from AppAndroidVersion this_ where this_.Version='0.2' for update
130703 16:46:03 133 Query rollback
133 Query SET autocommit=1
The problem is that the for update statement doesn't allow to acquire the lock because hibernate beginTransaction() doesn't become START TRANSACTION in mysql.
My hibernate configuration is the following (i'm not using Spring).
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/Versions?autoReconnect=true</property>
<property name="connection.username">name</property>
<property name="connection.password">password</property>
<!-- Session properties -->
<!-- <property name="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</property> -->
<property name="hibernate.current_session_context_class">org.hibernate.context.internal.ThreadLocalSessionContext</property>
<property name="hibernate.connection.autocommit">false</property>
<!-- configuration pool via c3p0-->
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.max_size">100</property>
<property name="hibernate.c3p0.min_size">10</property>
<property name="hibernate.c3p0.acquire_increment">2</property>
<property name="hibernate.c3p0.idle_test_period">180</property>
<property name="hibernate.c3p0.max_statements">0</property>
<property name="hibernate.c3p0.timeout">600</property>
<property name="hibernate.c3p0.debugUnreturnedConnectionStackTraces">true</property>
<property name="hibernate.c3p0.unreturnedConnectionTimeout">180</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
If you don't use declarative transaction management provided by container like Spring, you have to explicitly deal with the transaction.
One simple way is to implement a TransactionTemplate like Spring does.
BTW, be careful to use statement like 'select xxx for update', make sure you release the lock properly and no other transaction will touch the locked rows.

UTF8 - Hibernate/MySQL weirdness

I have a db in production where all of my tables are using utf8 / utf8_general_ci encoding. This is basically working fine except in one scenario.
What happens is that ??? are being returned for some characters (Chinese, etc); however, they are also returned correctly for the same table but via a different criteria.
I've double checked the connection parameters from Hibernate to MySQL and they have the good charset set.
I cannot understand how this can be happening. The criteria that returns the bad characters is just a simple findById:
Criteria criteria = getHibernateSession().createCriteria(CalendarEvent.class);
criteria.add(Restrictions.eq("id", id));
return (CalendarEvent) criteria.uniqueResult();
This is only happening in production on Solaris - I cannot reproduce it locally.
In your connection-string have you tried
jdbc:mysql://localhost/dbname?characterEncoding=utf8
or add JVM parameter -Dfile.encoding=utf-8 when starting your application / server
Try setting the following properties in your hibernate configuration file:
<property name="hibernate.connection.useUnicode">true</property>
<property name="hibernate.connection.characterEncoding">UTF-8</property>
<property name="hibernate.connection.charSet">UTF-8</property>