重用准备好的语句,事务和连接池

时间:2014-03-22 18:50:11

标签: java mysql transactions prepared-statement connection-pooling

我正在开展一个学校项目,我的团队必须确保数据的一致性和完整性,以及提高交易网站的性能。该网站使用JSP和JAVA编码。我们也在为我们的项目使用MySQL及其ndb集群。

首先,我已对使用100,175和250个虚拟用户的负载测试的预准备语句进行了实验。结果表明,重用预准备语句可以缩短响应时间和吞吐量。通过改进,我的意思是平均响应时间减少,最大吞吐量增加。

其次,我还使用连接池进行了实验,并对100,175和250个虚拟用户进行了相同的负载测试。同样,结果显示性能有所改善。只是一个附加信息,我使用c3p0作为连接池。

通过这些结果,我计划为交易网站使用预准备语句和连接池。同时,我们还会使用事务来确保数据的一致性和完整性。

目前,我实施预准备报表和交易的方式如下:

public class ExchangeBean {
private PreparedStatement psSelectFromBuy = null;
private PreparedStatement psSelectFromSell = null;
private PreparedStatement psInsertBuy = null;
private PreparedStatement psInsertSell = null;
private Connection tranDbConnection = null;

public ExchangeBean() {
    reusePreparedStatements();
}

public void reusePreparedStatements() {
    tranDbConnection = DbBean.getDBConnection();
    dbConnection.setAutoCommit(false);


    try {
        psSelectFromBuy = dbConnection.prepareStatement("SELECT * FROM buy WHERE stock = ?" FOR UPDATE);
        psSelectFromSell = dbConnection.prepareStatement("SELECT * FROM sell WHERE stock = ?" FOR UPDATE);
        psInsertBuy = tranDbConnection.prepareStatement("INSERT INTO buy (userid, date, price, stock) VALUES (?, ?, ?, ?)")
        psInsertSell = tranDbConnection.prepareStatement("INSERT INTO sell (userid, date, price, stock) VALUES (?, ?, ?, ?)");
    } catch (Exception e) {
    }
}

public boolean buy(//some parameters) {
    try {
        selectFromBuy(); //a method that contains psSelectFromBuy
        psInsertBuy.clearParameters();
        psInsertBuy.setInt(1, buy.getUserId());
        psInsertBuy.setLong(2, buy.getDate().getTime());
        psInsertBuy.setInt(3, buy.getPrice());
        psInsertBuy.setString(4, buy.getStock());
        psInsertBuy.executeUpdate();

        //some other codes
        psInsertBuy.commit();
    } catch (Exception e) {
        dbConnection.rollback();
    }
}

public boolean sell(//some parameters) {
    try {
        selectFromSell(); //a method that contains psSelectFromSell
        psInsertSell.clearParameters();
        psInsertSell.setInt(1, sell.getUserId());
        psInsertSell.setLong(2, sell.getDate().getTime());
        psInsertSell.setInt(3, sell.getPrice());
        psInsertSell.setString(4, sell.getStock());
        psInsertSell.executeUpdate();

        //some other codes
        psInsertSell.commit();
    } catch (Exception e) {
        dbConnection.rollback();
    }
}
}

注意:为简洁起见,此代码示例不完整;相当多的代码和逻辑不在其中。

基本上,我的方法是将预处理语句声明为类变量,然后在第一次调用类时实例化它们。

问题

  1. 我的方法是否正确?我觉得这不完全正确,因为我所有准备好的语句都与一个连接相关联。我担心如果多个用户同时尝试买卖,可能会出现问题,因为只使用了一个连接。但是,我不能关闭连接,否则我准备好的语句将在每次交易后关闭,因此不会被重用。此外,当我提交时,交易中涉及的所有准备好的语句应该一起提交,因此如果我只使用一个连接就会更容易。

  2. 您对如何使用连接池与预准备语句和事务有任何建议吗?我想在每次从池创建连接时将所有准备好的语句缓存到连接中。当连接用于买入或卖出时,该方法本身将禁用该连接上的自动提交,并在方法结束时再次启用自动提交。这种方法是否合适?或者我应该有两个连接池(一个用于非事务连接,一个用于事务连接)?

  3. 谢谢!

0 个答案:

没有答案