Hibernate transaction and 'for update' - mysql

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.

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.

REST API failure - org.hibernate.exception.SQLGrammarException: could not prepare statement

I'm working on a Java EE 7 project that connects to a MySQL database. When I try to make any API calls via Swagger Inspector (while the server is running and the .war is deployed, of course), I get the below errors:
org.hibernate.exception.SQLGrammarException: could not prepare statement
and
`Caused by: org.h2.jdbc.JdbcSQLException: Table "APARTMENTS" not found; SQL statement:
select apartment0_.id as id1_0_, apartment0_.apt as apt2_0_, apartment0_.city as city3_0_, apartment0_.country as country4_0_, apartment0_.numberOfBedrooms as numberOf5_0_, apartment0_.postalCode as postalCo6_0_, apartment0_.state as state7_0_, apartment0_.street as street8_0_ from apartments apartment0_ order by apartment0_.postalCode [42102-197]`
The things that stand out to me are that, first, I'm not using Hibernate to my knowledge. Pretty sure I'm using JPQL. Second, I'm not trying to connect to a H2 database. So why would I get errors related to technology I'm not using?
I'm using Intellij and was able to add the correct MySQL DB within the IDE.
Here's an example of one of the SQL query methods, in case I really am somehow using incorrect syntax:
public List findAll() {
TypedQuery query = em.createQuery("SELECT a from Apartment a order by a.postalCode",Apartment.class);
return query.getResultList();
}`
Pretty lost and confused, and new to this, so any help would be appreciated!
Edit (8/11/21 5:11PM CST) to add persistence.xml:
` <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
version="3.0">
<persistence-unit name="rentRantPU">
<class>com.rentRant.rentRant.model.Apartment</class>
<class>com.rentRant.rentRant.model.User</class>
<class>com.rentRant.rentRant.model.Review</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/rentRant"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="****"/>
</properties>
</persistence-unit>
</persistence>`

MySQL and Wicket: perform multiple queries parallel

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

Can Spring Batch use MySQL for its internal BATCH_ tables?

I have been using Oracle for this without any trouble but I then had to switch it all over to use MySQL and am seeing this error during initialization:
org.springframework.dao.DataAccessResourceFailureException: Could not obtain sequence value; nested exception is com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown table 'BATCH_JOB_SEQ' in field list
The tables are present so its something else going wrong here. After debugging I captured the actual sql it was trying to perform to get the sequence:
select BATCH_JOB_SEQ.nextval from dual;
Which is obviously an Oracle statement!
My config states this to setup the connection:
<bean id="springDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://10.252.205.5:3306/MASKNG" />
<property name="username" value="MASKNG" />
<property name="password" value="maskng" />
</bean>
Any help appreciated...
jobRepositoryFactoryBean.setDatabaseType(“mysql”)
Seems like there is no BATCH_JOB_SEQ created here in MySQL.
You need to create the sequence for that. Refer How do I create a sequence in MySQL? for creating sequence.

Auto creation of database tables using JDO

I am new to JDO and MySQL. In my project, i want that all entities should be converted in table automatically.
I had start using the JDO and defined properties like this,
javax.jdo.PersistenceManagerFactoryClass=org.datanucleus.api.jdo.JDOPersistenceManagerFactory
datanucleus.autoCreateSchema=true
datanucleus.validateTables=false
datanucleus.validateConstraints=false
datanucleus.query.sql.allowAll = true
javax.jdo.option.ConnectionDriverName=com.mysql.jdbc.Driver
javax.jdo.option.ConnectionURL=jdbc:mysql://127.0.0.1:3306/db_name
javax.jdo.option.ConnectionUserName=user
javax.jdo.option.ConnectionPassword=123456
javax.jdo.option.Mapping=hsql
Sample entity:
#PersistenceCapable(identityType = IdentityType.APPLICATION, table = "heartbeat")
public class HeartBeat implements Serializable{
#PrimaryKey
#Column(length=128)
private String userId;
.......
}
Now, when i compile or run my application the tables are not being auto created. I am not sure which property i should use for auto creation of tables based on the entities created.
Please bear with my question as i am new to JDO and MySQL integration.
Thanks in advance.
For JDO, if you want to create the schema for "tables" during the persistence process you tell DataNucleus by using this property, datanucleus.schema.autoCreateTables.
To auto create "columns" use datanucleus.schema.autoCreateColumns, and for "constraints" use datanucleus.schema.autoCreateConstraints. Set the properties to true.
<property name="datanucleus.schema.autoCreateTables" value="true"/>
<property name="datanucleus.schema.autoCreateColumns" value="true"/>
<property name="datanucleus.schema.autoCreateConstraints" value="true"/>
Shortcut for the three, use datanucleus.schema.autoCreateAll and set to true.
<!-- shortcut for the three -->
<property name="datanucleus.schema.autoCreateAll" value="true"/>
You can check the documentations here http://www.datanucleus.org/products/accessplatform_4_1/jdo/schema.html
Defined your JDO properties like this;
datanucleus.schema.autoCreateTables=true
datanucleus.schema.autoCreateColumns=true
datanucleus.schema.autoCreateConstraints=true
or shortcut
datanucleus.schema.autoCreateAll=true