java 坑死人的junit单元测试 ,多线程,连接池被关闭,线程中无法继续执行程序,报错: HikariDataSource (HikariPool-1) has been closed.

前言:调了一早上,到心态 崩溃,突然反应过来,真的是欲哭无泪呀,索性遭到了原因并解决了,大吉大利!大吉大利!

1.场景描述:

  执行方式:junit单元测试
  执行程序:

	@Test
	public void test() {
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				recordService.list();
			}
		}).start();
	}

  错误信息:Error querying database.  Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLException: HikariDataSource HikariDataSource (HikariPool-1) has been closed.

2.错误分析-数据库连接中断,无法连接数据库获取数据

3.问题原因-junit主线程执行完成之后会调用System.exit()方法,将JVM关闭,所以子线程虽然在执行,但是却获取不到数据库链接了

4.问题处理-

方式一:在junit单元测试主线程最后加上线程等待时间 Thread.sleep(10000);

方式二:多线程避免在junit中测试,使用接口测试等其他方式

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
好的,我可以回答你的问题。首先,你需要理解什么是数据库连接池。数据库连接池是一种维护数据库连接的技术,它可以在应用程序启动时创建一些连接,然后在需要连接数据库时从连接池获取一个连接,使用完后再将连接归还到连接池。这种技术可以避免频繁创建和销毁连接带来的性能损耗,提高应用程序的性能。 以下是一个简单的 Java 实现数据库连接池的代码,可以帮助你理解连接池的实现: ```java import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; public class ConnectionPool { private static final String DB_URL = "jdbc:mysql://localhost:3306/test"; private static final String USER = "root"; private static final String PASSWORD = "123456"; private static final int INIT_SIZE = 5; private static final int MAX_SIZE = 10; private List<Connection> pool; public ConnectionPool() { pool = new ArrayList<>(INIT_SIZE); for (int i = 0; i < INIT_SIZE; i++) { pool.add(createConnection()); } } private Connection createConnection() { try { return DriverManager.getConnection(DB_URL, USER, PASSWORD); } catch (SQLException e) { throw new RuntimeException("Unable to create a new connection.", e); } } public Connection getConnection() { if (pool.isEmpty()) { if (pool.size() < MAX_SIZE) { pool.add(createConnection()); } else { throw new RuntimeException("The connection pool is full."); } } Connection connection = pool.remove(0); return connection; } public void releaseConnection(Connection connection) { if (pool.size() < INIT_SIZE) { pool.add(connection); } else { try { connection.close(); } catch (SQLException e) { throw new RuntimeException("Unable to close the connection.", e); } } } } ``` 在这个实现,我们使用了一个 List 来维护连接池的连接对象。在初始化时,我们创建了一些连接,然后在需要连接数据库时从连接池获取连接,使用完后再将连接归还到连接池。当连接池没有可用的连接时,我们可以选择等待或者抛出异常。 接下来,我们可以编写一个简单的单元测试模块,并使用多线程模拟并发调用该连接池: ```java import org.junit.Test; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Random; public class ConnectionPoolTest { private ConnectionPool connectionPool = new ConnectionPool(); @Test public void test() throws InterruptedException { int threadCount = 10; Thread[] threads = new Thread[threadCount]; for (int i = 0; i < threadCount; i++) { threads[i] = new Thread(new Worker(), "Thread-" + (i + 1)); } for (Thread thread : threads) { thread.start(); } for (Thread thread : threads) { thread.join(); } } private class Worker implements Runnable { private Random random = new Random(); @Override public void run() { Connection connection = connectionPool.getConnection(); try { PreparedStatement statement = connection.prepareStatement("SELECT * FROM user WHERE id = ?"); statement.setInt(1, random.nextInt(100)); ResultSet resultSet = statement.executeQuery(); while (resultSet.next()) { System.out.println(Thread.currentThread().getName() + ": " + resultSet.getInt("id") + " " + resultSet.getString("name")); } } catch (SQLException e) { throw new RuntimeException("Unable to execute the SQL statement.", e); } finally { connectionPool.releaseConnection(connection); } } } } ``` 在这个单元测试模块,我们创建了多个线程,并在每个线程获取连接池的连接,并执行一些 SQL 查询操作。我们使用了一个随机数生成器来生成查询语句的参数,以模拟多个线程同时访问数据库的情况。 当我们运行这个单元测试模块时,我们会看到多个线程同时访问数据库,并输出查询结果。同时,我们也可以观察到连接池的状态,以确保连接池的运行状态。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浮生若梦l

你的鼓励实我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值