JDBC批量操作数据

import java.text.SimpleDateFormat;
import java.util.Date;

public static void addDate() {
    // 获取数据库连接
    Connection conn = DBUtil.getConnection();
    // 创建preparedstatement
    PreparedStatement pmst = null;
    // 创建resultSet【在这里他没啥用的增删改不需要它】
    ResultSet re = null;
    try {
        // 设置手动提交数据
        conn.setAutoCommit(false);
        String sql = "insert into classinfo(cid,cname) values(?,?)";
        pmst = conn.prepareStatement(sql);
        for (int i = 1; i < 1000000; i++) {
            pmst.setString(1, i + "");
            pmst.setString(2, "wangwang");
            pmst.addBatch();
        }
        // 返回一个int数组
        int[] count = pmst.executeBatch();
        if (count.length > 0) {
            System.out.println("批量操作了" + count.length + "条数据。。。。。。。。。");
        }
        conn.commit();// 提交数据
    } catch (Exception e) {

        e.printStackTrace();
        try {
            // 操作失败回滚数据
            conn.rollback();
        } catch (Exception e2) {
            e2.printStackTrace();
        }
    } finally {
        // 这个是用来关闭connection preparstatement resultset 方法自己写去
        DBUtil.closeConnection(conn, pmst, re);
    }

}



    public String saveDeviceItem(List<String> list) {
        // TODO Auto-generated method stub
        //通过循环将list中的SQL语句放到同一个事务中提交
        
        Connection conn=ConnectionFactory.GetConnection();
        Statement    st=null;
        try {
            conn.setAutoCommit(false);
            st=conn.createStatement();
            if(list!=null && list.size()>0){
                for(int i=0;i<list.size();i++){
                    if(list.get(i)!=null){
                        st.addBatch(list.get(i));
                    }
                }
            }
            int count[]=st.executeBatch();
            conn.commit();
            if(count.length>0){
                return "SUCCESS";
            }
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                conn.rollback();
            } catch (SQLException e2) {
                e2.printStackTrace();
            }
            
        }finally{
            
            try {
                st.close();    
            } catch (SQLException e2) {
                e2.printStackTrace();
            }
            ConnectionFactory.close(conn);
        }
        
        return "ERRORNUM005";
    }


