ExecutorServices
によって呼び出されるいくつかのスレッドがMySQL DBに書き込むことを許可するDAOクラスを作成しました。JDBCとc3p0を使用したMySQL DBのマルチスレッド書き込み
EDIT:私はc3p0を使用してJDBC ConnectionPoolを作成しています。だから、すべての新しいスレッドが
DataBaseManager.getInstance().getConnection()
を呼び出して新しいJDBC Connection
を取得します例えば、実行中にランダム同時実行の問題があるようです:
java.sql.SQLException: No value specified for parameter 1
at com.eanurag.dao.DataBaseManager.writeData(DataBaseManager.java:102)
私はコードですべての問題を理解することはできませんよ。私はちょうどwriteData()
全体を同期させるべきですか?
public class DataBaseManager {
private final static Logger logger = Logger.getLogger(DataBaseManager.class);
private static volatile DataBaseManager dbInstance = null;
private DataBaseManager() {
cpds = new ComboPooledDataSource();
try {
cpds.setDriverClass("com.mysql.jdbc.Driver");
} catch (PropertyVetoException e) {
logger.error("Error in Initializing DB Driver class", e);
}
cpds.setJdbcUrl("jdbc:mysql://" + DB_HOST + "/" + DB_NAME);
cpds.setUser(DB_USER);
cpds.setPassword(DB_PASS);
cpds.setMinPoolSize(MINIMUM_POOL_SIZE);
cpds.setAcquireIncrement(INCREMENT_SIZE);
cpds.setMaxPoolSize(MAXIMUM_POOL_SIZE);
cpds.setMaxStatements(MAX_STATEMENTS);
}
public static DataBaseManager getInstance() {
if (dbInstance == null) {
synchronized (WorkerManager.class) {
if (dbInstance == null) {
dbInstance = new DataBaseManager();
}
}
}
return dbInstance;
}
private ComboPooledDataSource cpds;
private static final Integer MINIMUM_POOL_SIZE = 10;
private static final Integer MAXIMUM_POOL_SIZE = 1000;
private static final Integer INCREMENT_SIZE = 5;
private static final Integer MAX_STATEMENTS = 200;
private volatile Connection connection = null;
private volatile Statement statement = null;
private volatile PreparedStatement preparedStatement = null;
private static final String DB_HOST = "localhost";
private static final String DB_PORT = "3306";
private static final String DB_USER = "root";
private static final String DB_PASS = "";
private static final String DB_NAME = "crawly";
private static final String URL_TABLE = "url";
public Connection getConnection() throws SQLException {
logger.info("Creating connection to DB!");
return this.cpds.getConnection();
}
public Boolean writeData(URL url) {
StringBuffer writeDBStatement = new StringBuffer();
writeDBStatement.append("insert into");
writeDBStatement.append(" ");
writeDBStatement.append(DB_NAME);
writeDBStatement.append(".");
writeDBStatement.append(URL_TABLE);
writeDBStatement.append(" ");
writeDBStatement.append("values (?,?,default)");
Boolean dbWriteResult = false;
try {
connection = DataBaseManager.getInstance().getConnection();
preparedStatement = connection.prepareStatement(writeDBStatement.toString());
preparedStatement.setString(1, url.getURL());
preparedStatement.setString(2, String.valueOf(url.hashCode()));
dbWriteResult = (preparedStatement.executeUpdate() == 1) ? true : false;
if(dbWriteResult){
logger.info("Successfully written to DB!");
}
} catch (SQLException e) {
logger.error("Error in writing to DB", e);
} finally {
try {
preparedStatement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return dbWriteResult;
}
}
異なるスレッドからメンバ変数(Connection、PreparedStatement)にアクセスします。 writeData()のメソッド変数を作成するか、各スレッドがクラスのインスタンスを所有していることを確認してください。 – Michal
私は 'volatile'はあなたがそれがそこにあると思う利益を与えることになると思いません。なぜ、preparedstatementはクラスレベルの変数ですか? – kolossus
@Michal(Connection、PreparedStatement)メソッドの変数writeData()は、各スレッドにクラスの独自のインスタンスを渡すので、ConnectionPoolの現在のロジックでは機能しません。ありがとう! – Anurag