My colleague told me that in high concurrency mysql could not process update correctly, e.g.
update product set count = count - 1 where id = ? and count > 0;
maybe have count less than 0, I think he is wrong, so I wrote below code to prove this.
int nThreads = 140; //less than max_connections 151
ExecutorService pool = Executors.newFixedThreadPool(nThreads);
CountDownLatch startLatch = new CountDownLatch(nThreads);
CountDownLatch endLatch = new CountDownLatch(nThreads);
for (int i = 0; i < nThreads; i++) {
pool.submit(() -> {
startLatch.countDown();
try { startLatch.await(); } catch (Exception e1) { } //waiting for all task is submitted to guarantee concurrency
String sql = "update t set count = count-1 where id =1 and count>0";
try {
Connection connection = DriverManager.getConnection(url, user, password);
Statement stat = connection.createStatement();
stat.execute(sql);
endLatch.countDown();
} catch (Exception e) {
e.printStackTrace();
}
});
}
endLatch.await(); //waiting for all task is done
System.out.println("done");
System.exit(0);
I'd like to know my above code is could mock high concurrency correctly? and if could simplify above code by java8?
It is not right that mysql can't update data correctly.
MySql lock the record for the update until the transaction is terminated, so no other thread can try to update it if the previous transaction on the same record has not been finished.
Related
I wrote a simple java program to use JDBC to run 20 queries to fetch data from a view
int connectionSize = 10;
ds.init(connectionSize, settings);
ExecutorService executor = Executors.newFixedThreadPool(10);
try {
stopwatch.start();
for (int i = 0; i < 20; i++) {
executor.execute(new Runnable() {
#Override
public void run() {
String sql = String.format("select * from viewA where userId in (%s)", randomUserIds(5));
PreparedStatement ps = null;
Connection conn = null;
try {
while ((conn = ds.getConnection()) == null) {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
}
}
logger.info("conn: " + conn.toString());
ps = conn.prepareStatement(sql);
ps.executeQuery();
ps.close();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (conn != null) {
ds.returnConnection(conn);
}
}
}
});
}
executor.shutdown();
boolean finished = executor.awaitTermination(10, TimeUnit.MINUTES);
stopwatch.stop();
logger.log(Level.INFO, "Query Complete in " + stopwatch);
} catch (Exception ex) {
ex.printStackTrace();
}
e.g. select * from ViewA where userId in (random few user Ids)
I used a single connection, and inside a for loop executed the 20 queries in a sequential way
I set up 10 connections in a pool and running the 20 queries in 10 threads
I expected the second approach would use less time to finish the 20 queries, but after testing, the results show me these two approaches return similar time consumption.
I can confirm when I was running the second approach, it created 10 sessions in db.
Is the second approach supposed to give a better performance than the first one? What would be the problem to make the second performance same as the first one?
Hello everyone once again i would like to get some suggestions about my code efficiency
Thread thread= new Thread (new Runnable(){
public void run(){
while(true){
PreparedStatement ps = null;
ResultSet rs = null;
try {
Connection con = DatabaseConnection.getConnection();
ps = con.prepareStatement("SELECT Datacolum FROM accounts WHERE id = ? ");
ps.setInt(1, 2);
rs = ps.executeQuery();
if(rs.next()) { //there is a row
LConnection = rs.getInt("Datacolum");
}
ps.close();
} catch (SQLException ex) {}
for (int i = 0; i < 10; i++) { //Timer To Recheck Connection database 10 seconds
try{
Thread.sleep(1000);
}catch(InterruptedException ex){}}
if (LConnection !=1) {
user.Kick(5, "8", 5);
thread.stop();
}}}});
i would really like to know if such Thread will not hurt the rest of the code outside it while this code is looping every 10 seconds, maybe if there is a more efficient Timer Code i would be more then grateful to know. i want this thread to work as long as the user is connected to my application
the code does the next operation starting Looping thread>>it checks a colum>> wait 10 seconds >>enter if operator>>if not met >>Repeat Code
Open for suggestions
Sincerely yours,
Ex
I'm having an issue where my transaction doesn't truly seem to be starting unless I issue a command that appears to be transaction worthy (the last part is conjecture).
Below I have a method decorated with the #Transaction attribute, it's public, it's being called via the spring proxy. I'm connecting to SQL Server, using Microsoft's JDBC driver version 4.2. And getting an app lock, if I try and get the app lock before doing something that's transaction worth the transaction doesn't appear to start. I'm guessing this based on the returned error code (-999) which is consistent with not being in a transaction.
This code works perfectly fine in my other project, but there we are doing more than just grabbing an app lock.
Here's the method (Ignore the fact that this would just lose the app lock right after fetching it)
#Transactional
public Boolean getAppLock(String lockString, Integer timeoutMilliseconds) {
try {
Session session = entityManager.unwrap(Session.class);
int result = session.doReturningWork(connection -> {
int execResult = -1;
// Works if I add this line
// connection.prepareStatement("insert into foo (baz) values('bar')").execute();
// This line works also, which is stupid, cause it doesn't even update anything
// connection.prepareStatement("update foo set baz = baz where id = 1231241").execute();
try (PreparedStatement statement = connection.prepareStatement("declare #i int; exec #i = sp_getapplock ?,?,?,?; select #i;")) {
statement.setString(1, lockString);
statement.setString(2, "Exclusive");
statement.setString(3, "Transaction");
Integer timeout = timeoutMilliseconds == null ? 0 : timeoutMilliseconds;
statement.setInt(4, timeout);
try (ResultSet resultSet = statement.executeQuery()) {
resultSet.next();
// Complains about not being in a transaction, unless
// I have a random statement that seems transaction worthy
execResult = resultSet.getInt(1);
} catch (Exception ex) {
logger.error("Failed getting the result set from the app lock", ex);
}
} catch (Exception ex) {
logger.error("Error executing statement sp_getapplock", ex);
}
return execResult;
});
// see return codes here (https://msdn.microsoft.com/en-us/library/ms189823.aspx), 0+ is good, < 0 is bad
return result >= 0;
}
catch (Exception ex){
throw new RuntimeException(ex.getMessage());
}
}
I'm not sure if this is a driver or a spring thing, I'm leaning toward driver thing.
I am currently creating an application that executes updates on a MySQL database.
I have the following code here:
public int execute(String script, Object... values) throws Exception
{
Connection con = datasource.getConnection();
PreparedStatement statement = null;
int num = 0;
try{
try{
statement = getConnection().prepareStatement(script);
for (int i = 1; i <= values.length; i++)
{
statement.setObject(i, values[i - 1]);
}
num = statement.executeUpdate();
}finally{
if(statement != null) statement.close();
}
}finally{
if(con != null) con.close();
}
return num;
}
After looking at the process list for the database, it is clear the connection is not being closed until the entire data source is closed.
Why isn't the connection being closed?
I'm not entirely sure how your code is structured, but I suspect the issue is you are calling getConnection().prepareStatement(script).
You are getting a connection and assigning it to con, and closing it at the end. However, the statement returned from getConnection()'s Connection is causing that connection to stay open.
You should be calling con.prepareStatement(script)
You are not catching exceptions or handling errors. You should be using Java 7's try-with-resources:
e.g.
public int execute(String script, Object... values) throws Exception {
try (Connection con = datasource.getConnection();
PreparedStatement statment = con.prepareStatement(script)) {
for (int i = 1; i <= values.length; i++)
{
statement.setObject(i, values[i - 1]);
}
return statement.executeUpdate();
} catch (SQLException ex) {
// handleException
}
}
This will ensure errors are handled and all resources are correctly closed.
Because it's "borrowed" from pool and "returned" into a pool.
Basically, connection pools create well... "pool" of connection's. They spawn multiple connections upon intitialization and increase their number if required and decrease if idle. So when you call close for your current connection, you just release it into a pool while connection itself still remains "alive". All connections are being destroyed if connection pool is being destroyed. Why connection pooling? Because creation of connection upon each request is too expensive.
Here's a good article about connection pooling.
I have written following code. i want when control becomes 1 the infinite loop should stop. Otherwise it keeps on updating the SQL database after regular period of time. Some kind of exception is causing it to the thread to terminate. I am not able to figure it out. Can anybody help with it.
public void run()
{
while(true)
{
System.out.println("I am working t asfbjakhbfjabf");
synchronized(lock)
{
if(control==1)
{
return;
}
}
try
{
Thread.sleep(wTIME);
Class.forName(driver).newInstance();
conn = DriverManager.getConnection(url+dbName,userName,password);
String st="SELECT count FROM ThreadResults WHERE ThreadNo = "
+t;
Statement stmt = conn.createStatement();
stmt.execute(st);
ResultSet resultSet = stmt.getResultSet();
boolean b=resultSet.next();
synchronized(WebCrawler.seed.lock6)
{
float t1=(System.currentTimeMillis()-time)/60000;
if(b)
{
String s2="UPDATE ThreadResults SET count = "+WebCrawler.seed.count+", time = "+t1+" WHERE ThreadNo = "+t;
System.out.println("updated count");
stmt.executeUpdate(s2);
}
else
{
String s1="INSERT ThreadResults VALUES("+t+" ,"+WebCrawler.seed.count+" ,"+t1+")";
System.out.println("inserting count");
stmt.executeUpdate(s1);
}
}
resultSet.close();
conn.close();
}
catch(InterruptedException | ClassNotFoundException | InstantiationException | IllegalAccessException | SQLException c)
{
System.out.println("caught in thread resilt updation "+ c.getMessage());
}
}
}
Although this is not a preferred way to schedule a repeated task, you can fix it by catching Throwable instead of your explicit list of exceptions. That way you will make sure you catch anything that can theoretically be thrown. Be sure to print the whole exception stacktrace, not just the message.
When you fix the catching, you will need to additionally fix the cleanup logic: put the close statements into a finally. Better yet, rewrite your code to use Automatic Resource Management. The syntax is try (Statement stmt = conn.createStatement()) { ... }.
The proper way to schedule a repeated task is by using the Executors:
final ScheduledExecutorService sched = Executors.newSingleThreadScheduledExecutor();
sched.scheduleWithFixedDelay(task, 0, wTIME, TimeUnit.MILLISECONDS);
You can write
catch(Exception e)
instead of what you wrote. It will catch all exceptions.