do we need to synchronise the DB calls if multithreading is involved? - multithreading

I have a scenario where two threads invoke a method and this method generated a sequence using postgres nextval(test_sequence).
test_sequence is initailly assigned to 1.
public String createNotification() {
logger.info("createNotification ENTRY");
Future<String> futRes = this.threadPool.submit(new Callable<String>() {
#Override
public String call() {
String notificationID = getNotificationId();//DB CALL TO GENERATE THE NEXT SEQUENCE.
boolean isInsertSuccess = notificationDaoService.insertNotificationIntoDB(notificationID);
if (isInsertSuccess == true) {
return notificationID;
} else {
return null;
}
}
});
try {
return futRes.get(5, TimeUnit.SECONDS);
} catch (Exception e) {
logger.error("Issue while getting value from future with exception :", e);
return null;
}
}
So in the above snippet, getNotificationId() will generate the sequence and insertNotificationIntoDB() wil insert the generated notification id to the table.
I some times observing the primary key voilation exception when multiple threads try to invoke createNotification().
So i am thinking to synchronise the db calls as mentioned below,
synchronised(object)
{
String notificationID = getNotificationId();
boolean isInsertSuccess = notificationDaoService.insertNotificationIntoDB(notificationID);
}
is this solution ok?
and also i want to ask if i can generalise that if multiple threads are accessing a function and if that function has DB calls that does basic CRUD, then all the DB calls needs to be synchronised. Is this right inference?

Related

JavaFX task waiting for another task to finish

