I've currently two server who are running a same application, this morning they tried to save at the same time an instance of an object 'Rackstatus'.
The result was :
10:23:37,781 WARN [org.hibernate.util.JDBCExceptionReporter]
(XXXX) SQL Error: 1062, SQLState: 23000
10:23:37,783 ERROR [org.hibernate.util.JDBCExceptionReporter]
(XXXX) Duplicate entry '114464' for key
'PRIMARY' 10:23:37,784 ERROR
[org.hibernate.event.def.AbstractFlushingEventListener]
(XXXX) Could not synchronize database state with
session: org.hibernate.exception.ConstraintViolationException: Could
not execute JDBC batch update
my save code :
public void Save(RackStatus stData) {
Session session = null;
session = super.getSession("BANK");
//Create new instance
Transaction trans = session.beginTransaction();
// execute save
session.save(stData);
// do commit
trans.commit();
}
And finally hibernate definition :
<id name="id" type="int">
<column name="id" />
<generator class="assigned"/>
</id>
Any idea ? Thanks.
Related
I have created a Dataservice in WSO2 to execute SQL Query TRUNCATE TABLE Student and expose it as an API , but i got this error
[2022-12-07 16:33:57,222] ERROR {DBInOnlyMessageReceiver} - Error in
in-only message receiver DS Fault Message: Error in DS non result
invoke. DS Code: DATABASE_ERROR Nested Exception:-
javax.xml.stream.XMLStreamException: DS Fault Message: Error in
'SQLQuery.processStoredProcQuery': DS Fault Message: Error in
'createProcessedPreparedStatement' DS Code: UNKNOWN_ERROR Nested
Exception:- java.sql.SQLException: Unable to retrieve metadata for
procedure.
DS Code: DATABASE_ERROR Source Data Service:- Name: RADMINDataService
Location:
/home/master/Downloads/IntegrationStudio/runtime/microesb/tmp/carbonapps/-1234/1670427210936TestCompositeApplication_1.0.0.car/RADMINDataService_1.0.0/RADMINDataService-1.0.0.dbs
Description: Exposing the radmin data service as a REST service
Default Namespace: http://ws.wso2.org/dataservice/samples/json_sample
Current Request Name: _gettruncatenumseq Current Params: {} Nested
Exception:- DS Fault Message: Error in
'createProcessedPreparedStatement' DS Code: UNKNOWN_ERROR Nested
Exception:- java.sql.SQLException: Unable to retrieve metadata for
procedure.
at
org.wso2.micro.integrator.dataservices.core.dispatch.SingleDataServiceRequest.processSingleRequest(SingleDataServiceRequest.java:117)
at
org.wso2.micro.integrator.dataservices.core.dispatch.SingleDataServiceRequest.processRequest(SingleDataServiceRequest.java:66)
at
org.wso2.micro.integrator.dataservices.core.dispatch.DataServiceRequest.dispatch(DataServiceRequest.java:358)
at
org.wso2.micro.integrator.dataservices.core.DataServiceProcessor.dispatch(DataServiceProcessor.java:40)
at
org.wso2.micro.integrator.dataservices.core.DBInOnlyMessageReceiver.invokeBusinessLogic(DBInOnlyMessageReceiver.java:52)
at
org.apache.axis2.receivers.AbstractMessageReceiver.receive(AbstractMessageReceiver.java:110)
at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:180)
at
org.apache.synapse.transport.passthru.ServerWorker.processNonEntityEnclosingRESTHandler(ServerWorker.java:376)
at
org.apache.synapse.transport.passthru.ServerWorker.run(ServerWorker.java:190)
at
org.apache.axis2.transport.base.threads.NativeWorkerPool$1.run(NativeWorkerPool.java:172)
at
java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at
java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834) Caused by:
javax.xml.stream.XMLStreamException: DS Fault Message: Error in
'SQLQuery.processStoredProcQuery': DS Fault Message: Error in
'createProcessedPreparedStatement' DS Code: UNKNOWN_ERROR Nested
Exception:- java.sql.SQLException: Unable to retrieve metadata for
procedure.
This is my configuration file
<query id="truncatenum" useConfig="mysql">
<sql><![CDATA[TRUNCATE TABLE Student]]></sql>
</query>
<resource method="GET" path="truncatenum">
<description />
<call-query href="truncatenum"/>
</resource>
I don't think the error is caused by the code snippet you shared. The following seems correct.
<query id="truncatenum" useConfig="mysql">
<sql><![CDATA[TRUNCATE TABLE Student]]></sql>
</query>
<resource method="GET" path="truncatenum">
<description />
<call-query href="truncatenum"/>
</resource>
Probably one of the queries you have doesn't match the input parameters you are providing. Hence double check all the other queries you have.
Update
You are correct the TRUNCATE query is executed as a STOREDPROC. I had a closer look at the source-code and it seems if the QUERY String doesn't start with one of the following it's inferred as a STOREDPROC. This is definitely a bug in WSO2.
The weird thing is, in my case the TRUNCATE query is executed as a Stored Procedure successfully. So I assume there is a difference in your Dataeervice from the one I'm trying. Can you create the following Dataservice as it is and try it out? (Just change the connection parameters)
Dataservice
<data name="RESTDataService" serviceNamespace="http://ws.wso2.org/dataservice/samples/json_sample" transports="http https">
<description>Exposing the data service as a REST service.</description>
<config id="default">
<property name="driverClassName">com.mysql.jdbc.Driver</property>
<property name="url">jdbc:mysql://localhost:3306/school_db</property>
<property name="org.wso2.ws.dataservice.user">root</property>
<property name="org.wso2.ws.dataservice.password">root123456</property>
</config>
<resource method="GET" path="truncatenum">
<description />
<call-query href="truncatenum" />
</resource>
<query id="truncatenum" useConfig="default">
<sql><![CDATA[TRUNCATE TABLE students]]></sql>
</query>
</data>
Request
curl --location --request GET 'http://localhost:8290/services/RESTDataService/truncatenum'
If you still get the error. Please enable DEBUG logs for the package org.wso2.micro.integrator.dataservices and share the logs.
I have created MySQL sink connector and successfully run and i see the logs and got 200 response, But the sink connector not able to push the data into mysql db (data is available in the topic)
{
"name":"mysql-sink-connector",
"config":{ "tasks.max":"2",
"batch.size":"1000",
"batch.max.rows":"1000",
"poll.interval.ms":"500",
"connector.class":"io.confluent.connect.jdbc.JdbcSinkConnector",
"connection.url":"jdbc:mysql://mysql.azure.com:3306/db_test_dev",
"table.name.format":"tbl_clients_merchants",
"topics":"createorder",
"connection.user":"user",
"connection.password":"password",
"auto.create":"true",
"auto.evolve":"true",
"value.converter":"org.apache.kafka.connect.json.JsonConverter",
"value.converter.schemas.enable":"true",
"key.converter":"org.apache.kafka.connect.json.JsonConverter",
"key.converter.schemas.enable":"true"
}}
getting an error
[2021-07-29 09:41:03,157] ERROR WorkerSinkTask{id=jdbc-mysql-sink-connector-1} Task threw an uncaught and unrecoverable exception (org.apache.kafka.connect.runtime.WorkerTask:177) org.apache.kafka.connect.errors.ConnectException: Tolerance exceeded in error handler
at org.apache.kafka.connect.runtime.errors.RetryWithToleranceOperator.execAndHandleError(RetryWithToleranceOperator.java:178)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748) Caused by: org.apache.kafka.connect.errors.DataException: Converting byte[] to Kafka Connect data failed due to serialization error:
at org.apache.kafka.connect.json.JsonConverter.toConnectData(JsonConverter.java:344)
at java.lang.Thread.run(Thread.java:748) Caused by: org.apache.kafka.connect.errors.DataException: Unknown schema type: null
at org.apache.kafka.connect.json.JsonConverter.convertToConnect(JsonConverter.java:743
at org.apache.kafka.connect.runtime.errors.RetryWithToleranceOperator.execAndHandleError(RetryWithToleranceOperator.java:162) ... 13 more
[2021-07-29 13:26:11,347] ERROR WorkerSinkTask{id=mysql-sink-connector-0} Task is being killed and will not recover until manually restarted (org.apache.kafka.connect.runtime.WorkerTask:178)
As the error suggests, you have null tombstone records in the topic, which cannot be mapped to any MySQL columns since there are no field names.
Option 1) Fix your producer to not send these messages
Option 2) Filter them in Connect
For example,
"transforms": "Filter",
"transforms.Filter.type": "org.apache.kafka.connect.transforms.Filter",
"transforms.Filter.predicate" : "DropNull",
"predicates" : "DropNull",
"predicates.DropNull.type": "org.apache.kafka.connect.transforms.predicates.RecordIsTombstone"
I have two pure Java EE applications, RemoteApp and ClientApp. I want to use ClientApp to access RemoteApp through a remote EJB to perfom some persistent action. I using JTA and CMT but when invoke anyone RemoteApp method in a Persistence Context and perform some Database action, the server simply does not respond until a transaction timeOut occurs.
To materialize what I said, I'll show the core code:
RemoteApp code:
package br.com;
#Remote
interface IRemote {void method();}
#Stateless
//I explained the use of these below annotations only for clarity
#TransactionManagement(value = TransactionManagementType.CONTAINER)
#TransactionAttribute(value = TransactionAttributeType.REQUIRED)
class Remote implements IRemote {
#PersistenceContext
private EntityManager em;
void method(){
em.persist(new MyEntity()); //A simple action just to example a Persistence Context situation
}
Persistence.xml of RemoteApp:
<persistence-unit name="remoteAppPU" transaction-type="JTA">
<jta-data-source>jdbc/remoteAppDS</jta-data-source>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="eclipselink.ddl-generation.table-creation-suffix" value="engine=InnoDB"/>
</properties>
</persistence-unit>
Datasource of Glassfish domain of RemoteApp (config.xml):
<jdbc-connection-pool datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" name="remoteAppPool" res-type="javax.sql.XADataSource">
<property name="user" value="user"></property>
<property name="url" value="jdbc:mysql://remoteApp:3306/remoteAppDB"></property>
<property name="password" value="password"></property>
</jdbc-connection-pool>
<jdbc-resource pool-name="remoteAppPool" jndi-name="jdbc/remoteAppDS"></jdbc-resource>
Client-App code:
#Stateless
class LocalBean {
#EJB(mappedName = "corbaname:iiop:server.com:3700#java:global/RemoteApp/Remote!br.com.IRemote"
private IRemote remote;
#TransactionAttribute
void testMethod(){remote.method();}
}
When ClientApp invokes a RemoteApp method i got a exception after 30 minutes (I can't found a way to decrease this time):
javax.ejb.EJBException: Unable to complete container-managed transaction.
at com.sun.ejb.containers.EJBContainerTransactionManager.completeNewTx(EJBContainerTransactionManager.java:734)
at com.sun.ejb.containers.EJBContainerTransactionManager.postInvokeTx(EJBContainerTransactionManager.java:507)
at com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4600)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2108)
at com.sun.ejb.containers.BaseContainer.postInvoke(BaseContainer.java:2078)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:220)
at com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:88)
at com.sun.proxy.$Proxy283.testar(Unknown Source)
at br.com.ejb.EJB31_Generated__LocalBean__Intf____Bean.method(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory.lambda$static$0(ResourceMethodInvocationHandlerFactory.java:76)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:148)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:191)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:243)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:103)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:493)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:415)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:104)
at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:277)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:272)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:268)
at org.glassfish.jersey.internal.Errors.process(Errors.java:316)
at org.glassfish.jersey.internal.Errors.process(Errors.java:298)
at org.glassfish.jersey.internal.Errors.process(Errors.java:268)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:289)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:256)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:703)
at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:416)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:370)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:389)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:342)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:229)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1580)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:258)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:652)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:591)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:371)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:238)
at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:463)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:168)
at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:206)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:180)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:242)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:133)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:539)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:593)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:573)
at java.lang.Thread.run(Thread.java:748)
Caused by: javax.transaction.SystemException: org.omg.CORBA.UNKNOWN: ----------BEGIN server-side stack trace----------
org.omg.CORBA.UNKNOWN: ADVERTÊNCIA: 00010002: Unknown user exception thrown by the server - exception: javax.persistence.PersistenceException; message: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.0.v20170811-d680af5): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: Error in allocating a connection. Cause: org.omg.CORBA.COMM_FAILURE: ADVERTÊNCIA: 00410019: Communications timeout waiting for response. Exceeded 1.800.000 milliseconds vmcid: OMG minor code: 19 completed: Maybe
Error Code: 0
Call: INSERT INTO MYENTITY (NAME) VALUES (?)
bind => [bla]
Query: InsertObjectQuery(br.com.MyEntity#0) vmcid: OMG minor code: 2 completed: Maybe
at com.sun.proxy.$Proxy194.runtimeexception(Unknown Source)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.convertThrowableToSystemException(MessageMediatorImpl.java:1764)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.handleThrowableDuringServerDispatch(MessageMediatorImpl.java:1714)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.handleThrowableDuringServerDispatch(MessageMediatorImpl.java:1679)
at com.sun.corba.ee.impl.protocol.ServerRequestDispatcherImpl.dispatch(ServerRequestDispatcherImpl.java:255)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.handleRequestRequest(MessageMediatorImpl.java:1550)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.handleRequest(MessageMediatorImpl.java:1426)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.handleInput(MessageMediatorImpl.java:931)
at com.sun.corba.ee.impl.protocol.giopmsgheaders.RequestMessage_1_2.callback(RequestMessage_1_2.java:213)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.handleRequest(MessageMediatorImpl.java:695)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.dispatch(MessageMediatorImpl.java:497)
at com.sun.corba.ee.impl.protocol.MessageMediatorImpl.doWork(MessageMediatorImpl.java:2223)
at com.sun.corba.ee.impl.threadpool.ThreadPoolImpl$WorkerThread.performWork(ThreadPoolImpl.java:497)
at com.sun.corba.ee.impl.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:540)
Caused by: javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.0.v20170811-d680af5): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: Error in allocating a connection. Cause: org.omg.CORBA.COMM_FAILURE: ADVERTÊNCIA: 00410019: Communications timeout waiting for response. Exceeded 1.800.000 milliseconds vmcid: OMG minor code: 19 completed: Maybe
Error Code: 0
Call: INSERT INTO MYENTITY (NAME) VALUES (?)
bind => [bla]
Query: InsertObjectQuery(br.com.MyEntity#0)
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl$1.handleException(EntityManagerSetupImpl.java:772)
at org.eclipse.persistence.transaction.AbstractSynchronizationListener.handleException(AbstractSynchronizationListener.java:275)
at org.eclipse.persistence.transaction.AbstractSynchronizationListener.beforeCompletion(AbstractSynchronizationListener.java:170)
at org.eclipse.persistence.transaction.JTASynchronizationListener.beforeCompletion(JTASynchronizationListener.java:68)
at com.sun.jts.jta.SynchronizationImpl.before_completion(SynchronizationImpl.java:99)
at com.sun.jts.CosTransactions.RegisteredSyncs.distributeBefore(RegisteredSyncs.java:141)
at com.sun.jts.CosTransactions.TopCoordinator.beforeCompletion(TopCoordinator.java:2548)
at com.sun.jts.CosTransactions.CoordinatorSynchronizationImpl.before_completion(CoordinatorSynchronizationImpl.java:165)
at org.omg.CosTransactions.SynchronizationPOA._invoke(SynchronizationPOA.java:39)
at com.sun.corba.ee.impl.protocol.ServerRequestDispatcherImpl.dispatchToServant(ServerRequestDispatcherImpl.java:528)
at com.sun.corba.ee.impl.protocol.ServerRequestDispatcherImpl.dispatch(ServerRequestDispatcherImpl.java:199)
... 9 more
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.0.v20170811-d680af5): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: Error in allocating a connection. Cause: org.omg.CORBA.COMM_FAILURE: ADVERTÊNCIA: 00410019: Communications timeout waiting for response. Exceeded 1.800.000 milliseconds vmcid: OMG minor code: 19 completed: Maybe
Error Code: 0
Call: INSERT INTO MYENTITY (NAME) VALUES (?)
bind => [bla]
Query: InsertObjectQuery(br.com.MyEntity#0)
... repeated log
Here are some observations:
Both Apps are in different containers and security configs are disable.
I have been used Glassfish Server 5.0 with Java EE Specification 8.0
I have ben used mysql 5.7 with XA Protocol and engine InnoDB on tables
If I don't use a Persistence Context / persistent operation it works
If I use BMT it works
I'm insisting on this approach because i want to control transaction by client, otherwise I would use a SIMPLE web service
CMT = Container Management Transaction = TransactionManagementType.CONTAINER
BMT = Bean Management Transaction = TransactionManagementType.BEAN
What I think is causing the problem:
I suspect MySql is crashing in commit / rollback (But i was tried with Derby and same problem happened)
A problem with XA MySql DataSource
MySql transaction support. I suspected that InnoDB engine would solve... I was wrong.
I've seen all sorts of posts on using Spring and MyBatis with transactions, but I'm facing a problem with rollbacks not working with plain old JDBC.
My ( test / throwaway) code is pretty simple : I open a session, insert a rec, throw an error on purpose and rollback the transaction. However, it always commits.
public static void main (String[] args){
//-- omitted for brevity
try {
org.apache.ibatis.logging.LogFactory.useSlf4jLogging();
inputStream = Resources.getResourceAsStream("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
sess = sqlSessionFactory.openSession(false);
BillsMapper mapper = sess.getMapper(BillsMapper.class);
BillState billState = new BillState();
billState.setBillId(-1);
billState.setLastName("TESTER");
billState.setFirstName("TESTER");
mapper.insert(billState);
logger.info("Post insert: key = {}", billState.getBillId());
if(1 == 1)
throw new RuntimeException("Error Thrown on purpose...testing rollback ");
sess.commit();
}catch(Exception e){
logger.error("Error: {}", e);
sess.rollback();
}finally{
sess.close();
logger.info("Finito!");
}
}
The logs show:
DEBUG | (BaseJdbcLogger.java:145) - ==> Preparing: insert into bills (users_userId, refId, firstName, ...
DEBUG | (BaseJdbcLogger.java:145) - ==> Parameters: 67(Integer), 67-120530180328(String), TESTER(String), ...
DEBUG | (BaseJdbcLogger.java:145) - <== Updates: 1
INFO | (TestAction.java:50) - Post insert: key = 2478
ERROR | (TestAction.java:56) - Error: {} java.lang.RuntimeException: Error Thrown on purpose...testing rollback at com.s2stest.TestAction.main(TestAction.java:53)
DEBUG | (JdbcTransaction.java:79) - Rolling back JDBC Connection [com.mysql.jdbc.JDBC4Connection#371e88fb]
DEBUG | (JdbcTransaction.java:122) - Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection#371e88fb]
DEBUG | (JdbcTransaction.java:90) - Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection#371e88fb]
DEBUG | (PooledDataSource.java:344) - Returned connection 924748027 to pool.
Note the resetting of autocommit before closing the connection.... Would resetting autcommit before closing the SqlSession cause my rolled-back transaction to be committed? If so, is this a bug? Has anyone gotten JDBC working with transactions? I need it for testing, and I'd value some help. Right now, no transactions can be rolled back.
I've looked at the MyBatis source, and it indeed calls resetAutocommit before closing the connection. I'm using MySQL 5.6 and mysql-connector-java-5.1.36.jar for the driver if someone has a workaround that they've found.
--- UPDATE ---
mybatis-config.xml is as follows:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="logImpl" value="SLF4J" />
</settings>
<typeAliases>
<package name="com.ship2storage.domain" />
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mytestDb?zeroDateTimeBehavior=convertToNull" />
<property name="username" value="--shhh!!--" />
<property name="password" value="--shhh!!--" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/ship2storage/db/maps/BillsMapper.xml" />
</mappers>
</configuration>
OK, I've found the answer by digging deeper into my setup. It seems that the MySQL storage engine I installed for my test DB is ISAM. ISAM does not support transactions. I switched to InnoDB using the following SQL tidbit, and transactions now work with JDBC:
ALTER TABLE bills ENGINE=InnoDB;
I haven't tried this, but it looks like you can also do this temporarily too:
SET default_storage_engine=InnoDB;
Hopefully this will help someone. The code/config posted above works.
I have a very simple test that works with dbcp connection pool and forever hangs with c3p0 (0.9.2).
private String query="select ROWID from SOMETABLE " +
" where rownum <= 100 for update skip locked";
private String deleteQuery = "delete from SOMETABLE where ROWID = ?";
public void retrieve() throws Exception {
while (retrieveChunk() > 0){
//do nothing
}
}
#Transactional
private int retrieveChunk(){
final List<Object[]> delPar = new ArrayList<Object[]>(100);
template.query(query, new RowCallbackHandler() {
public void processRow(ResultSet rs) throws SQLException {
String rowid = rs.getString(1);
delPar.add(new String[]{rowid});
}
});
template.batchUpdate(deleteQuery, delPar);
return delPar.size();
}
Spring context:
<bean id="connPool" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="user" value="**"/>
<property name="password" value="**"/>
<property name="driverClass" value="oracle.jdbc.driver.OracleDriver"/>
<property name="jdbcUrl" value="jdbc:oracle:thin:#****"/>
<property name="initialPoolSize" value="0"/>
<property name="maxPoolSize" value="10"/>
<property name="minPoolSize" value="1"/>
<property name="acquireIncrement" value="1"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg>
<ref bean="connPool"/>
</constructor-arg>
</bean>
What is wrong with c3p0 configuration?
Update - log4j output:
12:17:18,449 DEBUG JdbcTemplate:435 - Executing SQL query [select ROWID from SOMETABLE where rownum <= 100 for update skip locked]
12:17:18,465 DEBUG DataSourceUtils:110 - Fetching JDBC Connection from DataSource
12:17:18,809 DEBUG DataSourceUtils:327 - Returning JDBC Connection to DataSource
12:17:18,809 DEBUG JdbcTemplate:881 - Executing SQL batch update [delete from SOMETABLE where ROWID = ?]
12:17:18,824 DEBUG JdbcTemplate:570 - Executing prepared SQL statement [delete from SOMETABLE where ROWID = ?]
12:17:18,824 DEBUG DataSourceUtils:110 - Fetching JDBC Connection from DataSource
12:17:18,887 DEBUG JdbcUtils:362 - JDBC driver supports batch updates
12:17:18,902 DEBUG DataSourceUtils:327 - Returning JDBC Connection to DataSource
12:17:18,902 INFO PlainJdbcTableRetriever:36 - JdbcTemplateRetriever retrieve started
12:17:18,902 DEBUG JdbcTemplate:435 - Executing SQL query [select ROWID from SOMETABLE where rownum <= 100 for update skip locked]
12:17:18,902 DEBUG DataSourceUtils:110 - Fetching JDBC Connection from DataSource
12:17:18,934 DEBUG DataSourceUtils:327 - Returning JDBC Connection to DataSource
12:17:18,934 DEBUG JdbcTemplate:881 - Executing SQL batch update [delete from SOMETABLE where ROWID = ?]
12:17:18,934 DEBUG JdbcTemplate:570 - Executing prepared SQL statement [delete from SOMETABLE where ROWID = ?]
12:17:18,934 DEBUG DataSourceUtils:110 - Fetching JDBC Connection from DataSource
12:17:18,934 DEBUG JdbcUtils:362 - JDBC driver supports batch updates
12:17:18,934 DEBUG DataSourceUtils:327 - Returning JDBC Connection to DataSource
12:17:18,934 DEBUG JdbcTemplate:435 - Executing SQL query [select ROWID from SOMETABLE where rownum <= 100 for update skip locked]
12:17:18,934 DEBUG DataSourceUtils:110 - Fetching JDBC Connection from DataSource
12:17:18,981 DEBUG DataSourceUtils:327 - Returning JDBC Connection to DataSource
12:17:18,981 DEBUG JdbcTemplate:881 - Executing SQL batch update [delete from SOMETABLE where ROWID = ?]
12:17:18,981 DEBUG JdbcTemplate:570 - Executing prepared SQL statement [delete from SOMETABLE where ROWID = ?]
12:17:18,981 DEBUG DataSourceUtils:110 - Fetching JDBC Connection from DataSource
12:17:18,981 DEBUG JdbcUtils:362 - JDBC driver supports batch updates
12:17:18,996 DEBUG DataSourceUtils:327 - Returning JDBC Connection to DataSource
12:17:18,996 DEBUG JdbcTemplate:435 - Executing SQL query [select ROWID from SOMETABLE where rownum <= 100 for update skip locked]
12:17:18,996 DEBUG DataSourceUtils:110 - Fetching JDBC Connection from DataSource
12:17:19,012 DEBUG DataSourceUtils:327 - Returning JDBC Connection to DataSource
12:17:19,012 DEBUG JdbcTemplate:881 - Executing SQL batch update [delete from SOMETABLE where ROWID = ?]
12:17:19,012 DEBUG JdbcTemplate:570 - Executing prepared SQL statement [delete from SOMETABLE where ROWID = ?]
12:17:19,012 DEBUG DataSourceUtils:110 - Fetching JDBC Connection from DataSource
12:17:19,012 DEBUG JdbcUtils:362 - JDBC driver supports batch updates