jdbc插入大量数据时优化处理:转载https://www.jianshu.com/p/b455d5d7d659

博客介绍了JDBC使用MySQL处理大数据时的优化方法。普通执行每条数据都访问一次数据库,而批处理累积一定数量再提交,可减少交互、提高效率。还介绍了事务概念,默认关闭。通过代码展示了PreparedStatement批处理、启用事务处理及二者混合使用,结果显示二者结合处理大批量数据最快。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JDBC使用MySQL处理大数据的时候,自然而然的想到要使用批处理,
普通的执行过程是:每处理一条数据,就访问一次数据库;
而批处理是:累积到一定数量,再一次性提交到数据库,减少了与数据库的交互次数,所以效率会大大提高;
至于事务:事务指逻辑上的一组操作,组成这组操作的各个单元,要不全部成功,要不全部不成功,默认是关闭事务的。

1. PreparedStatement使用批处理 executeBatch()

1.1. 不使用executeBatch(),而使用executeUpdate()

代码如下:

Class.forName("com.mysql.jdbc.Driver");
         Connection conn = DriverManager.getConnection(dbUrl, user, password);
         PreparedStatement pstmt = conn.prepareStatement("update content set introtext=? where id=?");

         for(int i=0; i<10000; i++){
             pstmt.setString(1, "abc"+i);
             pstmt.setInt(2, id);
             pstmt.executeUpdate();
         }

这样,更新10000条数据,就得访问数据库10000次.

1.2. 使用executeBatch()

代码如下:

Class.forName("com.mysql.jdbc.Driver");
         Connection conn = DriverManager.getConnection(dbUrl, user, password);
         PreparedStatement pstmt = conn.prepareStatement("update content set introtext=? where id=?");

         for(int i=0; i<10000; i++){
             pstmt.setString(1, "abc"+i);
             pstmt.setInt(2, id);
             pstmt.addBatch();//添加到同一个批处理中
         }

         pstmt.executeBatch();//执行批处理

注意:

  1. 如果使用了 addBatch() -> executeBatch() 还是很慢,那就得使用到这个参数了

                  rewriteBatchedStatements=true (启动批处理操作)
    
                  在数据库连接URL后面加上这个参数:      
    
                      String dbUrl =  "jdbc:mysql://localhost:3306/User? rewriteBatchedStatements=true";
    
  2. 在代码中,pstmt的位置不能乱放,

                      //必须放在循环体外
    
                 pstmt = conn.prepareStatement("update content set introtext=? where id=?");
    
                 for(int i=0; i<10000; i++){
    
                       //放这里,批处理会执行不了,因为每次循环重新生成了pstmt,不是同一个了
    
                       //pstmt = conn.prepareStatement("update content set introtext=? where id=?");
                       pstmt.setString(1, "abc"+i);
                       pstmt.setInt(2, id);
                       pstmt.addBatch();//添加到同一个批处理中
                 }
    
                 pstmt.executeBatch();//执行批处理
    

2 启用事务处理

Class.forName("com.mysql.jdbc.Driver");

 

          Connection conn = DriverManager.getConnection(dbUrl, user, password);

          conn.setAutoCommit(false);//将自动提交关闭
          PreparedStatement pstmt = conn.prepareStatement("update content set introtext=? where id=?");
          for(int i=0; i<10000; i++){
             pstmt.setString(1, "abc"+i);
             pstmt.setInt(2, id);
             pstmt.executeUpdate();
         }     
          pstmt.close();
          conn.commit();//执行完后,手动提交事务
          conn.setAutoCommit(true);//在把自动提交打开
          conn.close();

3. 事务和批处理混合使用

Class.forName("com.mysql.jdbc.Driver");

          Connection conn = DriverManager.getConnection(dbUrl, user, password);

          conn.setAutoCommit(false);//将自动提交关闭
          PreparedStatement pstmt = conn.prepareStatement("update content set introtext=? where id=?");

          for(int i=0; i<1000000; i++){
               pstmt.setString(1, tempintrotext);
               pstmt.setInt(2, id);
               pstmt.addBatch();

               //每500条执行一次,避免内存不够的情况,可参考,[Eclipse设置JVM的内存参数](http://www.cnblogs.com/tommy-huang/p/4535116.html)

               if(i>0 && i%500==0){
                    pstmt.executeBatch();

                    //如果不想出错后,完全没保留数据,则可以没执行一次提交一次,但得保证数据不会重复

                    conn.commit();

                }

         }
          pstmt.executeBatch();//执行最后剩下不够500条的
          pstmt.close();

          conn.commit();//执行完后,手动提交事务
          conn.setAutoCommit(true);//在把自动提交打开
          conn.close();

