Spring boot datasource is down with exception - mysql

I've setup spring boot so under /health to display the datasource status. However, I'm getting this JSON back:
"dataSource" : {
"status" : "DOWN",
"database" : "MySQL",
"error" : "org.springframework.dao.TransientDataAccessResourceException: StatementCallback; SQL [SELECT 1]; Conversion not supported for type java.lang.Object; nested exception is java.sql.SQLException: Conversion not supported for type java.lang.Object"
},
As you can see my database is mysql and I'm running it on Windows8. I did try the 'select 1' query and it did return 1 in the command line of mysql. Any idea where the problem might be?

DataSourceHealthIndicator runs its configured query (SELECT 1 by default) by calling JdbcTemplate:
this.jdbcTemplate.queryForObject(query, Object.class)
On Java 6, this ultimately leads to a call to ResultSet.getObject(index) and things work as expected. On Java 7, the call is to ResultSet.getObject(index, Object.class) (this overload of getObject is new in Java 7). In its default configuration the MySQL JDBC driver is unable to create and return an instance of java.lang.Object so it throws the exception described in the question.
You can change MySQL's behaviour and have it return an instance of whatever is appropriate for the column by enabling auto-deserialization:
spring.datasource.url: jdbc:mysql://localhost/test?autoDeserialize=true
I've also opened Spring boot issue so that we can make a change so that enabling auto-deserialization isn't necessary.

Related

Using both Hive and MySql JDBC drivers

