本文介绍如何使用Hibernate.jdbc.Work批量处理大量的数据(QCUD)
简介
为何使用原生的批量处理数据操作而不用现有的hibernate框架实现呢,因为hibernate对插入和更新的处理方式在大量数据插入式并不能更好的支持。
需求分析,如果你希望将一个对象的集合全部插入到数据库,但使用hibernate框架的批处理速度回比较慢,hibernate其实是一条一条的插入数据的,JDBC的BATCH不同是JDBC的bactch会先将sql预编译,再将集合的值SET进去,大大节省了编译SQL的时间。
经过测试:使用hibernate插入10条数据,需要预编译SQL10次,而原始JDBC的batch只需要预编译一次,且随着需要插入的数据增长需要的时间区别也越来越大,使用hibernate默认batch插入10000条数据需要1-2秒,优化后只需要200毫秒左右.
hibernate de persist he merge
/**
* Make an instance managed and persistent.
* @param entity entity instance
* @throws EntityExistsException if the entity already exists.
* (If the entity already exists, the <code>EntityExistsException</code> may
* be thrown when the persist operation is invoked, or the
* <code>EntityExistsException</code> or another <code>PersistenceException</code> may be
* thrown at flush or commit time.)
* @throws IllegalArgumentException if the instance is not an
* entity
* @throws TransactionRequiredException if invoked on a
* container-managed entity manager of type
* <code>PersistenceContextType.TRANSACTION</code> and there is
* no transaction
*/
public void persist(Object entity);
/**
* Merge the state of the given entity into the
* current persistence context.
* @param entity entity instance
* @return the managed instance that the state was merged to
* @throws IllegalArgumentException if instance is not an
* entity or is a removed entity
* @throws TransactionRequiredException if invoked on a
* container-managed entity manager of type
* <code>PersistenceContextType.TRANSACTION</code> and there is
* no transaction
*/
public <T> T merge(T entity);
通过Hibernate的缓存进行批量插入
public class HibernateTest {
public static void main(String args[]){
SessionFactory sessionFactory = hibernateTemplate.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction(); //开启事务
for(int i=0;i<50;i++){
Usertable user = new Usertable();
user.setPassword("100"+i);
session.save(user);
if(i%100==0){
session.flush();
session.clear();
}
}
ts.commit();
HibernateSessionFactory.closeSession();
}
}
直接调用JDBC
@Transactional(rollbackFor = Exception.class)
public RpcServiceResult createSubThings(ArrayNode insertArray) {
SessionFactory sessionFactory = hibernateTemplate.getSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction(); //开启事务
try {
//do something
String sqlStr = new String("INSERT INTO table ( `attribute1`,"
+ " `attribute2`, "
+ " `attribute3`"
+ ") "
+ "VALUES (?, ?, ?);");
Work work = new Work() {//Contract for performing a discrete piece of org.hibernate.jdbc.Work;
@Override
public void execute(Connection connection) throws SQLException {
PreparedStatement statement = connection.prepareStatement(sqlStr);
for (int i = 0; i < insertArray.size(); i++) {
JsonNode subThingJsonNode = insertArray.get(i);
String value1 = subThingJsonNode.get("key1").asText();
String value2 = subThingJsonNode.get("key2").asText();
String value3 = subThingJsonNode.get("key3").asText();
statement.setString(1,value1);
statement.setString(2,value2);
statement.setString(3,value3);
statement.addBatch();
}
statement.executeBatch();
}
};
session.doWork(work);
tx.commit(); //提交事务
ObjectNode responseNode = JsonNodeFactory.instance.objectNode();
return new RpcServiceResult(HttpStatus.SC_OK, responseNode);
} catch(HibernateException en) {
tx.rollback();
logger.error("Failed to save the ...");
return new RpcServiceResult(HttpStatus.SC_INTERNAL_SERVER_ERROR);
} catch (Exception en) {
logger.error("Failed to save the ...");
tx.rollback();
return new RpcServiceResult(HttpStatus.SC_INTERNAL_SERVER_ERROR);
} finally {
session.close();
}
}
总结
使用此方法批量提交插入操作,不仅可以提高效率,也可以防止SQL注入, 同时UPDATE, DELETE 等操作也可以使用此方式.