Can Spring Batch use MySQL for its internal BATCH_ tables? - mysql

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.

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>`

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.

NHibernate : Store VARBINARY to MAX

I am using following mapping to store a Serializable object to SQL Server 2008:
<class name="EMSApplication.Data.Domain.Configuration, EMSApplication.Data" table="ems_Configurations" proxy="EMSApplication.Data.Domain.IConfiguration, EMSApplication.Data" lazy="true">
<id name="Id" type="System.Int32">
<column name="Id" not-null="true"/>
<generator class="native"/>
</id>
<property name="Settings" type="Serializable">
<column name="Settings" not-null="true"/>
</property>
</class>
It is generating a varbinary(8000) for column type of the database. How can I make it to use varbinary(max)?
If I use:
<property name="Settings" type="Serializable" length="2147483647">
<column name="Settings" not-null="true"/>
</property>
It is also truncated to 8000. I am using NHibernate3.2(not fluent).
According to the nHibernate documentation, "length" is not an attribute/property of <property> but instead should be used in <column>.
This section shows that "length" is not a part of <property> :
http://nhibernate.info/doc/nh/en/index.html#mapping-declaration-property
This section shows that "length" is a part of <column> :
http://nhibernate.info/doc/nh/en/index.html#toolsetguide-s1-2
That last section (20.1 and the Table 20.1 Summary) shows that "sql-type" is also part of <column> so try one of these variations:
<property name="Settings" type="Serializable">
<column name="Settings" not-null="true" length="2147483647"/>
</property>
or
<property name="Settings" type="Serializable">
<column name="Settings" not-null="true" sql-type="varbinary(max)"/>
</property>
Edit:
This question seems to be a duplicate of:
How do I get fluent nhibernate to create a varbinary(max) field in sql server
but that information is almost 3 years old and the newer version of nHibernate might have corrected for this (I have no way to test this).
The following page appears to also be the same issue and is much more recent:
Binary Blob truncated to 8000 bytes - SQL Server 2008 / varbinary(max)

Using mysql database to authenticate users in Spring security?

I want to use Spring security to authenticate users in my web application..
Since am not a matured user to Spring framework ,i can't get a clear idea about how we can do the configuration settings to use jdbc-user-service ..
i had done the following configurations.but its not working
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="myDataSource"/>
</authentication-provider>
</authentication-manager>
<beans:bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<beans:property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<beans:property name="url" value="jdbc:mysql://localhost:3306/testDB"/>
<beans:property name="username" value="admin"/>
<beans:property name="password" value="admin"/>
</beans:bean>
..can anyone please help me to solve the issue with a sample config file.
Thanks in advance.
another way to do this is to create tables using the standard spring security database schema (http://static.springsource.org/spring-security/site/docs/3.0.x/reference/appendix-schema.html). Then you can simply use spring's jdbc-userservice:
<security:authentication-provider >
<security:jdbc-user-service data-source-ref="dataSource" />
<security:password-encoder hash="sha" />
</security:authentication-provider>
Or if you want to use your own schema you can override the queries like this:
<security:authentication-provider>
<securiy:jdbc-user-service
data-source-ref="dataSource"
users-by-username-query="select username, password from users where username=?"
authorities-by-username-query="select username, roleName from role..."
role-prefix="ROLE_"
/>
</security:authentication-provider>
You usually do it with a custom UserDetailsService. The UserDetailsService is a DAO used to load data about a user when they attempt login. Have a look at the loadUserByUsername(String username) method and the UserDetails class in spring.
Yo need to define it in your context:
<bean id="myDetailsService"
class="com.company.service.impl.MyDetailsService" />
To use it you can add this to your security config:
<authentication-manager>
<authentication-provider user-service-ref="myDetailsService" />
</authentication-manager>
and all you security filters will use it.
You can ask a more specific question if you need help implementing it, but you won't have trouble IMO.
Add these lines to your <authentication-provider> tag:
<authentication-provider>
<password-encoder hash="sha-256" />
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="
SELECT username, password, enabled
FROM user WHERE username = ?"
authorities-by-username-query="
SELECT u.username, r.role_name
FROM user u, user_role r, assigned_role a
WHERE u.id = a.username
AND r.id = a.role_id
AND u.username = ?"
/>
</authentication-provider>
Of course you'll have to tweak the queries to match your table names.