I am developing a JSF application which uses JNDI connection pooling to a DB2 database through the Tomcat 7 configuration. I am having problems managing transactions and more specifically rolling back when an exception is thrown from a method which shares a connection.
The following code establishes a connection and passes this down through all other methods being called. This connection is then only closed in the finally block of the method. My issue is that for example...if an exception is thrown at any point in the method, any work completed prior to this is committed and not rolled back. I was under the impression that when closing a connection in the finally block, this would not commit if any exceptions were thrown during the life time of this connection and then the connection is returned to the pool regardless if the work has been committed or rolled back.
public boolean updateSubCountry(SubCountryDTO dto,
List<FeatureAliasDTO> aliases, List<FeatureCodeDTO> codes)
throws ReferenceDataException {
boolean success = true;
Connection c = null;
try {
c = fDao.getConnection();
success = fDao.updateSubCountry(c, dto, TEMP_USERNAME) && success;
success = updateAliases(c, aliases, dto.getOdi(), TEMP_USERNAME,
dto.getSubCountryId()) && success;
for (FeatureCodeDTO codeDto : codes) {
success = updateFeatureCode(c, codeDto, dto.getSubCountryId())
&& success;
}
} finally {
closeConnection(c, DEFAULT_CONNECTION_ERROR_MSG);
}
return success;
}
My JNDI configuration is as follows (sensitive info starred out):
<Resource name="jdbc/core" auth="Container" type="javax.sql.DataSource"
url="****"
driverClassName="com.ibm.db2.jcc.DB2Driver"
username="****" password="****"
maxActive="20" maxIdle="3" maxWait="10000"
poolPreparedStatements="true"
maxOpenPreparedStatements="100"
validationQuery="SELECT 1 FROM SYSIBM.SYSDUMMY1" />
Any help is appreciated.
Thanks.
UPDATE
I have attempted to implement the suggestions made by #Tiny. However, the when purposely making updateFeatureCode() method throw an exception on the database level, any work before this is still not rolled back?
#Transactional (rollbackFor={Exception.class, ReferenceDataException.class})
public boolean updateSubCountry(SubCountryDTO dto,
List<FeatureAliasDTO> aliases, List<FeatureCodeDTO> codes)
throws ReferenceDataException {
boolean success = true;
Connection c = null;
try {
c = fDao.getConnection();
success = fDao.updateSubCountry(c, dto, TEMP_USERNAME) && success;
success = updateAliases(c, aliases, dto.getOdi(), TEMP_USERNAME,
dto.getSubCountryId()) && success;
for (FeatureCodeDTO codeDto : codes) {
success = updateFeatureCode(c, codeDto, dto.getSubCountryId())
&& success;
}
} finally {
closeConnection(c, DEFAULT_CONNECTION_ERROR_MSG);
}
return success;
}
The IBM JDBC driver, when connected to a DB2 database, defaults to autoCommit=true, which means that an explicit COMMIT is issued after each statement. If you wish to control transactions yourself, disable autocommit and commit or rollback as necessary. Alternatively, as suggested by #Tiny, use a transaction manager.
Related
I have a jax-rs-based REST service that I run on Tomcat 8.5 on 64bit Linux, using Java 11; this service connects to a RavenDB 4.1.2 instance, also on the same Linux machine. I make use of the streaming query to return the request result. I use Postman to submit the same request, and everything works well: the results are returned, and rather quickly.
However - it only works 10 times. When I submit the same request as previously an 11th time, the results = currentSession.advanced().stream(query); line hangs and doesn't return.
At first I thought I could have something to do with the StreamingOutput or OutputStreamWriter not being closed appropriately. or perhaps something do to with the Response - but as I stepped through the deployed code in Eclipse in debug mode, I noticed that execution hangs on that streaming line.
(I find exactly 10 times to be a peculiarly "human choice" kind of number...)
The relevant parts of my code:
#GET
#Path("/abcntr/{ccode}/{st}/{zm}")
#Produces(MediaType.TEXT_PLAIN)
#Consumes(MediaType.TEXT_PLAIN)
public Response retrieveInfo(#PathParam("ccode") String ccode, #PathParam("st") String st, #PathParam("zm") String zm)
{
(...)
StreamingOutput adminAreaStream = new StreamingOutput()
{
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
#Override
public void write(OutputStream output) throws IOException, WebApplicationException
{
try(IDocumentSession currentSession = ServiceListener.ravenDBStore.openSession())
{
Writer writer = new BufferedWriter(new OutputStreamWriter(output));
(...)
if(indexToBeQueried.startsWith("Level0"))
{
IDocumentQuery<AdministrativeArea> query = currentSession.query(area.class, Query.index(indexToBeQueried))
.whereEquals("i", ccode);
results = currentSession.advanced().stream(query);
}
else
{
IDocumentQuery<AdministrativeArea> query = currentSession.query(area.class, Query.index(indexToBeQueried))
.whereEquals("i", ccode)
.andAlso()
.whereEquals("N1", sName);
results = currentSession.advanced().stream(query); // THIS IS WHERE IT DOESNT COME BACK
}
while(results.hasNext())
{
StreamResult<AdministrativeArea> adma = results.next();
adma.getDocument().properties = retrievePropertiesForArea(adma.getDocument(), currentSession);
writer.write(ow.writeValueAsString(adma.getDocument()));
writer.write(",");
}
(...)
currentSession.advanced().clear();
currentSession.close();
}
catch (Exception e)
{
System.out.println("Exception: " + e.getMessage() + e.getStackTrace());
}
}
};
if(!requestIsValid)
return Response.status(400).build();
else
return Response.ok(adminAreaStream).build();
}
The RavenDB error logs come up empty, as do the Tomcat error logs. The only thing that remotely resembles an error message relevant to this is something that shows up from "Gather debug info":
System.ArgumentNullException: Value cannot be null.
Parameter name: source
at System.Linq.Enumerable.Any[TSource](IEnumerable`1 source, Func`2 predicate)
at Raven.Server.Documents.Handlers.Debugging.QueriesDebugHandler.QueriesCacheList() in C:\Builds\RavenDB-Stable-4.1\src\Raven.Server\Documents\Handlers\Debugging\QueriesDebugHandler.cs:line 181
at Raven.Server.ServerWide.LocalEndpointClient.InvokeAsync(RouteInformation route, Dictionary`2 parameters) in C:\Builds\RavenDB-Stable-4.1\src\Raven.Server\ServerWide\LocalEndpointClient.cs:line 61
at Raven.Server.ServerWide.LocalEndpointClient.InvokeAndReadObjectAsync(RouteInformation route, JsonOperationContext context, Dictionary`2 parameters) in C:\Builds\RavenDB-Stable-4.1\src\Raven.Server\ServerWide\LocalEndpointClient.cs:line 91
at Raven.Server.Documents.Handlers.Debugging.ServerWideDebugInfoPackageHandler.WriteForDatabase(ZipArchive archive, JsonOperationContext jsonOperationContext, LocalEndpointClient localEndpointClient, String databaseName, String path) in C:\Builds\RavenDB-Stable-4.1\src\Raven.Server\Documents\Handlers\Debugging\ServerWideDebugInfoPackageHandler.cs:line 311
Thank you for any kinds of investigation hints you can give me.
UPDATE:
Same thing when moving the compiler and Tomcat JVM back to Java 1.8.
It appears that it has nothing to do with Java 11 (or 1.8), but simply that it had slipped my attention to close CloseableIterator<StreamResult<AdministrativeArea>> results; After adding a simple results.close(); everything appears to work as it should. If this wasn't the solution, I'll come back and update.
I'm connecting to Azure Redis and they show me the number of open connections to my redis server. I've got the following c# code that encloses all my Redis sets and gets. Should this be leaking connections?
using (var connectionMultiplexer = ConnectionMultiplexer.Connect(connectionString))
{
lock (Locker)
{
redis = connectionMultiplexer.GetDatabase();
}
var o = CacheSerializer.Deserialize<T>(redis.StringGet(cacheKeyName));
if (o != null)
{
return o;
}
lock (Locker)
{
// get lock but release if it takes more than 60 seconds to complete to avoid deadlock if this app crashes before release
//using (redis.AcquireLock(cacheKeyName + "-lock", TimeSpan.FromSeconds(60)))
var lockKey = cacheKeyName + "-lock";
if (redis.LockTake(lockKey, Environment.MachineName, TimeSpan.FromSeconds(10)))
{
try
{
o = CacheSerializer.Deserialize<T>(redis.StringGet(cacheKeyName));
if (o == null)
{
o = func();
redis.StringSet(cacheKeyName, CacheSerializer.Serialize(o),
TimeSpan.FromSeconds(cacheTimeOutSeconds));
}
redis.LockRelease(lockKey, Environment.MachineName);
return o;
}
finally
{
redis.LockRelease(lockKey, Environment.MachineName);
}
}
return o;
}
}
}
You can keep connectionMultiplexer in a static variable and not create it for every get/set. That will keep one connection to Redis always opening and proceed your operations faster.
Update:
Please, have a look at StackExchange.Redis basic usage:
https://github.com/StackExchange/StackExchange.Redis/blob/master/Docs/Basics.md
"Note that ConnectionMultiplexer implements IDisposable and can be disposed when no longer required, but I am deliberately not showing using statement usage, because it is exceptionally rare that you would want to use a ConnectionMultiplexer briefly, as the idea is to re-use this object."
It works nice for me, keeping single connection to Azure Redis (sometimes, create 2 connections, but this by design). Hope it will help you.
I was suggesting try using Close (or CloseAsync) method explicitly. In a test setting you may be using different connections for different test cases and not want to share a single multiplexer. A search for public code using Redis client shows a pattern of Close followed by Dispose calls.
Noting in the XML method documentation of Redis client that close method is described as doing more:
//
// Summary:
// Close all connections and release all resources associated with this object
//
// Parameters:
// allowCommandsToComplete:
// Whether to allow all in-queue commands to complete first.
public void Close(bool allowCommandsToComplete = true);
//
// Summary:
// Close all connections and release all resources associated with this object
//
// Parameters:
// allowCommandsToComplete:
// Whether to allow all in-queue commands to complete first.
[AsyncStateMachine(typeof(<CloseAsync>d__183))]
public Task CloseAsync(bool allowCommandsToComplete = true);
...
//
// Summary:
// Release all resources associated with this object
public void Dispose();
And then I looked up the code for the client, found it here:
https://github.com/StackExchange/StackExchange.Redis/blob/master/src/StackExchange.Redis/ConnectionMultiplexer.cs
And we can see Dispose method calling Close (not the usual override-able protected Dispose(bool)), further more with the wait for connections to close set to true. It appears to be an atypical dispose pattern implementation in that by trying all the closure and waiting on them it is chancing to run into exception while Dispose method contract is supposed to never throw one.
I recently switched an MVC application that serves data feeds and dynamically generated images (6k rpm throughput) from the v3.9.67 ServiceStack.Redis client to the latest StackExchange.Redis client (v1.0.450) and I'm seeing some slower performance and some new exceptions.
Our Redis instance is S4 level (13GB), CPU shows a fairly constant 45% or so and network bandwidth appears fairly low. I'm not entirely sure how to interpret the gets/sets graph in our Azure portal, but it shows us around 1M gets and 100k sets (appears that this may be in 5 minute increments).
The client library switch was straightforward and we are still using the v3.9 ServiceStack JSON serializer so that the client lib was the only piece changing.
Our external monitoring with New Relic shows clearly that our average response time increases from about 200ms to about 280ms between ServiceStack and StackExchange libraries (StackExchange being slower) with no other change.
We recorded a number of exceptions with messages along the lines of:
Timeout performing GET feed-channels:ag177kxj_egeo-_nek0cew, inst: 12, mgr: Inactive, queue: 30, qu=0, qs=30, qc=0, wr=0/0, in=0/0
I understand this to mean that there are a number of commands in the queue that have been sent but no response available from Redis, and that this can be caused by long running commands that exceed the timeout. These errors appeared for a period when our sql database behind one of our data services was getting backed up, so perhaps that was the cause? After scaling out that database to reduce load we haven't seen very many more of this error, but the DB query should be happening in .Net and I don't see how that would hold up a redis command or connection.
We also recorded a large batch of errors this morning over a short period (couple of minutes) with messages like:
No connection is available to service this operation: SETEX feed-channels:vleggqikrugmxeprwhwc2a:last-retry
We were used to transient connection errors with the ServiceStack library, and those exception messages were usually like this:
Unable to Connect: sPort: 63980
I'm under the impression that SE.Redis should be retrying connections and commands in the background for me. Do I still need to be wrapping our calls through SE.Redis in a retry policy of my own? Perhaps different timeout values would be more appropriate (though I'm not sure what values to use)?
Our redis connection string sets these parameters: abortConnect=false,syncTimeout=2000,ssl=true. We use a singleton instance of ConnectionMultiplexer and transient instances of IDatabase.
The vast majority of our Redis use goes through a Cache class, and the important bits of the implementation are below, in case we're doing something silly that's causing us problems.
Our keys are generally 10-30 or so character strings. Values are largely scalar or reasonably small serialized object sets (hundred bytes to a few kB generally), though we do also store jpg images in the cache so a large chunk of the data is from a couple hundred kB to a couple MB.
Perhaps I should be using different multiplexers for small and large values, probably with longer timeouts for larger values? Or couple/few multiplexers in case one is stalled?
public class Cache : ICache
{
private readonly IDatabase _redis;
public Cache(IDatabase redis)
{
_redis = redis;
}
// storing this placeholder value allows us to distinguish between a stored null and a non-existent key
// while only making a single call to redis. see Exists method.
static readonly string NULL_PLACEHOLDER = "$NULL_VALUE$";
// this is a dictionary of https://github.com/StephenCleary/AsyncEx/wiki/AsyncLock
private static readonly ILockCache _locks = new LockCache();
public T GetOrSet<T>(string key, TimeSpan cacheDuration, Func<T> refresh) {
T val;
if (!Exists(key, out val)) {
using (_locks[key].Lock()) {
if (!Exists(key, out val)) {
val = refresh();
Set(key, val, cacheDuration);
}
}
}
return val;
}
private bool Exists<T>(string key, out T value) {
value = default(T);
var redisValue = _redis.StringGet(key);
if (redisValue.IsNull)
return false;
if (redisValue == NULL_PLACEHOLDER)
return true;
value = typeof(T) == typeof(byte[])
? (T)(object)(byte[])redisValue
: JsonSerializer.DeserializeFromString<T>(redisValue);
return true;
}
public void Set<T>(string key, T value, TimeSpan cacheDuration)
{
if (value.IsDefaultForType())
_redis.StringSet(key, NULL_PLACEHOLDER, cacheDuration);
else if (typeof (T) == typeof (byte[]))
_redis.StringSet(key, (byte[])(object)value, cacheDuration);
else
_redis.StringSet(key, JsonSerializer.SerializeToString(value), cacheDuration);
}
public async Task<T> GetOrSetAsync<T>(string key, Func<T, TimeSpan> getSoftExpire, TimeSpan additionalHardExpire, TimeSpan retryInterval, Func<Task<T>> refreshAsync) {
var softExpireKey = key + ":soft-expire";
var lastRetryKey = key + ":last-retry";
T val;
if (ShouldReturnNow(key, softExpireKey, lastRetryKey, retryInterval, out val))
return val;
using (await _locks[key].LockAsync()) {
if (ShouldReturnNow(key, softExpireKey, lastRetryKey, retryInterval, out val))
return val;
Set(lastRetryKey, DateTime.UtcNow, additionalHardExpire);
try {
var newVal = await refreshAsync();
var softExpire = getSoftExpire(newVal);
var hardExpire = softExpire + additionalHardExpire;
if (softExpire > TimeSpan.Zero) {
Set(key, newVal, hardExpire);
Set(softExpireKey, DateTime.UtcNow + softExpire, hardExpire);
}
val = newVal;
}
catch (Exception ex) {
if (val == null)
throw;
}
}
return val;
}
private bool ShouldReturnNow<T>(string valKey, string softExpireKey, string lastRetryKey, TimeSpan retryInterval, out T val) {
if (!Exists(valKey, out val))
return false;
var softExpireDate = Get<DateTime?>(softExpireKey);
if (softExpireDate == null)
return true;
// value is in the cache and not yet soft-expired
if (softExpireDate.Value >= DateTime.UtcNow)
return true;
var lastRetryDate = Get<DateTime?>(lastRetryKey);
// value is in the cache, it has soft-expired, but it's too soon to try again
if (lastRetryDate != null && DateTime.UtcNow - lastRetryDate.Value < retryInterval) {
return true;
}
return false;
}
}
A few recommendations.
- You can use different multiplexers with different timeout values for different types of keys/values
http://azure.microsoft.com/en-us/documentation/articles/cache-faq/
- Make sure you are not network bound on the client and server. if you are on the server then move to a higher SKU which has more bandwidth
Please read this post for more details
http://azure.microsoft.com/blog/2015/02/10/investigating-timeout-exceptions-in-stackexchange-redis-for-azure-redis-cache/
I have used .net C# code to put messages on the queue and get messages back. I have no problem in accessing the queue and getting messages. Now I want to have the get message calls under Transaction and used explicit transaction option to commit and rollback the messages.
try
{
MQQueueManager queueManager;
MQEnvironment.Hostname = hostName;
MQEnvironment.Channel = channelName;
MQEnvironment.Port = 1414;
MQEnvironment.properties.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES);
queueManager = new MQQueueManager(queueManagerName);
// obtain a read/write queue reference
var queue = queueManager.AccessQueue(queueName, MQC.MQOO_INPUT_AS_Q_DEF + MQC.MQOO_INQUIRE + MQC.MQOO_FAIL_IF_QUIESCING);
IList<string> Messages = new List<string>();
using (var scope = new CommittableTransaction())
{
CommittableTransaction.Current = scope;
var message = new MQMessage();
try
{
var getMessageOptions = new MQGetMessageOptions();
getMessageOptions.Options += MQC.MQGMO_SYNCPOINT ;
int i = queue.CurrentDepth;
queue.Get(message,getMessageOptions);
Console.WriteLine(message.ReadString(message.MessageLength));
scope.Rollback();
}
catch (MQException mqe)
{
if (mqe.ReasonCode == 2033)
{
Console.WriteLine("No more message available");
Console.ReadLine();
scope.Rollback();
}
else
{
Console.WriteLine("MQException caught: {0} - {1}", mqe.ReasonCode, mqe.Message);
Console.ReadLine();
scope.Rollback();
}
}
CommittableTransaction.Current = null;
}
// closing queue
queue.Close();
// disconnecting queue manager
queueManager.Disconnect();
Console.ReadLine();
}
catch (MQException mqe)
{
Console.WriteLine("");
Console.WriteLine("MQException caught: {0} - {1}", mqe.ReasonCode, mqe.Message);
Console.WriteLine(mqe.StackTrace);
Console.ReadLine();
}
The first problem I faced was , related to access to System.Dotnet.XARecovery queue. Even though I had access to the queue to get messages from the queue , the program started to fail because of the access rights on the recovery queue when below line was invoked.
queue.Get(messages),
Then I got the access on the recovery queue and access denied problem was resolved. Now after getting the message from the queue , the messages are not roll backed after scope.RollBack() is called.
I checked in the System.Dotnet.XARecovery queue and dead letter queue and there was not nothing there as well.
Why I am not able to see the rolled back messages in the WMQ message queue.
You have a scope.Commit(); after queue.Get(message); After getting the message you are explicitly calling the Commit. If the Get is successful, the Commit call tells the queue manager to remove the message from queue. So there is no chance of message getting rolled back.
EDIT: GMO_SYNCPOINT option is missing in your code. You need to have something like this
MQGetMessageOptions getMessageOptions = new MQGetMessageOptions();
getMessageOptions.Options += MQC.MQGMO_SYNCPOINT;
queue.Get(message, getMessageOptions);
I figured out the solution of my problem. In my code above if I change the line from
MQEnvironment.properties.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES);
to
MQEnvironment.properties.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED);
then it starts to register the transactions of the local DTC as well as it works fine in rolling back or commit a message on the queue.
I know related questions are asked in other places but mine is different :)
I'm using BasicHttpClient and a HttpPoster to send stuff to a thirdparty service. I'm using this in a scenario where i have JMS listeners using a single bean to post stuff. I didn't think this was a problem since the BasicHttpclient uses SingleClientConnectionManager and the javadoc says
This connection manager maintains only one active connection at a time. Even though this class is thread-safe it ought to be used by one execution thread only.
(thread-safe is key here) But, when i have two simultaneous requests i get the classic
java.lang.IllegalStateException: Invalid use of SingleClientConnManager: connection still allocated.
Why do i get that? I don't clean up anything since the basicclient does that according to the docs.
my bean constructor:
HttpParams params = new BasicHttpParams();
params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, SMS_SOCKET_TIMEOUT);
params.setParameter(CoreConnectionPNames.SO_TIMEOUT, SMS_SOCKET_TIMEOUT);
params.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET,
encoding);
params.setParameter(CoreProtocolPNames.HTTP_ELEMENT_CHARSET,
encoding);
httpclient = new DefaultHttpClient(params);
poster = new HttpPost(mtUrl);
poster.setHeader("Content-type", contentType);
responseHandler = new BasicResponseHandler();
my code to run a post call:
public String[] sendMessage(MtMessage mess) throws MtSendException, MtHandlingException {
StringEntity input;
try {
String postBody = assembleMessagePostBody(mess);
input = new StringEntity(postBody);
poster.setEntity(input);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
String response = httpclient.execute(poster, responseHandler);
return new String[]{extractResponseMessageId(response)};
} catch(HttpResponseException ee){
throw new MtSendException(ee.getStatusCode(), ee.getMessage(), false);
} catch (IOException e) {
throw new MtSendException(0, e.getMessage(), false);
} finally{
}
}
I thought that although the "sendMessage" could be called from multiple JMS listener threads at once, it would be thread safe, since the connectionhandler is thread safe. I guess i could just make the sendMessage() method synchronized perhaps.
If anyone has any input, i'd be most thankful.
SingleClientConnectionManager is fully thread safe in the sense that when used by multiple execution threads its internal state is synchronized and is always consistent. This does not change the fact that it can dispense a single connection only. So, if two threads attempt to lease a connection, only one can succeed, while the other is likely to get 'java.lang.IllegalStateException: Invalid use of SingleClientConnManager'
You should be using a pooling connection manager if your application needs to execute requests concurrently.