0

I'm currently learning JDBC. And I try to update the product information and insert a log at the same time.

private void testTransaction() {
        try {
            // Get Connection
            Connection connection = ConnectionUtils.getConnection();
            connection.setAutoCommit(false);

            // Execute SQL
            Product product = new Product(1, 4000d);
            productService.updateProduct(connection, product);
            Log log = new Log(true, "None");
            logService.insertLog(connection, log);

            // Commit transaction
            connection.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            ConnectionUtils.closeConnection();
        }
    }

When using single thread, it would be fine.

    @Test
    public void testMultiThread()  {
        testTransaction();
    }

But When I using multi-thread, even start one thread, the process would terminate automatically.

    @Test
    public void testMultiThread()  {
        for (int i = 0; i < 1; i++) {
            new Thread(this::testTransaction).start();
        }
    }

After debugging, I found that it was Class.forName() function in ConnectionUtils cause this situation.

public class ConnectionUtils {
    static private String url;
    static private String driver;
    static private String username;
    static private String password;

    private static Connection connection = null;

    private static ThreadLocal<Connection> t = new ThreadLocal<>();

    static {
        try {
            Properties properties = new Properties();
            properties.load(new FileReader("src/main/resources/jdbcConnection.properties"));

            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");

            Class.forName(driver);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

    public static Connection getConnection() {
        try {
            connection = DriverManager.getConnection(url, username, password);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            t.set(connection);
        }
        return connection;
    }
}

The process will terminate at Class.forName(). I found this by adding two print funcion before and after the statement. And only the former works.

System.out.println("Before");
Class.forName(driver);
System.out.println("After");

The console only print the Before and doesn't show any exception information. I want to know that why multi-thread in java will cause this situation and how to solve this problem.

sh-zh-7
  • 33
  • 4

2 Answers2

2

This is more likely your test method complete before your other threads and the test framework is not waiting (junit?). You need to wait until the threads have completed. You should use an Executors, this is more convinient.

@Test
public void testMultiThread()  {
    
    Thread[] threads = new Thread[1];
    for (int i = 0; i < threads.length; i++) {
        threads[i] = new Thread(this::testTransaction);
        threads[i].start();
    }

    // wait thread completion
    for (Thread th : threads) {
        th.join();
    }

}
Cyril G.
  • 1,879
  • 2
  • 5
  • 19
1

Junit will terminate all your thread as long as the test method finish.

In your case, test will finish when the loop ends, it doesn't care whether testTransaction has finished. It has nothing to do with class.forName , maybe it's just because this method exceute longer.

you can check this answer

haoyu wang
  • 1,241
  • 4
  • 17