Hibernate批处理与存储过程

时间:2011-11-24 13:26:36

标签: sql hibernate stored-procedures

我有一个存储过程,旨在插入一行。我通过以下方式使用Hibernate进行操作(简化示例):

public void store(int param1, int param2) {
   Connection con = session.connection();  // obtain JDBC connection from Session object
   CallableStatement stmt = con.prepareCall("{ call changesalary(?,?) }");
   stmt.setInt(1, param1);  // first parameter index start with 1
   stmt.setInt(2, param2); // second parameter
   stmt.execute();  // call stored procedure
   cleanup(con, stmt);
}

我想知道是否有可能以更加批处理的方式重用此存储过程而无需修改它(我无法添加新的存储过程或修改现有过程)。我想这样做:

public void batchStore(int[] params1, int[] params2) {
    for (int i = 0; i < params1.length; i++) {
        store(params1[i], params2[i]);
    }
}

public void store(int param1, int param2) {
   Connection con = session.connection();
   CallableStatement stmt = con.prepareCall("{ call changesalary(?,?) }");
   stmt.setInt(1, param1);
   stmt.setInt(2, param2);
   stmt.execute();
   cleanup(con, stmt);
}

但是为了避免大量调用DB,我宁愿准备一组语句,然后我在一次调用中批量处理数据库:

public void store(int[] params1, int[] params2) {
   Connection con = session.connection();
   CallableStatement[] stmts = new CallableStatements[params.size];

   for (int i = 0; i < params1.length; i++) {
       CallableStatement stmt = con.prepareCall("{ call changesalary(?,?) }");
       stmt.setInt(1, params1[i]);
       stmt.setInt(2, params2[i]);  
       stmts[i] = stmt;
    }

    con.executeStatements(stmts);
}

是否可以实现上述伪代码,并通过这样做来提高性能吗?

2 个答案:

答案 0 :(得分:2)

你实际上在做什么是使用JDBC来执行你的SQL(即使你从Hibernate的会话中获取JDBC连接)。使用JDBC,您可以执行以下操作:

public void store(int[] params1, int[] params2) {
   Connection con = session.connection();
   boolean initialAutocommitSetting = connection con.getAutoCommit();
   //disable autocommit
   con.setAutoCommit(false);
   //you only need one statement object:
   CallableStatement stmt = con.prepareCall("{ call changesalary(?,?) }");

   for (int i = 0; i < params1.length; i++) {       
       stmt.setInt(1, params1[i]);
       stmt.setInt(2, params2[i]);  
       //for each call, add the set of parameters as needed and call addBatch();
       stmt.addBatch();
    }
    //when you're done, execute your (batch) statement and see how many updates you got
    int [] updatesCount=stmt.executeBatch(); 

    //manually commit
    con.commit();

    if(updatesCount!=i) {
        //some updates didn't work
    }

    //return connection to initial autocommit setting:
    connection.setAutoCommit(initialAutocommitSetting );
}

希望这会有所帮助。 Javadocs:CallableStatementStatement

答案 1 :(得分:0)

如果您不想使用纯JDBC,则可以使用from bokeh.io import show from bokeh.layouts import column from bokeh.models import DataTable, TableColumn, Button, CustomJS, ColumnDataSource ds = ColumnDataSource(data=dict(a=[1, 2, 3], b=[2, 3, 4])) t = DataTable(columns=[TableColumn(title='a', field='a'), TableColumn(title='b', field='b')], source=ds) b = Button(label="Add random column") b.js_on_click(CustomJS(args=dict(ds=ds, t=t), code="""\ let column_name = null; while (column_name == null || column_name in ds.data) { column_name = Math.random().toString(36).substring(7); } const n = ds.get_length(); ds.data[column_name] = Array.from({length: n}, () => Math.random()); const TableColumn = Bokeh.Models('TableColumn'); t.columns.push(new TableColumn({title: column_name, field: column_name})); t.change.emit(); ds.change.emit(); """)) show(column(b, t)) 设置分页偏移,并使用query.setFirstResult()指定页面大小。这需要您进行一些计算工作:根据query.setMaxResult()的值,您可以确定页面大小并计算页面编号。这样做的好处是您可以变得灵活。 (例如,仅在大于1000条记录时才分页)

query.getMaxResults()类可能有用。