多个线程没有将所有内容插入MySQL

时间:2014-06-19 21:02:23

标签: java mysql eclipse multithreading java-ee

请原谅任何错误的做法,因为我对线程很新。我有一个程序调用我的api并以json格式返回数据。每个请求都以json格式返回一行数据。总而言之,我需要每天检索大约2,000,000行,这意味着2,000,000个请求(我知道这是一个糟糕的设计,但系统不是为此设计的,这正是我在接下来的几周内需要做的)。当我尝试在单个线程上运行它时,我每分钟处理大约200个请求,这太慢了。结果我创建了12个线程,我每分钟处理5500行,这是一个很大的改进。问题是平均只有90%的行被插入到数据库中,因为我运行了几次以确保。在每个插入打印到文件之前,每个发送的URL然后我检查每个插入语句是否成功(执行时返回1),这一切似乎都很好。每次我运行它都会插入大约90%,但它确实有所不同,它从来都不是一致的数字。我在java代码中做错了吗?本质上,代码通过创建12个线程从main开始。每个线程创建一个run方法,该方法调用MySQLPopulateHistData的新实例,并传递一个开始和结束整数,这些整数在insert语句中用于范围。我做了很多system.out.println类型测试,可以看到所有线程都启动了,所有12个实例(每个线程的一个实例)都在执行?有谁知道它可能是什么?

MAIN:

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class MainClass {


    public static void main(String[] args) {

        try {

             //create a pool of threads

             Thread[] threads = new Thread[12];

            //  submit jobs to be executing by the pool



             for (int i = 0; i <12; i++) {

            threads[i] = new Thread(new Runnable() {

                public void run() {

                     try {

                              new MySQLPopulateHistData(RangeClass.IdStart, RangeClass.IdEnd);

                        } catch (Throwable e) {
                             //TODO Auto-generated catch block
                            e.printStackTrace();
                        }

                    }

                 });
                 threads[i].start();
                 Thread.sleep(1000);

                    RangeClass.IdStart = RangeClass.IdEnd + 1;  
                    RangeClass.IdEnd = RangeClass.IdEnd + 170000;
             }

        } catch (Throwable e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


    }

}

MyDataSourceFactory.class

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

import javax.sql.DataSource;

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;



    public class MyDataSourceFactory {

        static String url = "jdbc:mysql://localhost:3306/my_schema";
        static String userName = "root"; 
        static String password = "password";


        public synchronized static DataSource getMySQLDataSource() {


            MysqlDataSource mysqlDS = null;

            mysqlDS = new MysqlDataSource();

            mysqlDS.setURL(url);

            mysqlDS.setUser(userName);

            mysqlDS.setPassword(password);

            return mysqlDS;

        }    

    }

MySQLPopulateHistData.class

public class MySQLPopulateHistData {

        public MySQLPopulateHistData(int s, int e ) throws IOException, Throwable{

            getHistory(s,e);


        }
            public synchronized void getHistory(int start, int end){


                DataSource ds = MyDataSourceFactory.getMySQLDataSource();


                Connection con = null;
                Connection con2 = null;

                Statement stmt = null;
                Statement stmt2 = null;

                ResultSet rs = null;


                try {

                    con = ds.getConnection();
                    con2 = ds.getConnection();

                    stmt = con.createStatement();
                    stmt2 = con.createStatement();

                    rs = stmt.executeQuery("SELECT s FROM sp_t where s_id BETWEEN "+ start +" AND "+  end + " ORDER BY s;");


                    String s = "";


                    while(rs.next()){

                         s = rs.getString("s");


                        if( s == ""){

                        }
                        else{

                        try{


                            URL fullUrl = new URL(//My Url to my api with password with start and end range);


                        InputStream is = fullUrl.openStream();
                        String jsonStr = getStringFromInputStream(is);


                          JSONObject j = new JSONObject(jsonStr);

                            JSONArray arr = j.getJSONObject("query").getJSONObject("results").getJSONArray("quote");


                            for(int i=0; i<arr.length(); i++){
                                JSONObject obj = arr.getJSONObject(i);
                                String symbol = obj.getString("s");


                            stmt2.executeUpdate("INSERT into sp2_t(s) VALUES ('"+ s +"') BETWEEN "+start+" AND "+ end +";");


                            }


                        }
                        catch(Exception e){
                        }


                            }
                            s = "";

                    }

                } catch (Exception e) {

                    e.printStackTrace();

                }finally{

                        try {

                            if(rs != null) rs.close();

                            if(stmt != null) stmt.close();

                            if(con != null) con.close();



                            if(stmt2 != null) stmt.close();

                            if(con2 != null) con.close();



                        } catch (Exception e) {

                            e.printStackTrace();

                        }

                }

            }



}

更新

所以我说:

(if s.equals("")){
System.out.println("EMPTY");
}

它从未打印出EMPTY。在JSON请求转换为JSONArray之后,我添加了:

if(arr.length()>0){
StaticClassHolder.cntResponses++;
}

这只是另一个类中的静态变量,每当有一个有效的JSON响应时它就会递增。它等于它应该是的确切数量。所以似乎URL正确获取所有响应,正确解析它们,但是没有将它们正确地插入到数据库中?我想不通为什么?

2 个答案:

答案 0 :(得分:0)

在Oracle中插入记录时,我也遇到了类似的问题。由于我没有找到任何具体的解决方案。我试过单线程,一切都很顺利。

答案 1 :(得分:-1)

为什么这不起作用有几个原因:

  • 普通计算机每个CPU只能处理大约4-8个线程。由于系统使用某些线程,因此您只能同时运行某些线程。计算机通过暂停某些线程然后运行另一个线程来处理此问题。

  • 如果您尝试通过套接字向mysql服务器发送多个查询,同时有些请求将无效,您将丢失部分数据。

至于现在,我没有任何解决方案来更快地更新表格。