-
一个多线程查询数据库的奇怪问题0
表中有50W笔数据,表结构很简单,主键id(32位随机码),外加一个name字段,都是varchar2类型,想取出全部数据并封装到JavaBean中,但是一次查询耗时太长,想使用多线程的方法取出这些数据,但是用下面的多线程代码运行后发现,预期能取出全部50W笔,但是实际只取出499992笔,少了8笔,不知道是什么原因。
思路是先创建容量为50W的公共List,把这个List当类成员变量传递到线程对象里,然后创建100个线程,每个线程单独创建数据库连接执行查询,然后把各自查出来的结果集封装到JavaBean然后填充到公共list中,代码如下:
package jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; public class Test2 { public static void main(String[] args) { Test2 t2 = new Test2(); List<A> list_db = t2.getAll(); } public List<A> getAll(){ //Connection conn = null; List<A> list_db = new ArrayList<A>(500000); try{ long start = System.currentTimeMillis(); //Class.forName(DRIVER_CLASSNAME); //conn = DriverManager.getConnection(URL, USER, PASSWORD); QueryThread qt = null; for(int i = 0; i < 100; i++){ qt = new QueryThread(); //qt.setConn(conn); qt.setList_db(list_db); qt.settName("thread" + i); qt.setStart((i*5000+1)); qt.setEnd((i+1) * 5000); Thread dao = new Thread(qt); dao.start(); } while(true){ if(list_db.size() == 500000){ break; } System.out.println("..." + list_db.size()); Thread.sleep(1000); } long end = System.currentTimeMillis(); System.out.println("封装完毕!耗时:" + (end - start)/1000 + "秒!"); System.out.println("查询完成,结果集:" + list_db.size()); }catch(Exception e){ e.printStackTrace(); }finally{ // if(conn != null){ // try { // conn.close(); // } catch (SQLException e) { // e.printStackTrace(); // } // } } return list_db; } }
package jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; public class QueryThread extends Thread{ public static String DRIVER_CLASSNAME = "x"; public static String URL = "x"; public static String USER = "x"; public static String PASSWORD = "x"; private List<A> list_db; public void setList_db(List<A> list_db) { this.list_db = list_db; } private int start; private int end; public void setStart(int start) { this.start = start; } public void setEnd(int end) { this.end = end; } private String tName; public void settName(String tName) { this.tName = tName; } @Override public void run(){ Connection conn = null; PreparedStatement stmt = null; try{ System.out.println("线程[" + this.tName + "]开始执行!"); Class.forName(DRIVER_CLASSNAME); conn = DriverManager.getConnection(URL, USER, PASSWORD); stmt = conn.prepareStatement("select t2.* from (select t1.*,rownum rn from (select * from testa t order by t.taid) t1 where rownum <= ?) t2 where t2.rn >= ? "); stmt.setInt(1, end); stmt.setInt(2, start); ResultSet rs = stmt.executeQuery(); A a = null; int count = 0; while(rs.next()){ a = new A(); a.settId(rs.getString(1)); a.setaName(rs.getString(2)); this.list_db.add(a); count++; //System.out.println("线程[" + this.tName + "] 遍历中结果集:" + this.list_db.size()); } System.out.println("线程[" + this.tName + "]执行结束! 结果集:" + count); }catch(Exception e){ System.out.println("线程[" + this.tName + "]插入失败!" + e.getMessage()); e.printStackTrace(); }finally{ if(stmt != null){ try { stmt.close(); } catch (SQLException e2) { System.out.println("线程[" + this.tName + "]关闭stmt 失败!" + e2.getMessage()); e2.printStackTrace(); } } if(conn != null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
问题补充:100个线程每个线程查询5000笔,用分页和动态传参的方式实现2014年3月21日 16:00
8个答案 按时间排序 按投票排序
-
因为ArrayList线程并不安全,要线程安全的话你可以用ConcurrentLinkedQueue。不过话说回来,50w的数据,一般是不需要拆库分表的,磁盘IO你单线程扫就行了,多线程反而可能更慢。
2014年3月24日 22:50
-
如果的查的机子只有一个物理硬盘,用不用多线程查数据,基本一样速度 ,还有可能多线程会变慢.
如果数据在变成javabean这个过程时间比较长,可以用多线程,如果不是多核CPU,还是用单线程吧。
而且你这代码有线程安全问题,多线程访问ArrayList出问题,要用CopyOnWriteArrayList
最好用并发包的线程池看下ExecutorService.invokeAll 这个方法,可以返回每个线程的结果。
楼主,好像还不是很清楚什么情况要注意线程安全,还是了解下先2014年3月24日 14:54
-
System.out.println(Runtime.getRuntime().availableProcessors());看看几何的cup就就启动几个线程
2014年3月23日 12:37
-
1.加个排序字段试试
2.另外线程数要根据 CPU 线程数来定的,多了CPU应付不过来,还要不断切换线程反而慢
3.数据库连接数也要设定好2014年3月22日 09:07
-
1. 100个线程, 是不是太多, 不是线程多就查询快, io是有限的!
2. ArrayList不是线程安全的, 当然数目不对了. 但是也不要用CopyOnWriteArrayList, 因为这个只适合大部分读, 很少量的写.
建议你直接使用Vector, 或者在add的时候, 加锁好了.2014年3月21日 18:56
-
1、ArrayList不是线程安全的,你多线程添加时可能会有问题的。
2、建议你将ArrayList换做java.util.concurrent 下的线程安全的类
例如CopyOnWriteArrayList
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CopyOnWriteArrayList.html
3你的机器CPU线程数是多少,最好启动(cpu核心线程数-1)的线程数,我觉得起太多线程反而慢,你可以测试下,结果共享出来,大家看看2014年3月21日 18:28
-
因为没看到具体操作 不知道具体原因
建议你这样试试
代码的主要逻辑不变 然后变成10个线程 读取100条数据 看看是否也少了 确定一下是不是你写的哪部分逻辑有问题2014年3月21日 17:13
相关推荐
在多线程环境下使用`QsqlQuery`变量时,有时会遇到奇怪的问题,即使按照上述方法进行了处理,程序运行一段时间后仍可能出现数据库死锁或者异常关闭的情况。此时,可以尝试通过限制`QsqlQuery`变量的作用域来改善这一...
本项目名为“数据库程式:尚未完成的”,它是一个用于实现通用查询功能的数据库工具。然而,项目开发者遇到了一个棘手的问题:一旦出现未返回结果的查询,应用就无法继续进行其他查询操作,这显然不符合正常的功能...
如果深入做下去,你会发现要面对不同的网页要求,比如有认证的,不同文件格式、编码处理,各种奇怪的url合规化处理、重复抓取问题、cookies 跟随问题、多线程多进程抓取、多节点抓取、抓取调度、资源压缩等一系列...
4.关于并发和多线程 5.幽灵代码 6.常见的Java泥潭 7.JVM 8.关于字符集与编码 9.常用分析工具 10.Java最佳实践 11.关于数据库 12.工程实践 13.常见的案例 附录 A JProfiler内存泄漏精确定位 B SUN JDK自带故障定位 C...
为了避免这些问题,可以使用 JedisPool,JedisPool 是一个线程安全的网络连接池。可以用 JedisPool 创建一些可靠 Jedis 实例,可以从池中拿到 Jedis 的实例。 Jedis 的基本操作 Jedis 提供了多种基本操作,包括...
与cgi的区别在于servlet处于服务器进程中,它通过多线程方式运行其service方法,一个实例可以服务于多个请求,并且其实例一般不会销毁,而CGI对每个请求都产生新的进程,服务完成后就销毁,所以效率上低于servlet。...
你曾经多少次有过这种感觉—你已经解决过了一个问题但就是不能确切知道是在什么地 方或怎么解决的?如果你能记起以前问题的细节和怎么解决它的,你就可以复用以前的经验而不需要重新发现它。然而,我们 并没有很好...
与cgi的区别在于servlet处于服务器进程中,它通过多线程方式运行其service方法,一个实例可以服务于多个请求,并且其实例一般不会销毁,而CGI对每个请求都产生新的进程,服务完成后就销毁,所以效率上低于servlet。...
1.11.4 一个独立的领域:应用程序 1.12 分析和设计 1.12.1 不要迷失 1.12.2 阶段0:拟出一个计划 1.12.3 阶段1:要制作什么? 1.12.4 阶段2:开始构建? 1.12.5 阶段3:正式创建 1.12.6 阶段4:校订 1.12.7 计划的...
- **如何创建一个动态的Tree控件**(P.23) - 创建动态Tree控件可以通过动态添加和删除节点以及监听相关的控件事件实现。 - **如何重载MRU文件**(P.25) - 重载MRU文件可以通过自定义`CMRUFile`类或通过覆盖相应...
5. **多线程编程**:在聊天软件中,通常需要同时处理接收和发送消息,这就需要用到多线程技术,以确保用户界面的响应性和系统的稳定性。 6. **网络编程**:理解网络编程的基础知识,如套接字(Socket)编程,是实现...
1.11.4 一个独立的领域:应用程序 1.12 分析和设计 1.12.1 不要迷失 1.12.2 阶段0:拟出一个计划 1.12.3 阶段1:要制作什么? 1.12.4 阶段2:开始构建? 1.12.5 阶段3:正式创建 1.12.6 阶段4:校订 1.12.7 计划的...
1.11.4 一个独立的领域:应用程序 1.12 分析和设计 1.12.1 不要迷失 1.12.2 阶段0:拟出一个计划 1.12.3 阶段1:要制作什么? 1.12.4 阶段2:开始构建? 1.12.5 阶段3:正式创建 1.12.6 阶段4:校订 1.12.7 ...
1.11.4 一个独立的领域:应用程序 1.12 分析和设计 1.12.1 不要迷失 1.12.2 阶段0:拟出一个计划 1.12.3 阶段1:要制作什么? 1.12.4 阶段2:开始构建? 1.12.5 阶段3:正式创建 1.12.6 阶段4:校订 1.12.7 计划的...
1.11.4 一个独立的领域:应用程序 1.12 分析和设计 1.12.1 不要迷失 1.12.2 阶段0:拟出一个计划 1.12.3 阶段1:要制作什么? 1.12.4 阶段2:开始构建? 1.12.5 阶段3:正式创建 1.12.6 阶段4:校订 1.12.7 计划的...
1.11.4 一个独立的领域:应用程序 1.12 分析和设计 1.12.1 不要迷失 1.12.2 阶段0:拟出一个计划 1.12.3 阶段1:要制作什么? 1.12.4 阶段2:开始构建? 1.12.5 阶段3:正式创建 1.12.6 阶段4:校订 1.12.7 计划的...
1.11.4 一个独立的领域:应用程序 1.12 分析和设计 1.12.1 不要迷失 1.12.2 阶段0:拟出一个计划 1.12.3 阶段1:要制作什么? 1.12.4 阶段2:开始构建? 1.12.5 阶段3:正式创建 1.12.6 阶段4:校订 1.12.7 计划的...
1.11.4 一个独立的领域:应用程序 1.12 分析和设计 1.12.1 不要迷失 1.12.2 阶段0:拟出一个计划 1.12.3 阶段1:要制作什么? 1.12.4 阶段2:开始构建? 1.12.5 阶段3:正式创建 1.12.6 阶段4:校订 1.12.7 计划的...
1.11.4 一个独立的领域:应用程序 1.12 分析和设计 1.12.1 不要迷失 1.12.2 阶段0:拟出一个计划 1.12.3 阶段1:要制作什么? 1.12.4 阶段2:开始构建? 1.12.5 阶段3:正式创建 1.12.6 阶段4:校订 1.12.7 计划的...