场景:一个Test类中有两个或以上的处理数据库DML语句
原因:出现这种异常的原因是,正规的mysql 操作DML语句都是执行Connection取到数据后,就执行JDBCUtils.close(con, pst, rs) ,而test自动化单元测试(mvn clean test || mvn test)时,会在一个单元测试类中执行多次DML语句。当第一次释放资源后,第二次再去连接数据库就会出现这样的异常报错。【注:一个类只有一个DML语句操作的test时请绕过】
package com.kmt.bkm.server.Utils.sql;
import java.sql.*;
/*
* 实现JDBC的工具类
* 定义方法,直接返回数据库的连接对象
*
* 写关闭方法
*/
public class JDBCUtils {
private static Connection con;
static {
try{ //useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=CTT&autoReconnect=true
String url = "jdbc:mysql:localhost/库Name?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT&autoReconnect=true";
String username = "root";
String password = "root";
//根据版本去使用对应的数据库驱动
// Class.forName("com.mysql.jdbc.Driver"); //6.0版本以前
Class.forName("com.mysql.cj.jdbc.Driver"); //6.0版本以后
con = DriverManager.getConnection(url, username, password);
} catch (Exception ex) {
throw new RuntimeException(ex + "数据库连接失败");
}
}
/*
* 返回数据库的连接对象
*/
public static Connection getConnection() {
return con;
}
public static void close(Connection con, Statement stat) {
if (stat != null) {
try {
stat.close();
} catch (SQLException ex) {
}
}
if (con != null) {
try {
con.close();
} catch (SQLException ex) {
}
}
}
public static void close(Connection con, Statement stat, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException ex) {
}
}
if (stat != null) {
try {
stat.close();
} catch (SQLException ex) {
}
}
if (con != null) {
try {
con.close();
} catch (SQLException ex) {
}
}
}
/**
* 获取MySql的版本
* @return
* @throws SQLException
*/
public static Integer sqlVersion() throws SQLException {
DatabaseMetaData metaData = (DatabaseMetaData) con.getMetaData();
String version = metaData.getDatabaseProductVersion(); //得到数据库版本信息
Integer ver = Integer.valueOf(version.substring(0 ,1));
return ver;
}
public static void main(String str[]) throws SQLException {
DatabaseMetaData metaData = (DatabaseMetaData) con.getMetaData();
String version = metaData.getDatabaseProductVersion(); //得到数据库版本信息
System.out.println("-----> " + version.substring(0 ,1));
}
}
一般流程:
/**
* 获取数据库中的商家id
* @param limit 需要查几条
* @return
* @throws SQLException
*/
public ArrayList<Long> getCustomerIdByDB(int limit) throws SQLException {
ArrayList<Long> customerList = new ArrayList<>();
String sql = "SELECT * FROM cct_customer ORDER BY id ASC LIMIT " + limit + ";";
//获取数据库连接对象
Connection con = JDBCUtils.getConnection();
//获取sql语句执行者对象
PreparedStatement pst = (PreparedStatement) con.prepareStatement(sql);
//调用查询方法获得结果集
ResultSet rs = pst.executeQuery();
//所需取值Object定义
Long sid;
while (rs.next()) {
//获取每个列的数据,封装到Product对象中
sid = rs.getLong("id");
//把封装好的Product对象存储到list中
customerList.add(sid);
}
//查询完成释放资源
JDBCUtils.close(con , pst , rs);
if (null != customerList && customerList.size() > 0)
return customerList;
else
return null;
}
解决方法:建立常链接(优缺点我不太清楚,只是单纯的解决异常),把Connection ,PreparedStatement,ResultSet定义为全局变量,如下所示
public class Test{
//获取数据库连接对象
static Connection con;
PreparedStatement pst;
ResultSet rs;
static {
//Connection实例化方式一
con = JDBCUtils.getConnection();
}
@Before
public void before(){
//Connection实例化方式二
con = JDBCUtils.getConnection();
}
@After
public void after(){
JDBCUtils.close(con, pst, rs);
}
@Test
public void testDemo1(){
//DML处理1
//todo
}
@Test
public void testDemo2(){
//DML处理2
//todo
}
}
好了,就是这么处理的,如果处理方法有问题,欢迎大佬留言其他处理方法或者优缺点的理论
文章参考:https://www.cqmaple.com/201308/no-operations-allowed-after-connection-closed.html