<think>在Java中使用JDBC批量插入数据可以提高数据库插入操作的效率,尤其是当需要插入大量数据时。批量插入可以减少与数据库的交互次数,从而显著减少网络传输开销和数据库处理时间。 ### 实现步骤: 1. 加载数据库驱动(对于JDBC 4.0及以上,通常可以自动加载)。 2. 建立数据库连接。 3. 创建PreparedStatement对象,使用参数化SQL语句。 4. 关闭自动提交(以便手动控制事务)。 5. 循环设置参数,并添加到批处理中。 6. 执行批处理。 7. 提交事务(如果之前关闭了自动提交)。 8. 处理异常,必要时回滚事务。 9. 关闭资源。 ### 示例代码: 以下是一个使用JDBC批量插入数据的示例代码: ```java import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class BatchInsertExample { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/testdb"; String user = "username"; String password = "password"; Connection conn = null; PreparedStatement pstmt = null; try { // 1. 建立连接 conn = DriverManager.getConnection(url, user, password); // 2. 设置手动提交事务 conn.setAutoCommit(false); String sql = "INSERT INTO users (name, email) VALUES (?, ?)"; pstmt = conn.prepareStatement(sql); // 3. 批量插入数据 for (int i = 1; i <= 1000; i++) { pstmt.setString(1, "User" + i); pstmt.setString(2, "user" + i + "@example.com"); pstmt.addBatch(); // 添加到批处理 // 每100条执行一次批处理,避免内存溢出 if (i % 100 == 0) { pstmt.executeBatch(); conn.commit(); // 提交事务 } } // 执行剩余的批处理 pstmt.executeBatch(); conn.commit(); // 提交事务 System.out.println("批量插入完成!"); } catch (SQLException e) { e.printStackTrace(); try { if (conn != null) { conn.rollback(); // 回滚事务 } } catch (SQLException ex) { ex.printStackTrace(); } } finally { // 4. 关闭资源 try { if (pstmt != null) pstmt.close(); if (conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } ``` ### 关键点解释: 1. **关闭自动提交**:通过`conn.setAutoCommit(false)`关闭自动提交,这样可以将多个插入操作作为一个事务处理,要么全部成功,要么全部失败(通过回滚)。 2. **批处理添加**:使用`addBatch()`方法将参数化的预编译语句添加到批处理中。 3. **分批执行**:在循环中,每100条记录执行一次批处理并提交,这样可以避免一次性添加太多数据导致内存溢出。 4. **事务提交**:在批处理执行后,需要手动提交事务(`conn.commit()`)。 5. **异常处理**:在catch块中打印异常,并回滚事务。在finally块中关闭资源,确保资源释放。 ### 注意事项: - **批处理大小**:根据实际情况调整批处理的大小(如每100条、500条等),以平衡内存使用和性能。 - **事务管理**:批量插入通常在一个事务中完成,如果插入的数据量非常大,可能需要考虑分多个事务提交,以避免长事务和锁表问题。 - **数据库驱动**:不同的数据库(如MySQL、Oracle、PostgreSQL等)对批处理的支持可能有所不同,需要确保使用的驱动支持批处理操作。 - **内存管理**:如果一次性添加太多数据到批处理中,可能会导致内存溢出(OutOfMemoryError),因此建议分批次执行。 ### 相关问题: §§相关问题§§: 1. 在JDBC中,如何设置事务的隔离级别? 2. 使用PreparedStatement和Statement在批处理中有什么区别? 3. 如何处理JDBC批处理过程中的异常? 4. 在批量插入时,如何获取自动生成的主键?</think>### Java使用JDBC批量插入数据Java中,使用JDBC批量插入数据可以显著提高数据操作效率,特别是当需要插入大量数据时。以下是完整的实现方法和代码示例: #### 方法实现 ```java import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class BatchInsertExample { // 数据库连接信息 private static final String URL = "jdbc:mysql://localhost:3306/testdb"; private static final String USER = "username"; private static final String PASSWORD = "password"; public static void main(String[] args) { try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD)) { // 1. 关闭自动提交(关键步骤!) conn.setAutoCommit(false); // 2. 准备SQL语句(使用占位符) String sql = "INSERT INTO employees (name, email, department) VALUES (?, ?, ?)"; try (PreparedStatement pstmt = conn.prepareStatement(sql)) { // 3. 批量设置参数 for (int i = 1; i <= 1000; i++) { pstmt.setString(1, "Employee_" + i); // name pstmt.setString(2, "emp" + i + "@company.com"); // email pstmt.setString(3, "Dept_" + (i % 5)); // department pstmt.addBatch(); // 添加到批处理 // 4. 分段执行(每100条执行一次) if (i % 100 == 0) { pstmt.executeBatch(); conn.commit(); // 提交事务 } } // 5. 执行剩余批处理 int[] updateCounts = pstmt.executeBatch(); conn.commit(); // 最终提交 System.out.println("批量插入完成,影响行数: " + updateCounts.length); } } catch (SQLException e) { e.printStackTrace(); // 实际应用中应添加事务回滚逻辑 } } } ``` #### 关键优化点 1. **事务管理**: - `conn.setAutoCommit(false)`:禁用自动提交(核心优化) - 手动分批提交事务(`conn.commit()`),避免单条提交的开销 2. **批处理机制**: - `addBatch()`:将参数化语句加入批处理队列 - `executeBatch()`:一次性发送整批SQL数据库 - 返回`int[]`数组表示每条SQL影响的行数 3. **分段执行**: - 每100条执行一次,避免内存溢出(OOM) - 根据数据库配置调整批次大小(通常500-2000条/批) #### 性能对比 | 插入方式 | 10,000条耗时 | 资源消耗 | |----------------|--------------|----------| | 单条插入 | 15-20秒 | 高 | | 批量插入 | 0.5-2秒 | 低 | | 带事务的批量 | 0.3-1秒 | 最低 | #### 常见问题原因 1. **内存溢出(OutOfMemoryError)**: - 原因:一次性添加过多批处理未及时执行 - 解决:分批执行(如每500条执行一次) 2. **事务超时**: - 原因:单批次数据量过大,执行时间超过数据库等待超时 - 解决:减小批次大小或增加`wait_timeout` 3. **主键冲突**: - 原因:批量操作中部分数据违反唯一约束 - 解决:使用`try-catch`捕获`BatchUpdateException`,通过`getUpdateCounts()`定位失败行 4. **连接泄漏**: - 原因:未正确关闭`PreparedStatement`和`Connection` - 解决:使用try-with-resources语法(Java 7+) #### 高级技巧 ```java // 1. 获取自动生成的主键(需在SQL中指定) PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); // 2. 批处理异常处理 try { pstmt.executeBatch(); } catch (BatchUpdateException e) { int[] successCounts = e.getUpdateCounts(); // 获取成功执行的计数 // 处理部分失败的情况 } // 3. 使用重写BatchedStatements(MySQL优化) // 在JDBC URL后添加参数:jdbc:mysql://...?rewriteBatchedStatements=true ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值