赞
踩
场景:一个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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。