较完整的代码:

 1  public class ExecuteBatchTest {
 2     private Connection conn;
 3     private PreparedStatement pstmt;
 4     private PreparedStatement pstmt2;
 5     private ResultSet rs;
 6     private String user = "root";
 7     private String password = "123456";
 8     private String dbUrl = "jdbc:mysql://localhost:3306/user?rewriteBatchedStatements=true";
 9     private int limitNum = 10000;
10 
11     public void changeData() {
12         try {
13             Class.forName("com.mysql.jdbc.Driver");
14             conn = DriverManager.getConnection(dbUrl, user, password);
15             
16             //既不用batch,也不用事务
17             testBatch(false,false);
18             //只用batch, 不用事务
19             testBatch(false,true);
20             //只用事务,不用batch
21             testBatch(true,false);
22             //不仅用事务,还用batch
23             testBatch(true,true);
24             
25             pstmt.close();
26             conn.close();
27         } catch (ClassNotFoundException e) {
28             e.printStackTrace();
29         } catch (SQLException e) {
30             e.printStackTrace();
31         }
32     }
33     
34     public void testBatch(Boolean openTransaction, Boolean useBatch) throws SQLException{
35         if(openTransaction)
36             conn.setAutoCommit(false);
37         
38         if(pstmt!=null){
39             pstmt.clearParameters();
40             pstmt.clearBatch();
41         }
42         
43         pstmt = conn.prepareStatement("insert into person (name) values (?)");
44         long start = System.currentTimeMillis();
45         for(int a = 0;a<limitNum;a++){
46             String name = "tommy"+a;
47             pstmt.setString(1, name);
48             if(useBatch)
49                 pstmt.addBatch();
50             else
51                 pstmt.executeUpdate();
52         }
53         
54         if(useBatch)
55            pstmt.executeBatch();
56          
57         if(openTransaction){
58             conn.commit();
59             conn.setAutoCommit(true);
60         }
61         long end = System.currentTimeMillis();
62         System.out.println("use time:"+(end-start)+" ms");
63         
64     }
65     
66     //main method
67     publi static void main(String[] args){
68         ExecuteBatchTest ebt = new ExecuteBatchTest();
69         ebt.changeData();
70     }
71        
72 }

运行结果:

 

image.png


分别是:
不用批处理,不用事务;
只用批处理,不用事务;
只用事务,不用批处理;
既用事务,也用批处理;(很明显,这个最快,所以建议在处理大批量的数据时,同时使用批处理和事务)

作者:zjk_00
链接:https://www.jianshu.com/p/b455d5d7d659
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

一、综合实战—使用极轴追踪方式绘制信号灯 实战目标:利用对象捕捉追踪和极轴追踪功能创建信号灯图形 技术要点:结合两种追踪方式实现精确绘图,适用于工程制图中需要精确定位的场景 1. 切换至AutoCAD 操作步骤: 启动AutoCAD 2016软件 打开随书光盘中的素材文件 确认工作空间为"草图与注释"模式 2. 绘图设置 1)草图设置对话框 打开方式:通过"工具→绘图设置"菜单命令 功能定位:该对话框包含捕捉、追踪等核心绘图辅助功能设置 2)对象捕捉设置 关键配置: 启用对象捕捉(F3快捷键) 启用对象捕捉追踪(F11快捷键) 勾选端点、中心、圆心、象限点等常用捕捉模式 追踪原理:命令执行悬停光标可显示追踪矢量,再次悬停可停止追踪 3)极轴追踪设置 参数设置: 启用极轴追踪功能 设置角度增量为45度 确认后退出对话框 3. 绘制信号灯 1)绘制圆形 执行命令:"绘图→圆→圆心、半径"命令 绘制过程: 使用对象捕捉追踪定位矩形中心作为圆心 输入半径值30并按Enter确认 通过象限点捕捉确保圆形位置准确 2)绘制直线 操作要点: 选择"绘图→直线"命令 捕捉矩形上边中点作为起点 捕捉圆的上象限点作为终点 按Enter结束当前直线命令 重复技巧: 按Enter可重复最近使用的直线命令 通过圆心捕捉和极轴追踪绘制放射状直线 最终形成完整的信号灯指示图案 3)完成绘制 验证要点: 检查所有直线是否准确连接圆心和象限点 确认极轴追踪的45度增量是否体现 保存绘图文件(快捷键Ctrl+S)
要获取简书上的特定文章 `b28e73eefa88` 的内容,可以通过解析网页结构来提取所需的信息。根据已知的引用描述[^1],目标数据位于 `<li>` 标签下的子元素中,具体来说: - **标题** 和 **链接** 存在于 `<a>` 标签下。 - **摘要** 则存储于 `<p>` 标签。 以下是实现这一功能的一个 Python 脚本示例,它利用 Selenium 来模拟浏览器行为并抓取指定文章的数据: ### 使用 Selenium 抓取简书文章 ```python from selenium import webdriver from selenium.webdriver.common.by import By # 初始化 WebDriver (需确保本地安装有对应版本的驱动程序) browser = webdriver.Chrome() try: # 打开目标页面 article_url = f"https://www.jianshu.com/p/b28e73eefa88" browser.get(article_url) # 提取标题、摘要和链接 title_element = browser.find_element(By.TAG_NAME, "h1") abstract_element = browser.find_element(By.CLASS_NAME, "abstract") link_element = browser.current_url # 输出结果 print(f"Title: {title_element.text} [{link_element}]") print(f"Abstract: {abstract_element.text}") finally: # 关闭浏览器实例 browser.quit() ``` 上述脚本通过定位 HTML 文档中的关键标签实现了对文章基本信息的捕获。需要注意的是,在实际运行前应确认环境配置无误(如 ChromeDriver 版本匹配),并且考虑到反爬机制的存在可能需要额外处理动态加载的内容或其他防护措施[^2]。 #### 数据保存至文件 如果希望将这些信息记录到外部 `.txt` 文件以便后续查阅,则可以扩展如下代码片段所示的方式完成操作: ```python with open("article_jianshu_b28e73eefa88.txt", "w", encoding="utf-8") as file: file.write(f"{title_element.text}\n{abstract_element.text}\n{link_element}") ``` 此部分逻辑基于先前提到的方法论进一步封装成可重复使用的模块化单元。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值