TL;DR:
Is it problematic to use both Hive and MySql JDBC together?
I'm working on an application that performs several SQL queries using the MySql JDBC driver and afterwards it also send another Hive query using Hive JDBC.
Now whats happening is that the MySql queries are working properly, when the code tries to execute the Hive query it throws this exception:
com.mysql.cj.core.exceptions.WrongArgumentException: Connector/J cannot handle a database URL of type 'jdbc:hive2:'.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.cj.core.exceptions.ExceptionFactory.createException(ExceptionFactory.java:54)
at com.mysql.cj.core.conf.url.ConnectionUrl$Type.fromValue(ConnectionUrl.java:149)
at com.mysql.cj.core.conf.url.ConnectionUrl.getConnectionUrlInstance(ConnectionUrl.java:193)
at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:195)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:247)
at company.services.HiveV2Provider.createConnection(HiveProvider.scala:105)
at company.services.HiveProvider$class.loanConnection(HiveProvider.scala:66)
Now after this exception is thrown the query is executed properly.
My guess is that since I'm loading both the MySql and Hive drivers, the MySql driver is trying to run this query first but when it encounters the Hive URL it throws this exception and then the Hive driver sees it and executes the query properly
This is how I execute the MySql code:
val query = ... // query is created here
var mysqlConn: Connection = null
var stmt: Statement = null
try {
Class.forName("com.mysql.jdbc.Driver")
mysqlConn = DriverManager.getConnection(mysqlAddress, username, password)
stmt = mysqlConn.createStatement()
val rs = stmt.executeQuery(query)
val returnVal = someResultSetHandlingFunction(rs)
rs.close()
returnVal
} catch {
case NonFatal(e) =>
logWarning(s"Failed to execute query on: $mysqlAddress", e)
throw e
} finally {
if (mysqlConn != null) {
mysqlConn.close()
}
}
My Hive code looks the same only with a driver name of: org.apache.hive.jdbc.HiveDriver (and it communicates with jdbc:hive2://someurl)
Versions:
Hive is hive-jdbc-1.1.0-cdh5.7.1
MySql is mysql-connector-java 6.0.4
Does anybody know if there's any way to avoid receiving this exception? Is it problematic to load 2 different JDBC drivers? Reading in other somewhat similar questions I get the impression that this should not be a problem
Just a few clarifications:
I know its probably not the best thing to use JDBC directly but I'm checking something and JDBC is fine for this task
I'm using Scala but I don't think it matters for this issue
Thanks in advance
I almost forgot to answer my question
So the issue is probably related to this bug. Back when I was facing this issue I didn't notice it was just a stack trace print and not an actual failure so it was less problematic than I expected.
Anyway, I then saw that in some specific versions this issue was fixed as you can see here so I just changed my mysql version to 5.1.9 (because I didn't need the higher version for anything specific) and the stack trace failure was gone.
I'll be happy if to hear if someone has a more elegant solution to this
Cheers
I was facing the same issue with MS SQL Server JDBC Driver. The same error was logged but everything worked fine.
According to this Microsoft page:
In the JDBC API 4.0, the DriverManager.getConnection method is
enhanced to load JDBC drivers automatically. Therefore, applications
do not need to call the Class.forName method to register or load the
driver when using the sqljdbc4.jar, sqljdbc41.jar, or sqljdbc42.jar
class library.
So I tried removing the Class.forName and just called DriverManager.getConnection. Things are just working and I'm not getting the annoying error anymore.
I believe the Driver itself must include a "META-INF/services/java.sql.Driver" file that registers itself as a valid JDBC driver, so not necessarily it will work for you, but to SQL Server Driver users it's the way to go.
BTW: I noticed that DriverManager.getConnection takes significant more time (6 or 7 seconds) to load the Drive the first time it's called. Subsequent calls are OK. Depending on your application it may be an issue.
Class.forName("com.mysql.jdbc.Driver")
will register your JDBC driver in the DriverManager. Then you put hive connection uri in
DriverManager.getConnection(mysqlAddress, username, password)
Exception is expected in this case.
Why don't you delegate the call to particular JDBC driver after checking uri like:
if (uri.contains("hive")){
//call Hive JDBC
}
else if (uri.contains("mysql")){
//call Mysql JDBC
}

Spring-Session with JDBC configuration: Table 'test.spring_session' doesn't exist

I try to run this example but without using Redis, instead with my local MySQL server.
I have edited this spring boot app like this:
Gradle:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion")
}
}
apply plugin: 'spring-boot'
apply from: JAVA_GRADLE
//this 'if' statement is because I was getting error: Execution failed for task ':samples:findbyusername:findMainClass'.
//> Could not find property 'main' on task ':samples:findbyusername:run'.
if (!hasProperty('mainClass')) {
ext.mainClass = 'sample.FindByUsernameApplication'
}
tasks.findByPath("artifactoryPublish")?.enabled = false
group = 'samples'
dependencies {
compile("org.springframework.boot:spring-boot-starter-jdbc:$springBootVersion")
compile group: 'mysql', name: 'mysql-connector-java', version: '6.0.2'
compile group: 'org.springframework.session', name: 'spring-session', version: '1.2.0.RELEASE'
compile project(':spring-session'),
"org.springframework.boot:spring-boot-starter-web",
"org.springframework.boot:spring-boot-starter-thymeleaf",
"nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect",
"org.springframework.security:spring-security-web:$springSecurityVersion",
"org.springframework.security:spring-security-config:$springSecurityVersion",
"com.maxmind.geoip2:geoip2:2.3.1",
"org.apache.httpcomponents:httpclient"
testCompile "org.springframework.boot:spring-boot-starter-test",
"org.assertj:assertj-core:$assertjVersion"
integrationTestCompile gebDependencies,
"org.spockframework:spock-spring:$spockVersion"
}
def reservePort() {
def socket = new ServerSocket(0)
def result = socket.localPort
socket.close()
result
}
application.properties
spring.datasource.url = jdbc:mysql://localhost:3306/TEST?characterEncoding=UTF-8&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=but
spring.thymeleaf.cache=false
spring.template.cache=false
HttpSessionConfig.java
#EnableJdbcHttpSession // <1>
public class HttpSessionConfig {
}
Application starts on tomcat but when I hit localhost in my browser I get:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Mon May 23 21:14:31 CEST 2016
There was an unexpected error (type=Internal Server Error, status=500).
PreparedStatementCallback; bad SQL grammar [INSERT INTO SPRING_SESSION(SESSION_ID, CREATION_TIME, LAST_ACCESS_TIME, MAX_INACTIVE_INTERVAL, PRINCIPAL_NAME) VALUES (?, ?, ?, ?, ?)]; nested exception is java.sql.SQLSyntaxErrorException: Table 'test.spring_session' doesn't exist
I don't remember reading anything about manually creating this table so I assumed that spring will handle it for me...
EDIT:
I actually tried to manually create tables and then application runs OK. But I guess I shouldn't be doing this manually.
Spring Session ships with database schema scripts for most major RDBMS's (located in org.springframework.session.jdbc package), but the creation of database tables for Spring Session JDBC supports needs to be taken care of by the users themselves.
The provided scripts can be used untouched, however some users may choose to modify them to fit their specific needs, using the provided scripts as a reference.
An option would be to use a database migration tool, such as Flyway, to handle the creation of database tables.
Since you're using Spring Boot, it might be of your interest that there is a pending PR to add support for automatic initialization of Spring Session JDBC schema: https://github.com/spring-projects/spring-boot/pull/5879
If the documentation misled you into thinking the tables should be created automatically by Spring Session itself, consider reporting the issue so we can update the documentation if necessary: https://github.com/spring-projects/spring-session/issues
At least as of now, you don't have to create tables manually.
In my test, tables were created automatically after adding the following line into the file application.properties when this file appears like shown above.
spring.session.jdbc.initialize-schema=always
I found this beautiful line from the following stackoverflow page.
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'test.spring_session' doesn't exist - Spring Boot
I am sorry that I don't know if it was necessary to create tables manually in 2016 or 2017. I will update this answer when I get to know this or get to have some more fruitful related information. I am just wishing that nobody will be led to an idea that automatic creation of session tables is impossible with the lastest Spring Framework version of 2019 or later.
spring.session.jdbc.initialize-schema=always worked for me