I'm pretty new with concurency and I'v hit the wall several times already.
Code pretty much describes everything, but just to clarify: user press the button, application send query to db and in the meantime statusLabel is set to:
Veryfing.
200ms
Veryfing..
200ms
Veryfing...
200ms
Result of query
I'v managed to achieve that, but now, I need to use result of query in another class (if it succeed, another window is opened), but It never does. I came to conclusion that it just checks the result before Task is finished so result is always false, I have no idea how to work around this, so another class checks condition once Task is done.
First, my Authorization class
public class Authorization {
private static String query = "";
private static boolean isValid;
private static Task<Void> task;
public static void verifyLogin(String username, String password) throws SQLException{
Status.get().unbind();
isValid = false;
task = new Task<Void>() {
#Override
protected Void call() throws SQLException {
while(!isCancelled()) {
try {
updateMessage("Weryfikacja.");
Thread.sleep(200);
updateMessage("Weryfikacja..");
Thread.sleep(200);
updateMessage("Weryfikacja...");
Thread.sleep(200);
if(username.equals("") || password.equals("")) {
task.cancel();
updateMessage("Pola nie mogą być puste");
} else {
query = "SELECT login FROM users WHERE login = ?";
Query.execute(query, username);
if(!Query.resultSet.next()) {
task.cancel();
updateMessage("Nie ma takiego użytkownika");
} else {
query = "SELECT password FROM users WHERE login = ?";
Query.execute(query, username);
if(Query.resultSet.next()) {
String passwordValue = Query.resultSet.getString(1);
if(!password.equals(passwordValue)) {
task.cancel();
updateMessage("Podane hasło jest błędne");
} else {
task.cancel();
updateMessage("");
isValid = true;
}
}
}
}
} catch(InterruptedException e) {
if(isCancelled()) {
break;
}
}
}
return null;
}
};
Status.get().bind(task.messageProperty());
new Thread(task).start();
}
public static boolean isValid() {
return isValid;
}
}
called from another class
private void login() {
if( SqlConnection.isConnected()) {
try{
Authorization.verifyLogin(String.valueOf(loginInput.getText()), String.valueOf(passwordInput.getText()));
if(Authorization.isValid()) {
//should go to next menu
//but never does
}
} catch (SQLException e) {
e.printStackTrace();
Debug.log(e.toString());
}
}
}
edit#
Sorry for polish in updateMessage().
Your verifyLogin() method simply starts the verification process in another thread, and then exits immediately. The isValid flag will not be changed until that thread completes, which happens quite a lot later. If you want to do the verification process and then do something else, it doesn't really make sense to manage the threads in verifyLogin().
I don't really understand a lot of what your code is supposed to be doing; you have a while(...) loop, which as far as I can tell can only be executed once (so is redundant). You also seem to execute two SQL queries which are essentially the same. (The first checks to see if there is a row with a certain condition, then if there is, the second retrieves that row. Why not just retrieve the row and check if it is there?)
I would refactor this so that the validateLogin() method doesn't handle the threading at all, and just returns the result of the validation (e.g. a status string, but maybe something else would be appropriate).
/**
* #return An empty string if the login is valid, or an error message otherwise
*/
public static String verifyLogin(String username, String password) throws SQLException{
isValid = false ;
if(username.equals("") || password.equals("")) {
return "Pola nie mogą być puste";
}
query = "SELECT login, password FROM users WHERE login = ?";
Query.execute(query, username);
if(!Query.resultSet.next()) {
return "Nie ma takiego użytkownika";
}
String passwordValue = Query.resultSet.getString(2);
if(!password.equals(passwordValue)) {
return "Podane hasło jest błędne" ;
}
isValid = true;
return "" ;
}
Now I would manage the threads from the login() method. That way you can use the task's onSucceeded handler to execute code when the task completes:
private void login() {
if( SqlConnection.isConnected()) {
Task<String> verifyTask = new Task<String>() {
#Override
protected String call() throws SQLException {
return Authorization.verifyLogin(loginInput.getText(), passwordInput.getText());
}
};
// probably better to use a progress indicator or similar here, but:
Animation animation = new Timeline(
new KeyFrame(Duration.ZERO, e -> Status.get().set("Weryfikacja.")),
new KeyFrame(Duration.millis(200), e -> Status.get().set("Weryfikacja..")),
new KeyFrame(Duration.millis(400), e -> Status.get().set("Weryfikacja...")),
new KeyFrame(Duration.millis(600)));
animation.setCycleCount(Animation.INDEFINITE);
verifyTask.setOnSucceeded(event -> {
animation.stop();
Status.get().set(verifyTask.getValue());
if(Authorization.isValid()) { // or if (verifyTask.getValue().isEmpty())
// go to next menu
}
});
verifyTask.setOnFailed(event -> {
animation.stop();
verifyTask.getException().printStackTrace();
Debug.log(verifyTask.getException().toString());
}
animation.play();
new Thread(verifyTask()).start();
}
}

JDBC insertin String,Date and duration values to table

I've been trying to insert String, Date(now) and duration to the table.
Here is my code: At the args section (at the end) "app.insert("name", "date_added","path", "duration");" those values I mentioned as " date_added and duration" it wants me to convert them into String with an error. How can I prevent this happening and let the code enter date(now) and duration to app.insert section?
package xxxxx;
import java.sql.*;
public class SAMPLE_SOUND {
private Connection connect() {
String url = "jdbc:sqlite:neural.db";
Connection conn = null;
try {
conn = DriverManager.getConnection(url);
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return conn;
}
public void insert(String name,Date date_added, String path, Time duration){
String sql= " INSERT INTO SAMPLE_SOUND(name,date_added,path,duration) VALUES(?,?,?,?)";
try(Connection conn = this.connect();
PreparedStatement pstmt = conn.prepareStatement(sql)){
pstmt.setString(1,name);
pstmt.setDate(2, date_added);
pstmt.setString(3,path);
pstmt.setTime(4, duration);
pstmt.executeUpdate();
} catch (SQLException e){
System.out.println(e.getMessage());
}
}
public static void main(String[] args) {
SAMPLE_SOUND app = new SAMPLE_SOUND();
app.insert("name", "date_added","path", "duration");
}
}
it wants me to convert them into String with an error
No, not at all. It signals that you're trying to pass strings as arguments, elthough the method expects a Date and a Time. The correct fix is of course to pass a Date and a Time. But IntelliJ doesn't know that, and it suggests that maybe you actually do want to pass Strings, and the arguments types should then be changed to String.
Remember, you are the smart developer. It's up to you to decide what to do.
Please respect the Java naming conventions.

ConcurrentHashMap remove issue

I have a class like this
import java.util.concurrent.*;
public class TestClass<V> {
private final ConcurrentMap<String, Future<V>> requests;
private final ExecutorService executorService;
public TestClass(final ExecutorService executorService) {
this.executorService = executorService;
this.requests = new ConcurrentHashMap<>();
}
public V submitRequest(String cacheKey, Callable<V> request) throws Exception {
final Future<V> task = getOrCreateTask(cacheKey, request);
final V results;
try {
results = task.get();
} catch (InterruptedException | ExecutionException e) {
throw new IllegalStateException(String.format("Exception while executing request for key '%s'", cacheKey),
e);
} finally {
//Nullpointer here
requests.remove(cacheKey);
}
return results;
}
private synchronized Future<V> getOrCreateTask(String key, Callable<V> request) {
if (requests.containsKey(key)) {
return requests.get(key);
} else {
final Future<V> newTask = executorService.submit(request);
requests.put(key, newTask);
return newTask;
}
}
}
but sometimes under heavy load server throws nullpointer on requests.remove(cacheKey). I have read final when not escaped by this in the constructor is write guaranteed. i.e. other threads can see what is going on with my requests map.
Not sure how do i fix efficiently? Does not like that idea of adding synchronised on the whole parent level method
I'm not actually sure the NPE is where you're identifying it is unless cacheKey is null, which you could check for. The concurrentmap is set correctly so the requests field should never be null. Nevertheless, this code is not correctly synchronized. You are attempting to perform two operations in getOrCreateTask() that while under the synchronized keyword are not correctly synchronized with the map because the map is interacted with in submitRequest when you remove the values.
What is likely happening is that between the check ConcurrentMap#containsKey and ConcurrentMap#get that another thread has removed the value from the cache (ConcurrentMap#remove).
Thread A: Check Contains "foobar" => true
Thread B: Remove "foobar"
Thread A: Call get("foobar") => null
Thread A: Calls Future#get on a null pointer, which then throws a NPE.
Since you control the concurrentmap you can know you'll never have null values. In that case you should instead just call the #get method and check if the returned value is null. This will prevent another thread from removing the value between a contains/get pair since you'll be only accessing the map through one atomic operation.

Groovy addBatch/executeBatch with autoGenerated keys

Has anyone retrieved the auto-generated keys for a database insert while using Groovy SQL's withBatch method? I have the following code
def Sql target = ...//database connection
target.withBatch { ps ->
insertableStuff.each { ps.addBatch ( it ) }
ps.executeBatch()
def results = ps.getGeneratedKeys() //what do I do with this?
}
We're using DB2, and I've successfully tested the getGeneratedKeys method with a single statement/result set, but once I wrap the process in a batch, I'm not sure what objects I'm dealing with anymore.
According to IBM, it is possible to get the results back, but their example is using standard JDBC objects, not the groovy ones. Any ideas?
I took the Groovy SQL stuff out the picture to see if I could get something working, I wanted to make sure that DB2 for z/OS actually supported the function, and was able to get the generated values. I was using IBM's example, however I had to add some extra code to handle for the casting that the IBM example is using.
SQL target = ...//get database connection
def preparedStatement = target.connection.prepareStatement(statement, ['ISN'] as String[])
ResultSet[] resultSets = ((DB2PreparedStatement) (ps.getDelegate().getDelegate())).getDBGeneratedKeys()
resultSets.each { ResultSet results ->
while(results.next()) {
println results.getInt(1)
}
}
So... that's a little clunky, but it's functional. Unfortunately, by controlling the statement myself, I lost all of the parameter mapping that Groovy normally does for me.
I was looking through the groovy Sql source code and can see where they are explicitly telling the database connection not to handle parameters, so I'm thinking I'll add a new method to Sql.metaClass that can pass in a list of the auto-generated column names or something to make this more palatable.
I also want to see if there's a way to get the getGeneratedKeys method working so that I don't have to do all of that casting. At the very least, a utility method to safely handle the casting for me.
try {
withinBatch = true;
PreparedStatement statement = (PreparedStatement) getAbstractStatement(new CreatePreparedStatementCommand(0), connection, sql);
configure(statement);
psWrapper = new BatchingPreparedStatementWrapper(statement, indexPropList, batchSize, LOG, this);
closure.call(psWrapper);
return psWrapper.executeBatch();
} catch (SQLException e) {
The createNewPreparedStatement(0) prevents the creation of a statement which could return the auto-generated keys.
Just to make sure I wasn't crazy, I re-tried the 'getGeneratedKeys' method again with a statement that I know works and I got no results (see below). I had to recursively spin through the results to find the IBM class. So... not my favorite code, it's pretty brittle, but it's functional. Now I just need to see if I can still use the withBatch method somehow, I'll obviously need to override some things.
println 'print using getGeneratedKeys'
def results = preparedStatement.getGeneratedKeys()
while (results.next()) {
println SqlGroovyMethods.toRowResult(results)
}
println 'print using delegate processing'
println getGeneratedKeys(preparedStatement)
private List getGeneratedKeys(PreparedStatement statement) {
switch (statement) {
case DelegatingStatement:
return getGeneratedKeys(DelegatingStatement.cast(statement).getDelegate())
case DB2PreparedStatement:
ResultSet[] resultSets = DB2PreparedStatement.cast(statement).getDBGeneratedKeys()
List keys = []
resultSets.each { ResultSet results ->
while (results.next()) {
keys << SqlGroovyMethods.toRowResult(results)
}
}
return keys
default:
return [SqlGroovyMethods.toRowResult(statement.getGeneratedKeys())]
}
}
---- Console Output ----
print using getGeneratedKeys
print using delegate processing
[[KEY:7391], [KEY:7392]]
Okay, got it working. I had to hack my way into the Groovy SQL class, and there are some things that I just couldn't do because the methods in the Groovy class were private, so this implementation doesn't support cachedStatements, the isWithinBatch method won't operate correctly in the closure, and there's no access to the number of rows that were updated.
It'd be nice to see some variation of this in the base Groovy code, perhaps with a extension point where you put in your own handler (since you wouldn't want the IBM specific stuff in the base Groovy code), but at least I have a workable solution now.
public class SqlWithGeneratedKeys extends Sql {
public SqlWithGeneratedKeys(Sql parent) {
super(parent);
}
public List<GroovyRowResult> withBatch(String pSql, String [] keys, Closure closure) throws SQLException {
return this.withBatch(0, pSql, keys, closure);
}
public List<GroovyRowResult> withBatch(int batchSize, String pSql, String [] keys, Closure closure) throws SQLException {
final Connection connection = this.createConnection();
List<Tuple> indexPropList = null;
final SqlWithParams preCheck = this.buildSqlWithIndexedProps(pSql);
BatchingPreparedStatementWrapper psWrapper = null;
String sql = pSql;
if (preCheck != null) {
indexPropList = new ArrayList<Tuple>();
for (final Object next : preCheck.getParams()) {
indexPropList.add((Tuple) next);
}
sql = preCheck.getSql();
}
PreparedStatement statement = null;
try {
statement = connection.prepareStatement(sql, keys);
this.configure(statement);
psWrapper = new BatchingPreparedStatementWrapper(statement, indexPropList, batchSize, LOG, this);
closure.call(psWrapper);
psWrapper.executeBatch();
return this.getGeneratedKeys(statement);
} catch (final SQLException e) {
LOG.warning("Error during batch execution of '" + sql + "' with message: " + e.getMessage());
throw e;
} finally {
BaseDBServices.closeDBElements(connection, statement, null);
}
}
protected List<GroovyRowResult> getGeneratedKeys(Statement statement) throws SQLException {
if (statement instanceof DelegatingStatement) {
return this.getGeneratedKeys(DelegatingStatement.class.cast(statement).getDelegate());
} else if (statement instanceof DB2PreparedStatement) {
final ResultSet[] resultSets = DB2PreparedStatement.class.cast(statement).getDBGeneratedKeys();
final List<GroovyRowResult> keys = new ArrayList<GroovyRowResult>();
for (final ResultSet results : resultSets) {
while (results.next()) {
keys.add(SqlGroovyMethods.toRowResult(results));
}
}
return keys;
}
return Arrays.asList(SqlGroovyMethods.toRowResult(statement.getGeneratedKeys()));
}
}
Calling it is nice and clean.
println new SqlWithGeneratedKeys(target).withBatch(statement, ['ISN'] as String[]) { ps ->
rows.each {
ps.addBatch(it)
}
}

Silverlight - limit application to one WCF call at a time

Silverlight can only send a certain number of simultaneous WCF requests at a time. I am trying to serialize the requests that a particular section of my application is performing because I don't need them to run concurrently.
The problem is as follows (summary below):
"WCF proxies in Silverlight applications use the SynchronizationContext of the thread from which the web service call is initiated to schedule the invocation of the async event handler when the response is received. When the web service call is initiated from the UI thread of a Silverlight application, the async event handler code will also execute on the UI thread."
http://tomasz.janczuk.org/2009/08/improving-performance-of-concurrent-wcf.html
summary: basically, if you block the thread that is calling the async method, it will never get called.
I can't figure out the right model of threading this such which would give me what I want in a reasonable way.
My only other requirement is that I don't want the UI thread to block.
As far as I can see, what should work is if the UI thread has a worker thread which queues up the calls as Action delegates, then uses an AutoResetEvent to execute a task one at a time in yet another worker thread. There are two problems:
1) The thread that calls async can't block, because then async will never get called. In fact, if you put that thread into a wait loop, I've noticed it doesn't get called either
2) You need a way to signal from the completed method of the async call that it is done.
Sorry that was so long, thanks for reading. Any ideas?
I have used a class that i build on my own to execute load operations synchronous. With the class you can register multiple load operations of diffrent domaincontexts and then execute them one by one. You can provide an Action to the constructor of the class that gets called, when all operations are finished (successful or failed).
Here´s the code of the class. I think it´s not complete and you have to change it to match your expectations. Maybe it can help you in your situation.
public class DomainContextQueryLoader {
private List<LoadOperation> _failedOperations;
private Action<DomainContextQueryLoader> _completeAction;
private List<QueuedQuery> _pendingQueries = new List<QueuedQuery>();
public DomainContextQueryLoader(Action<DomainContextQueryLoader> completeAction) {
if (completeAction == null) {
throw new ArgumentNullException("completeAction", "completeAction is null.");
}
this._completeAction = completeAction;
}
/// <summary>
/// Expose the count of failed operations
/// </summary>
public int FailedOperationCount {
get {
if (_failedOperations == null) {
return 0;
}
return _failedOperations.Count;
}
}
/// <summary>
/// Expose an enumerator for all of the failed operations
/// </summary>
public IList<LoadOperation> FailedOperations {
get {
if (_failedOperations == null) {
_failedOperations = new List<LoadOperation>();
}
return _failedOperations;
}
}
public IEnumerable<QueuedQuery> QueuedQueries {
get {
return _pendingQueries;
}
}
public bool IsExecuting {
get;
private set;
}
public void EnqueueQuery<T>(DomainContext context, EntityQuery<T> query) where T : Entity {
if (IsExecuting) {
throw new InvalidOperationException("Query cannot be queued, cause execution of queries is in progress");
}
var loadBatch = new QueuedQuery() {
Callback = null,
Context = context,
Query = query,
LoadOption = LoadBehavior.KeepCurrent,
UserState = null
};
_pendingQueries.Add(loadBatch);
}
public void ExecuteQueries() {
if (IsExecuting) {
throw new InvalidOperationException("Executing of queries is in progress");
}
if (_pendingQueries.Count == 0) {
throw new InvalidOperationException("No queries are queued to execute");
}
IsExecuting = true;
var query = DequeueQuery();
ExecuteQuery(query);
}
private void ExecuteQuery(QueuedQuery query) {
System.Diagnostics.Debug.WriteLine("Load data {0}", query.Query.EntityType);
var loadOperation = query.Load();
loadOperation.Completed += new EventHandler(OnOperationCompleted);
}
private QueuedQuery DequeueQuery() {
var query = _pendingQueries[0];
_pendingQueries.RemoveAt(0);
return query;
}
private void OnOperationCompleted(object sender, EventArgs e) {
LoadOperation loadOperation = sender as LoadOperation;
loadOperation.Completed -= new EventHandler(OnOperationCompleted);
if (loadOperation.HasError) {
FailedOperations.Add(loadOperation);
}
if (_pendingQueries.Count > 0) {
var query = DequeueQuery();
ExecuteQuery(query);
}
else {
IsExecuting = false;
System.Diagnostics.Debug.WriteLine("All data loaded");
if (_completeAction != null) {
_completeAction(this);
_completeAction = null;
}
}
}
}
Update:
I´ve just noticed that you are not using WCF RIA Services, so maybe this class will not help your.
There are some options:
- You can take a look at the Agatha-rrsl either by inspecting the implementation of it or by just using it instead of pure wcf. The framework allows you to queue requests. You can read more here.
- Another option is to use the Reactive extension. There is a SO example here and more info here and here.
- You can try the Power Thread library from Jeffrey Richter. He describes it on his book CLR via C#. You can find the library here. This webcast gives you some info about it.
- You can always roll your own implementation. The yield statement is a good help here. Error handling makes it very difficult to get the solution right.

Resources