cari

Rumah  >  Soal Jawab  >  teks badan

java的DriverManager.getConnection为什么返回同一个connection?

我启动了十个线程去测试一个业务方法,但有时候会报出连接已经关闭,无法继续操作的异常。直接上代码了:
首先是测试代码:

public class Test {
    public static void main(String[] args){
//        ProductService productService = new ProductServiceImpl();
//        productService.updateProductPrice(1, 3000);

        for(int i=0;i<10;i++){
            ProductService productService = new ProductServiceImpl();
            MyThread myThread = new MyThread(productService);
            myThread.start();
        }
    }
}

class MyThread extends Thread{

    private ProductService productService;

    public MyThread(ProductService productService){
        this.productService = productService;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
        productService.updateProductPrice(1,3000);
    }
}

业务代码:

public class ProductServiceImpl implements ProductService{
    private static final String UPDATE_PRODUCT_SQL = "update product set price = ? where id = ?";
    private static final String INSERT_LOG_SQL = "insert into log (created, description) values (?, ?)";

    public void updateProductPrice(long productId, int price) {
        Connection conn = null;
        try {
            // 获取连接
            conn = DBUtil.getConnection();
            System.out.println(Thread.currentThread().getName()+"---->"+conn.toString());
            conn.setAutoCommit(false); // 关闭自动提交事务(开启事务)

            // 执行操作
            updateProduct(conn, UPDATE_PRODUCT_SQL, productId, price); // 更新产品
            insertLog(conn, INSERT_LOG_SQL, "Create product."); // 插入日志

            // 提交事务
            conn.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭连接
            DBUtil.closeConnection(conn);
        }
    }

    private void updateProduct(Connection conn, String updateProductSQL, long productId, int productPrice) throws Exception {
        PreparedStatement pstmt = conn.prepareStatement(updateProductSQL);
        pstmt.setInt(1, productPrice);
        pstmt.setLong(2, productId);
        int rows = pstmt.executeUpdate();
        if (rows != 0) {
            System.out.println("Update product success!");
        }
    }

    private void insertLog(Connection conn, String insertLogSQL, String logDescription) throws Exception {
        PreparedStatement pstmt = conn.prepareStatement(insertLogSQL);
        pstmt.setString(1, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()));
        pstmt.setString(2, logDescription);
        int rows = pstmt.executeUpdate();
        if (rows != 0) {
            System.out.println("Insert log success!");
        }
    }
}

数据库操作类:

public class DBUtil {
    private static final String driver = "com.mysql.jdbc.Driver";
    private static final String url = "jdbc:mysql://localhost:3306/demo";
    private static final String username = "root";
    private static final String password = "root";

    // 定义一个数据库连接
    private static Connection conn = null;

    // 获取连接
    public static Connection getConnection() {
        try {
            Class.forName(driver);
            conn = DriverManager.getConnection(url, username, password);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }

    // 关闭连接
    public static void closeConnection(Connection conn) {
        try {
            if (conn != null) {
                conn.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}

其中一次得到的运行结果:

PHP中文网PHP中文网2767 hari yang lalu820

membalas semua(3)saya akan balas

  • 伊谢尔伦

    伊谢尔伦2017-04-18 10:30:56

    Masalahnya terletak pada baris kod ini dalam DBUtil:

    private static Connection conn = null;

    Pembolehubah sambung ialah pembolehubah statik global dan dikongsi oleh semua urutan.

    Kes yang melampau:
    Apabila thread A dijalankan ke conn = DriverManager.getConnection(...), conn ialah pangkalan data sambungan;
    Thread B laksanakan ke conn = DriverManager.getConnection(...) Apabila conn ditugaskan semula sebagai sambungan pangkalan data

    Pada masa ini, memandangkan conn dikongsi oleh semua thread, nilai conn untuk thread A dan thread B ialah sambungan pangkalan data b. Ini menyebabkan semua utas berkongsi sambungan pangkalan data b Apabila satu utas menutup sambungan, utas lain akan membuang pengecualian.

    Selain itu, kerana sambungan pangkalan data b dikongsi pada penghujungnya, pangkalan data sambungan tidak boleh ditutup, menyebabkan kebocoran memori.

    balas
    0
  • 巴扎黑

    巴扎黑2017-04-18 10:30:56

    Perlu dikatakan bahawa tiada jaminan bahawa sambungan yang berbeza akan dikembalikan setiap kali
    Lagipun, anda menulisnya sebagai pembolehubah ahli

    balas
    0
  • 天蓬老师

    天蓬老师2017-04-18 10:30:56

    Untuk menggunakan Pool, mulakan berbilang dan tetapkan satu pada setiap sambungan.

    public class ConnectionPool {  
          
        private Vector<Connection> pool;  
        private int poolSize = 100;  
        private static ConnectionPool instance = null;  
        Connection conn = null;  
    
        private ConnectionPool() {  
            pool = new Vector<Connection>(poolSize);  
      
            for (int i = 0; i < poolSize; i++) {  
                try {  
                    Class.forName(driverClassName);  
                    conn = DriverManager.getConnection(url, username, password);  
                    pool.add(conn);  
                } catch (ClassNotFoundException e) {  
                    e.printStackTrace();  
                } catch (SQLException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
      
        /* 返回连接到连接池 */  
        public synchronized void release() {  
            pool.add(conn);  
        }  
      
        /* 返回连接池中的一个数据库连接 */  
        public synchronized Connection getConnection() {  
            if (pool.size() > 0) {  
                Connection conn = pool.get(0);  
                pool.remove(conn);  
                return conn;  
            } else {  
                return null;  
            }  
        }  
    }  

    balas
    0
  • Batalbalas