How to set up the FOUND_ROWS flag?

I'm using Entity Framework 5, MySQL 5.6 and MySQLConnector 6.6.5.
I would like to set up the FOUND_ROWS flag in my Entity Framework connection string.
I tried the following configuration.
...
server=localhost;user id=root;option=2
..
According to the MySQL documentation the value '2' equals FOUND_ROWS parameter.
But it throws an InvalidOperationException saying that the Keyword is not supported (name parameter : option).
How am I supposed to do?
try
UseAffectedRows=false
reference.
UseAffectedRows
When true, the connection reports changed rows instead of found rows.
This option was added in Connector/Net version 5.2.6.

Edatabase error : Record not found while locating TTable ,

my application, i have used TTable.locate option in many places to move the cursor, but in only one place it will raise "EDatabaseerror : Record Not Found',
aslo it will raise for particular records only,
The Locate Option only returns boolean value, if records exist it return True,if not it return Fasle,
Why it raising Error?
am using:
Delphi 7, BDE5, Sql server 2008, am using Sql server native client driver to connect Sql server From BDE VIA ODBCE, application working fine except that place.
NOte:
am locting ttable using locaseinsensitive option,
example :
tb_user.locate('username',tb_global_user.fieldbyname('Username',[locaseinsensitive]));
this error raised from my Result form, am using this form for common search,
any helps ?

Linq with MySQL database in ASP.NET MVC 3, storing DateTime into variable

I am using MySQL database to work in ASP.NET MVC 3, i've already set up all requirements and connection is working fine. This code below is working properly and produce right result :
try
{
ViewBag.Model = (from n in _db.mainDatas
where n.time_stamp == new DateTime(2010, 11, 3, 0, 0, 15)
select n).Take(10).ToList();
}catch (Exception e) {
ViewBag.Error = e;
}
But when i change this code into :
DateTime test = new DateTime(2010,11,3,0,0,15);
try
{
ViewBag.Model = (from n in _db.mainDatas
where n.time_stamp == test
select n).Take(10).ToList();
}catch (Exception e) {
ViewBag.Error = e;
}
this error message is generated :
MySql.Data.MySqlClient.MySqlException: Fatal error encountered during command execution. ---> MySql.Data.MySqlClient.MySqlException: Unable to serialize date/time value
I am using MySQL Connector/Net 6.3.6. Any solution to this problem ?
It seems to be a problem with the Linq to SQL provider for MySql that you have been using.
In first case the date part is "in" the Expression tree that is generate from your linq query where as in the second case the DateTime is declared out side of the Linq query and hence the generated expression tree will be different from the first case. Now it depends on the parser of expression tree in the Linq to SQL provider how to handle both the cases and it seems in this case the provider is not able to properly handle the second case expression tree.
Ok, after doing some searches and googling like crazy, finally I found the solution for my problem. Well, it's not a solution actually, because it looks like MySQL Connector/Net 6.3.6 is not doing well with my project (maybe because of my server, database, project configurations, etc) so I use Devart dotConnector instead of MySQL Connector/Net 6.3.6 and everything works like magic. :D