We use Hibernate with Exasol in a web app. When we set Hibernate's hibernate.connection.pool_size property to a value greater than 1 (or the corresponding property of any JDBC connection pool, e.g, HikariCP, c3p0, to a value greater than 1), we get:
java.sql.SQLException: syntax error, unexpected FOR_READ_ONLY_, expecting end_of_input or ';' [line 1, column 93] (Session: 1622929410050974585)
at com.exasol.jdbc.ExceptionFactory.createSQLException(ExceptionFactory.java:164)
at com.exasol.jdbc.ExceptionFactory.createSQLException(ExceptionFactory.java:21)
at com.exasol.jdbc.AbstractEXAPreparedStatement.<init>(AbstractEXAPreparedStatement.java:62)
at com.exasol.jdbc.AbstractEXAPreparedStatement_14.<init>(AbstractEXAPreparedStatement_14.java:14)
at com.exasol.jdbc.EXAPreparedStatement.<init>(EXAPreparedStatement.java:12)
at com.exasol.jdbc.DialectGeneric.createPreparedStatement(DialectGeneric.java:10)
at com.exasol.jdbc.AbstractEXAConnection.prepareStatement(AbstractEXAConnection.java:608)
at org.hibernate.id.enhanced.TableGenerator.prepareStatement(TableGenerator.java:618)
at org.hibernate.id.enhanced.TableGenerator.access$200(TableGenerator.java:127)
From the Exasol's user manual,
The Connection Pooling of the driver manager is deactivated by
default. You can explicitly activate it in the configuration tool
"ODBC Data Source Administrator". But please note that in that case
reused connections keep their session settings which were set via SQL
commands (see ALTER SESSION).
Here, ODBC is mentioned, whereas we use JDBC. So my question is, how to enable JDBC connection pooling on Exasol?
Should we add/update a row in EXA_PARAMETERS view/table?
for JDBC, EXASOL itself doesn't have an integrated connection pooling.
But we find the following library very useful:
http://commons.apache.org/proper/commons-dbcp/download_dbcp.cgi
For instance, this is also used in JMeter and works fine there.
However, we do not have any experience combining this library with hibernate.
By the way, did you use https://github.com/exasol/hibernate-exasol?
Please let us know about the progress, we are happy to help! (Contact us: www.exasol.com/contact)
Best regards,
Team Exasol
Related
We are using hibernate3 jar and JDK 6. And for connection pool we are using UCP-11.2.0.3. Now we are facing connection pool full issue. We have already set Abandon limit. We want to implement query timeout on UCP. Is this can be handle at DataSource level to have query timeout. I can see function datasource.setConnectionProperty(name, value) but didn't find property for query timeout.
The properties you may set for the UCP are defined in the documentation
You may set Time-To-Live Connection Timeout which will cap the total time the connection is borrowed from the pool.
pds.setTimeToLiveConnectionTimeout(18000)
The query timeout can be set on the statement level and is valid only for this statement - see here - so this is not configured via the UCP.
stmt.setQueryTimeout(timeout)
My server app uses prepared statements in almost all cases, to prevent sql injection. Nevertheless a possibility is needed providing special users executing raw SELECT queries.
How can I more or less securely make sure the query does not modify the database? Is it possible to execute a query read only, or is there any other 'secure' way making sure noone tries any sql injection?
(Using sqlite3, so I cannot use any privileges)
Thanks a lot!
JDBC supports read-only connections by calling Connection.setReadOnly(true). However the javadoc says:
Puts this connection in read-only mode as a hint to the driver to enable database optimizations.
Some JDBC drivers will enforce the read-only request, others will use it for optimizations only, or simply ignore it. I don't know how sqlite3 implements it. You'll have to test that.
Otherwise, you could do a "simple" parse of the SQL statement, to ensure that it's a single valid SELECT statement.
I'm not aware of a general JBDC configuration which specifies readonly. But Sqlite does have special database open modes and this can be leveraged in your connection to your sqlite database. Eg.
Properties config = new Properties();
config.setProperty("open_mode", "1"); //1 == readonly
Connection conn = DriverManager.getConnection("jdbc:sqlite:sample.db", config);
Credit: https://stackoverflow.com/a/18092761/62344
FWIW All supported open modes can be seen here.
If you use some sort of factory class to create or return connections to the database, you can individually set connections to be read-only:
public Connection getReadOnlyConnection() {
// Alternatively this could come from a connection pool:
final Connection conn = DriverManager.getConnection("jdbc:sqlite:sample.db");
conn.setReadOnly(true);
return conn;
}
If you're using a connection pool, then you may also want to provide a method for getting writeable connections too:
public Connection getWriteableConnection() {
final Connection conn = getPooledConnection(); // I'm assuming this method exists!
conn.setReadOnly(false);
return conn;
}
You could also provide just a single getConnection(boolean readOnly) method and simply pass the parameter through to the setReadOnly(boolean) call. I prefer the separate methods personally, as it makes your intent much clearer.
Alternatively, some databases like Oracle provide a read only mode that can be enabled. SQLite doesn't provide one, but you can emulate it by simply setting the actual database files (including directories) to read only on the filesystem itself.
Another way of doing it is as follows (credit goes to deadlock for the below code):
public Connection getReadOnlyConnection() {
SQLiteConfig config = new SQLiteConfig();
config.setReadOnly(true);
Connection conn = DriverManager.getConnection("jdbc:sqlite:sample.db",
config.toProperties());
}
I have Java application with Hibernate framework(no spring) connect to MySQL DB , manage connection pooling via c3p0
i try to configure my apllication to read from slave db and write to master db , i have following this link to some extend Master/Slave load balance
let's say if the application already got a session with connection in pool and it need to execute a read-only method , like this
public someReadOnlyMethod()
{
Session session = (get session from current Thread)
//set read-only so that it read from slave db
session.connection().setReadOnly(true);
(...connect to db to do something...)
//set it back in case of this method is followed by write method so that it go to master db
session.connection().setReadOnly(false);
}
Is the pooling create a new connection to connect to db 2 times for read-only and write operation(if so,this will heavily impact performance) or it smart enough to swap the operation to already existing read-only and writable connection pool ?
thx for your advice.
so this has nothing to do with the pool; it's all in the mysql driver. c3p0 will pass your call to setReadOnly (whether true or false) to the underlying Connection, and the Connection will route to the master or the slaves accordingly.
if you don't like how your Connections default (probably by default they are not read only), you can set the read-only property in the onAcquire method of a c3p0 ConnectionCustomizer, and the value use set (true or false) will become th default that c3p0 resets Connections to.
good luck!
tl;dr: It will re-use existing connections whenever you switch setReadOnly(true/false).
JDBC will connect to all servers listed in your connection URL when you do ReplicationDriver().connect(url). Those connections will remain open for re-use no matter how many times you switch setReadOnly().
Source: I just tested Connector/J version 5.1.38 with com.mysql.jdbc.ReplicationDriver.
Does anybody know a way to reestablish/retry again hibernate connection. I mean for example: the remote DB is down and I start my application. Hibernate is not able to establish a connection. it fails. But the application is not closed. Is there a way to say hibernate to try one more time to establish a connecton?
Thanks in advance
You should really go for C3P0 connection pooling: http://www.mchange.com/projects/c3p0/index.html#hibernate-specific
There is a section in C3P0 documentation on that subject: http://www.mchange.com/projects/c3p0/index.html#configuring_recovery
First you have to properly configure c3p0, which in case of using hibernate must happen in c3p0.properties file.
In your c3p0.properties put these properties to retry to reconnect indefinitely every 3 seconds when database is down:
c3p0.acquireRetryAttempts = 0
c3p0.acquireRetryDelay = 3000
c3p0.breakAfterAcquireFailure = false
Also, to avoid broken connections lying in your pool indefinitely, use connection age management:
c3p0.maxConnectionAge = 6000
c3p0.maxIdleTime = 6000
c3p0.maxIdleTimeExcessConnections = 1800
c3p0.idleConnectionTestPeriod = 3600
These may be quite expensive, but helpful if above is not enough:
c3p0.testConnectionOnCheckout = true
c3p0.preferredTestQuery = SELECT 1;
You may also want to check for connection leaks which prevent recovery:
c3p0.debugUnreturnedConnectionStackTraces = true
And finally, make sure that C3P0 is hooked with hibernate correctly, enable debug logging for "com.mchange" package and see if C3P0 tells you anything about itself. It should state configuration properties which are loaded, so see if it's all there.
I hope this helps.
C3P0 is the internal connection-pool implementation for hibernate.
Add "hibernate.connection.provider_class = org.hibernate.connection.C3P0ConnectionProvider"
in hibernate properties file. Create a file c3p0.properties setting the parameters accordingly. This file & c3p0-x.jar must be in classpath.
c3p0.properties
c3p0.idleConnectionTestPeriod : If this is a number greater than 0, c3p0 will test all idle, pooled but unchecked-out connections, every this number of seconds.
c3p0.testConnectionOnCheckout : Use only if necessary. Expensive. If true, an operation will be performed at every connection checkout to verify that the connection is valid. Better choice: verify connections periodically using idleConnectionTestPeriod.
There are several other properties that can be configured in hibernate.properties & c3p0.properties.
May be, you try to call method .getCurrentSession() instead .openSession()?
If connection falls you must establish new one.
I hope this helps.
I am getting the following error:
java.sql.SQLException: Closed
Connection at
oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
at
oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:146)
at
oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:208)
at
oracle.jdbc.driver.PhysicalConnection.getMetaData(PhysicalConnection.java:1508)
at
com.ibatis.sqlmap.engine.execution.SqlExecutor.moveToNextResultsSafely(SqlExecutor.java:348)
at
com.ibatis.sqlmap.engine.execution.SqlExecutor.handleMultipleResults(SqlExecutor.java:320)
at
com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQueryProcedure(SqlExecutor.java:277)
at
com.ibatis.sqlmap.engine.mapping.statement.ProcedureStatement.sqlExecuteQuery(ProcedureStatement.java:34)
at
com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWithCallback(GeneralStatement.java:173)
at
com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryForList(GeneralStatement.java:123)
at
com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExecutorDelegate.java:614)
at
com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExecutorDelegate.java:588)
at
com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForList(SqlMapSessionImpl.java:118)
at
org.springframework.orm.ibatis.SqlMapClientTemplate$3.doInSqlMapClient(SqlMapClientTemplate.java:268)
at
org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemplate.java:193)
at
org.springframework.orm.ibatis.SqlMapClientTemplate.executeWithListResult(SqlMapClientTemplate.java:219)
at
org.springframework.orm.ibatis.SqlMapClientTemplate.queryForList(SqlMapClientTemplate.java:266)
at
gov.hud.pih.eiv.web.authentication.AuthenticationUserDAO.isPihUserDAO(AuthenticationUserDAO.java:24)
at
gov.hud.pih.eiv.web.authorization.AuthorizationProxy.isAuthorized(AuthorizationProxy.java:125)
at
gov.hud.pih.eiv.web.authorization.AuthorizationFilter.doFilter(AuthorizationFilter.java:224)
at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:246)
at
I am really stumped and can't figure out what could be causing this error. I am not able to reproduce the error on my machine but on production it is coming a lot of times. I am using iBatis in the whole application so there are no chances of my code not closing connections.
We do have stored procedures that run for a long time before they return results (around 15 seconds).
does anyone have any ideas on what could be causing this? I dont think raising the # of connections on the application server will fix this issue buecause if connections were running out then we'd see "Error on allocating connections"
Sample code snippet:
this.setSqlMapClientTemplate(getSqlTempl());
getSqlMapClientTemplate().queryForList("authentication.isUserDAO", parmMap);
this.setSqlMapClientTemplate(getSqlTemplDW());
List results = (List) parmMap.get("Result0");
I am using validate in my connection pool.
Based on the stack trace, the likely cause is that you are continuing to use a ResultSet after close() was called on the Connection that generated the ResultSet.
What is your DataSource framework? Apache Commons DBCP?
do you use poolPrepareStatement property in data source configuration?
Check the following:
Make sure testOnBorrow and testOnReturn are true and place a simple validationQuery like select 0 from dual.
Do you use au
do you use autoCommit? Are you using START TRANSACTION, COMMIT in your stored procedures? After several days of debugging we found out that you can't mix transaction management both in Java and in SQL - you have to decide on one place to do it. Where are you doing yours?
Edit your question with answers to this, an we'll continue from there.
When a db server reboots, or there are some problems with a network, all the connections in the connection pool are broken and this usuall requires a reboot of application server
And if broken connection detected, you shold create a new one to replace it in connection pool. It's common problem called deadly connections.