I have piece of code which is working fine with oracle db but giving exception SQL state [HY000]; error code [1205]; (conn=30) Lock wait timeout exceeded; try restarting transaction; nested exception is java.sql.BatchUpdateException: (conn=30) Lock wait timeout exceeded; try restarting transaction when trying to execute with mariadb . I have tried multiple solutions i.e. increased innodb_lock_wait_timeout , changed the ##GLOBAL.tx_isolation, ##tx_isolation but still getting the same error . Here is the code which is working fine with orcale but giving exception with mariadb:
public void updateFailureData(final Long mId, final Set<String> errorVals) {
try {
this.jdbcTemplate.batchUpdate("UPDATE MARKETS SET ERR_VALS = ? WHERE M_ID = ?", new BatchPreparedStatementSetter() {
#Override
public void setValues(final PreparedStatement preparedStatement, final int arg1) throws SQLException {
int index = 1;
preparedStatement.setString(index++, StringUtils.join(errorVals, ","));
preparedStatement.setLong(index, mId);
}
#Override
public int getBatchSize() {
return 1;
}
});
} catch (DataAccessException dataAccessException) {
System.out.println("Updating errorVals.", dataAccessException);
}
}
Is there anything which can be done or I am missing ?
Related
I have a method that call a procedure, see:
public void myMethod() {
((Session) em.getDelegate()).doWork(new Work() {
#Override
public void execute(Connection connection) throws SQLException {
StringBuilder sqlSP = new StringBuilder();
sqlSP.append("{ call myprocedure ");
sqlSP.append("(?) }");
CallableStatement cs = connection.prepareCall(sqlSP.toString());
cs.setInt(1, 1);
try {
cs.execute();
} finally {
if (!cs.isClosed()) {
cs.close();
}
}
}
});
}
This works very well in tomcat, because method isClosed() exists. But when i upload my application to jboss 5.1 i got following error:
Caused by: java.lang.AbstractMethodError: net.sourceforge.jtds.jdbc.JtdsCallableStatement.isClosed()Z
at org.jboss.resource.adapter.jdbc.jdk6.WrappedCallableStatementJDK6.isClosed(WrappedCallableStatementJDK6.java:64)
My tomcat and jboss, both use jTDS 1.2.5, so i can't understand what is the problem. I tried to debug jboss with WrappedCallableStatement but when i try to inspect line "cs.isClosed" i got nestedException.
I've integration solution based on weblogic application server. (Oracle Retail Integration Bus). Each adapter of solution is a EJB component.
Weblogic Console Application view
There are two types of Adapters, first one is for XA Transactions, and second one is for NONXA transactions. (NONXA needed when in PLSQL API function used External proc procedures).
XA - OracleObjectSubscriberComponentImpl
public class OracleObjectSubscriberComponentImpl
extends DefaultAdaptorComponentImpl
implements SubscriberComponent
{
....
protected void performSubscribe(RibContext ribContext, RibMessage inRibMessage, RibMessages outRibMsg)
throws RibAPIException
{
boolean success = false;
Connection connection = null;
try
{
setRibContext(ribContext);
setRibMessagesOut(outRibMsg);
connection = getNewConnection();
initCallableStatement(connection, null);
registerOutParams();
if (setInParams(inRibMessage))
{
execute();
processResult();
success = true;
}
}
finally
{
end(success);
cleanup();
super.closeConnection(connection);
}
}
public void performSubscribe(RibContext ribContext, RibMessage inRibMessage)
throws RibAPIException
{
performSubscribe(ribContext, inRibMessage, null);
}
public void subscribe(RibContext ribContext, RibMessage inRibMessage)
throws RibAPIException
{
performSubscribe(ribContext, inRibMessage);
}
...
}
NonXA - OracleObjectSubscriberComponentNonXAImpl extends OracleObjectSubscriberComponentImpl.
public class OracleObjectSubscriberComponentNonXAImpl
extends OracleObjectSubscriberComponentImpl
{
public void initCallableStatement(Connection c, String msgType)
throws RibAPIException
{
try
{
c.setAutoCommit(false);
}
catch (SQLException e)
{
this.LOG.error("Could not turn off AutoCommit", e);
throw createRibAPIException("initStmt", e);
}
super.initCallableStatement(c, msgType);
}
public void end(boolean successful)
{
super.end(successful);
try
{
if (successful) {
this.conn.commit();
} else {
this.conn.rollback();
}
this.conn.setAutoCommit(true);
}
catch (SQLException sqle)
{
String errorString = "Error occurred during commit/rollback";
this.LOG.error(errorString, sqle);
throw new RuntimeException(errorString, sqle);
}
}
public void subscribe(RibContext ribContext, RibMessage inRibMessage)
throws RibAPIException
{
NonTransactionalSubscriberCoreService nonTransactionalSubscriberCoreService = (NonTransactionalSubscriberCoreService)RetailServiceFactory.getService(NonTransactionalSubscriberCoreService.class);
nonTransactionalSubscriberCoreService.subscribe(this, ribContext, inRibMessage);
}
}
Differences between them is:
NonXA Autocommit = false, and this.conn.commit(); and this.conn.rollback(); used instead of XA Autocommit = true.
NonXA got overrided method subscribe, where new Proxy service created, and NonXA object goes into Proxy, where it will execute Perform Subscribe.
Non XA class uses NonTransactionalSubscriberCoreServiceEjb class, this is a Proxy service:
public class NonTransactionalSubscriberCoreServiceEjb
implements NonTransactionalSubscriberCoreService, SessionBean
{
...
public void subscribe(OracleObjectSubscriberComponentNonXAImpl subscriber, RibContext ribContext, RibMessage inRibMessage)
throws RibAPIException
{
RibContextFactory.setCurrentRibContext(ribContext);
subscriber.performSubscribe(ribContext, inRibMessage);
RibContextFactory.clearCurrentRibContext();
}
...
}
All Adapters does not parrallel, each adapter get messages one by one, from JMS Topic. XA component works fine, it get connection in weblogic datasource and return it back when work finished. NonXA does not working as expected, it take connection from datasourse and do not release it, connection hold up until timeout came.
If i change NonXA class, subscribe method to this:
public void subscribe(RibContext ribContext, RibMessage inRibMessage)
throws RibAPIException
{
this.performSubscribe(ribContext, inRibMessage);
}
Connections will be released after work finished, but i can't use External Proc in API, because ORA-xxx (this feature is not supported in XA) raised. I need keep NonXA functionality and release connections.
Solution:
If datasource managed from weblogic server.
From Weblogic console for the datasource,
uncheck "Keep Connection After Local Transaction"
check "Remove Infected Connections Enabled"
If datasource managed from appliaction, make same changes in datasource xml file.
<jdbc-data-source>
<name>rib-rms-managed-datasource</name>
<jdbc-driver-params>
<url>jdbc:oracle:thin:#monrmsdb.apm.local:1521:retekdb</url>
<driver-name>oracle.jdbc.xa.client.OracleXADataSource</driver-name>
<properties>
<property>
<name>user</name>
<value>RMS13DEV</value>
</property>
</properties>
</jdbc-driver-params>
<jdbc-connection-pool-params>
<initial-capacity>0</initial-capacity>
<max-capacity>350</max-capacity>
<capacity-increment>10</capacity-increment>
<connection-creation-retry-frequency-seconds>1</connection-creation-retry-frequency-seconds>
<test-connections-on-reserve>false</test-connections-on-reserve>
<profile-harvest-frequency-seconds>60000</profile-harvest-frequency-seconds>
<inactive-connection-timeout-seconds>5</inactive-connection-timeout-seconds>
<statement-cache-size>0</statement-cache-size>
<!-- Add this--><remove-infected-connections>true</remove-infected-connections>
<pinned-to-thread>false</pinned-to-thread>
</jdbc-connection-pool-params>
<jdbc-data-source-params>
<jndi-name>jdbc/OracleRibDs</jndi-name>
<global-transactions-protocol>TwoPhaseCommit</global-transactions-protocol>
<!-- Add this--><keep-conn-after-local-tx>false</keep-conn-after-local-tx>
</jdbc-data-source-params>
</jdbc-data-source>
(EDITED)
I am using the following code to check if my Postgres db is up and running. However if the machine running the db is slow (Not enough RAM for example) it sometimes pass but when i tried to get some real data from the db (a few millisec after) i fail. I guess because not all tables were loaded.
Here is my code:
public static boolean testDBConnection(boolean refreshFactory) throws Exception
Session session = null;
try {
if(refreshFactory){
ConnectionUtil.refreshSessionFactory();
}
session = ConnectionUtil.getSessionFactory().openSession();
String sql = "select 1";
session.createSQLQuery(sql).list();
return true;
}
catch (HibernateException e) {
String error = "Failed to connect db.";
throw ExceptionFactory.create(error);
}
finally{
if(session!=null){
session.close();
}
}
}
Is there a better way then "select 1"?
Thanks
I'm working with Java and mysql for database and I ran into a weird problem:
One of my clients have a very unstable connection and sometimes packet loss can be high. Ok that's not software's fault I know, but I went there to test and, when the program calls "DriverManager.getConnection()" and the network connection gets unstable, that line gets to lock the application (or the given thread) by several minutes. I have added some logics of course to use another datasource for caching data locally then saving to the network host when possible, but, I can't often let the program hang for longer than 10s (And this method doesn't seem to have any timeout specification).
So, I came out with a workaround like this:
public class CFGBanco implements Serializable {
public String driver = "com.mysql.jdbc.Driver";
public String host;
public String url = "";
public String proto = "jdbc:mysql://";
public String database;
public String user;
public String password;
}
private static java.sql.Connection Connect(HostConfig dataHost) throws java.sql.SQLException, ClassNotFoundException
{
dataHost.url = dataHost.proto+dataHost.host;
if(dataHost.database != null && !dataHost.database.equals("")) dataHost.url += "/"+dataHost.database;
java.lang.Class.forName(dataHost.driver);
ArrayList<Object> lh = new ArrayList<>();
lh.add(0, null);
Thread ConThread = new Thread(()-> {
try {
lh.add(0, java.sql.DriverManager.getConnection(
dataHost.url, dataHost.user, dataHost.password));
} catch(Exception x ) {
System.out.println(x.getMessage());
}
}, "ConnThread-"+SessId);
ConThread.start();
Thread TimeoutThread = new Thread(() -> {
int c = 0;
int delay = 100;
try {
try {
do {
try {
if(t.isAlive())
Thread.sleep(delay);
else
break;
} catch(Exception x) {}
} while((c+=delay) < 10000);
} catch(Exception x){}
} finally {
try {
t.stop();
} catch(Exception x){}
}
}, "ConTimeout-"+SessId);
TimeoutThread.start();
try {
ConThread.join();
} catch(Exception x) {}
if(lh.get(0) == null)
throw new SQLException();
return (Connection) lh.get(0);
}
I call getConnection from another thread, then make a secondary "timeout" thread to watch it and then Join the calling thread to the ConThread.
I have been getting results close to expected, indeed, but it got me wondering:
Is there a better way to do this? Does the creation of 2 threads eat up much on system resources, enough to make this approach unpractical?
You need connection pooling. Pool in the connection and reuse it rather than recreating everytime. One such library for DB connection pooling is DBCP by Apache
It will take care of when connection gets dropped off and so on. You could have validation Query and it would query DB say before borrowing connection from the pool and once it validates successfully, it will fire your actual query.
I got a deadlock problem with mysql and an application that I am developing. The application, based on spring boot, integration and jpa, has different threads and all of them can access this service:
#Override
#Transactional()
public List<TwitterUser> storeTwitterUsers(List<TwitterUser> twitterUsers)
{
logger.debug("Store list of users, total: " + twitterUsers.size());
List<TwitterUser> savedUsers = new ArrayList<>();
for ( TwitterUser twitterUser : twitterUsers ) {
TwitterUser user = getTwitterUserById(twitterUser.getTwitterId());
if ( user != null ) {
twitterUser.setId(user.getId());
user = entityManager.merge(twitterUser);
} else {
//HERE THE EXCEPTION IS THROWN
entityManager.persist(twitterUser);
user = twitterUser;
}
entityManager.flush();
savedUsers.add(user);
}
return savedUsers;
}
#Override
#Transactional(readOnly = true)
public TwitterUser getTwitterUserById(Long id)
{
Query query = entityManager.createQuery("from TwitterUser u where u.twitterId=:id");
query.setParameter("id", id);
TwitterUser twitterUser = null;
//Throw Exception NoResultException
try {
twitterUser = (TwitterUser)query.getSingleResult();
} catch (NoResultException e) {
//no result found
}
return twitterUser;
}
When more than one thread is within the method storeTwitterUsers, mysql throw this error:
Deadlock found when trying to get lock; try restarting transaction
This is the full stack track of the error:
http://pastebin.com/nZEvykux
I already read those two questions:
How to avoid mysql 'Deadlock found when trying to get lock; try restarting transaction'
Getting "Deadlock found when trying to get lock; try restarting transaction"
but my problem seems slightly different because I got the exception when almost any thread tries to persist the object.
Is there a clean and easy way to resolve the problem without implementing a low level code check? Can Spring JPA automatically manage the deadlock situation?
Any help is really appreciated, I am struggling with that error!