欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Hibernate+JDBC实现批量插入、更新及删除的方法详解

程序员文章站 2024-04-02 10:13:28
本文实例讲述了hibernate jdbc实现批量插入、更新及删除的方法。分享给大家供大家参考,具体如下: 一、批量插入(两种方式) 1. 通过hibernate缓存...

本文实例讲述了hibernate jdbc实现批量插入、更新及删除的方法。分享给大家供大家参考,具体如下:

一、批量插入(两种方式)

1. 通过hibernate缓存

如果这样写代码进行批量插入(初始设想):

package com.anlw.util;
import org.hibernate.session;
import org.hibernate.sessionfactory;
import org.hibernate.transaction;
import org.hibernate.boot.registry.standardserviceregistrybuilder;
import org.hibernate.cfg.configuration;
import org.hibernate.service.serviceregistry;
import com.anlw.entity.student;
public class sessionutil {
  configuration conf = null;
  serviceregistry st = null;
  sessionfactory sf = null;
  session sess = null;
  transaction tx = null;
  public void hibernatetest() {
    conf = new configuration().configure();
    st = new standardserviceregistrybuilder().applysettings(conf.getproperties()).build();
    sf = conf.buildsessionfactory(st);
    try {
      sess = sf.opensession();
      tx = sess.begintransaction();
      for (int i = 0; i < 10; i++) {
        student s = new student();
        s.setage(i + 1);
        s.setname("test");
        sess.save(s);
      }
      tx.commit();
    } catch (exception e) {
      if (tx != null) {
        tx.rollback();
      }
    } finally {
      sess.close();
      sf.close();
    }
  }
  public static void main(string[] args) {
    new sessionutil().hibernatetest();
  }
}

如果数据量太大,会有可能出现内存溢出的异常;

小知识:

(1).hibernate一级缓存,对其容量没有限制,强制使用,由于所有的对象都被保存到这个缓存中,内存总会达到一定数目时出现内存溢出的情况;
(2).hibernate二级缓存可以进行大小配置;

要解决内存溢出的问题,就应该定时的将sessiion缓存中的数据刷到数据库,正确的批量插入方式:

(1).设置批量尺寸(博主至今还没有明白下面这个属性和flush()方法的区别)

<property name="hibernate.jdbc.batch_size">2</property>

配置这个参数的原因就是尽量少读数据库,该参数值越大,读数据库的次数越少,速度越快;上面这个配置,是hibernate是等到程序积累了100个sql之后在批量提交;

(2).关闭二级缓存(这个博主也不是很明白)

<property name="hibernate.cache.use_second_level_cache">false</property>

除了session级别的一级缓存,hibernate还有一个sessionfactory级别的二级缓存,如果启用了二级缓存,从机制上来说,hibernate为了维护二级缓存,在批量插入时,hibernate会将对象纳入二级缓存,性能上就会有很大损失,也可能引发异常,因此最好关闭sessionfactory级别的二级缓存;

(3).在一二设置完成的基础上,清空session级别的一级缓存;

package com.anlw.util;
import org.hibernate.session;
import org.hibernate.sessionfactory;
import org.hibernate.transaction;
import org.hibernate.boot.registry.standardserviceregistrybuilder;
import org.hibernate.cfg.configuration;
import org.hibernate.service.serviceregistry;
import com.anlw.entity.student;
public class sessionutil {
  configuration conf = null;
  serviceregistry st = null;
  sessionfactory sf = null;
  session sess = null;
  transaction tx = null;
  public void hibernatetest() {
    conf = new configuration().configure();
    st = new standardserviceregistrybuilder().applysettings(conf.getproperties()).build();
    sf = conf.buildsessionfactory(st);
    try {
      sess = sf.opensession();
      tx = sess.begintransaction();
      for (int i = 0; i < 10; i++) {
        student s = new student();
        s.setage(i + 1);
        s.setname("test");
        sess.save(s);
        if(i%100 == 0){       //以每100个数据作为一个处理单元
          sess.flush();      //保持与数据库数据的同步
          sess.clear();      //清楚session级别的一级缓存的全部数据,及时释放占用的内存
        }
      }
      tx.commit();
    } catch (exception e) {
      if (tx != null) {
        tx.rollback();
      }
    } finally {
      sess.close();
      sf.close();
    }
  }
  public static void main(string[] args) {
    new sessionutil().hibernatetest();
  }
}

2. 绕过hibernate,直接调用jdbc api

package com.anlw.util;
import java.sql.connection;
import java.sql.preparedstatement;
import java.sql.sqlexception;
import org.hibernate.session;
import org.hibernate.sessionfactory;
import org.hibernate.transaction;
import org.hibernate.boot.registry.standardserviceregistrybuilder;
import org.hibernate.cfg.configuration;
import org.hibernate.jdbc.work;
import org.hibernate.service.serviceregistry;
public class sessionutil {
  configuration conf = null;
  serviceregistry st = null;
  sessionfactory sf = null;
  session sess = null;
  transaction tx = null;
  public void hibernatetest() {
    conf = new configuration().configure();
    st = new standardserviceregistrybuilder().applysettings(conf.getproperties()).build();
    sf = conf.buildsessionfactory(st);
    try {
      sess = sf.opensession();
      tx = sess.begintransaction();
      //执行work对象指定的操作,即调用work对象的execute()方法
      //session会把当前使用的数据库连接传给execute()方法
      sess.dowork(new work() {
        @override
        public void execute(connection arg0) throws sqlexception {//需要注意的是,不需要调用close()方法关闭这个连接
          //通过jdbc api执行用于批量插入的sql语句
          string sql = "insert into student(name,age) values(?,?)";
          preparedstatement ps = arg0.preparestatement(sql);
          for(int i=0;i<10;i++){
            ps.setstring(1, "kobe");
            ps.setint(2,12);
            ps.addbatch();
          }
          ps.executebatch();
        }
      });
      tx.commit();
    } catch (exception e) {
      if (tx != null) {
        tx.rollback();
      }
    } finally {
      sess.close();
      sf.close();
    }
  }
  public static void main(string[] args) {
    new sessionutil().hibernatetest();
  }
}

注意:通过jdbc api中的preparedstatement接口来执行sql语句,sql语句涉及到的数据不会被加载到session的缓存中,因此不会占用内存空间,因此直接调用jdbc api批量化插入的效率要高于hibernate缓存的批量插入;

更新&&删除

语法格式:(hql)

update  |     delete from? <classname> [where where_conditions]

1>在from子句中,from关键字是可选的,即完全可以不写from关键字
2>在from子句中,只能有一个类名,可以在该类名后指定别名
3>不能在批量hql语句中使用连接,显示或者隐式的都不行,但可以在where子句中使用子查询
4>整个where子句是可选的,where子句的语法sql语句中where子句的语法完全相同
5>query.executeupdate()方法返回一个整型值,该值是受此操作影响的记录数量,由于hibernate的底层操作实际上是由jdbc完成的,因此,如果有批量update或delete操作被转换成多条update或delete语句,(关联或者继承映射),该方法只能返回最后一条sql语句影响的记录行数,不是所有的记录行数,需要注意;

二、批量更新(两种方式)

1. 使用hibernate直接进行批量更新

(1)方式1:(hibernate的hql直接支持update/delete的批量更新语法)

package com.anlw.util;
import org.hibernate.query;
import org.hibernate.session;
import org.hibernate.sessionfactory;
import org.hibernate.transaction;
import org.hibernate.boot.registry.standardserviceregistrybuilder;
import org.hibernate.cfg.configuration;
import org.hibernate.service.serviceregistry;
public class sessionutil {
  configuration conf = null;
  serviceregistry st = null;
  sessionfactory sf = null;
  session sess = null;
  transaction tx = null;
  public void hibernatetest() {
    conf = new configuration().configure();
    st = new standardserviceregistrybuilder().applysettings(conf.getproperties()).build();
    sf = conf.buildsessionfactory(st);
    try {
      sess = sf.opensession();
      tx = sess.begintransaction();
      //在hql查询中使用update进行批量更新,下面的的语句是hql语句,不是sql语句
      query query = sess.createquery("update student set name = 'www'");
      query.executeupdate();
      tx.commit();
    } catch (exception e) {
      if (tx != null) {
        tx.rollback();
      }
    } finally {
      sess.close();
      sf.close();
    }
  }
  public static void main(string[] args) {
    new sessionutil().hibernatetest();
  }
}

(2)方式2:(强烈不推荐)

package com.anlw.util;
import java.sql.connection;
import java.sql.sqlexception;
import java.sql.statement;
import org.hibernate.cachemode;
import org.hibernate.query;
import org.hibernate.scrollmode;
import org.hibernate.scrollableresults;
import org.hibernate.session;
import org.hibernate.sessionfactory;
import org.hibernate.transaction;
import org.hibernate.boot.registry.standardserviceregistrybuilder;
import org.hibernate.cfg.configuration;
import org.hibernate.jdbc.work;
import org.hibernate.service.serviceregistry;
import com.anlw.entity.student;
public class sessionutil {
  configuration conf = null;
  serviceregistry st = null;
  sessionfactory sf = null;
  session sess = null;
  transaction tx = null;
  public void hibernatetest() {
    conf = new configuration().configure();
    st = new standardserviceregistrybuilder().applysettings(conf.getproperties()).build();
    sf = conf.buildsessionfactory(st);
    try {
      sess = sf.opensession();
      tx = sess.begintransaction();
      //查询表中的所有数据
      scrollableresults student = sess.createquery("from student")
          .setcachemode(cachemode.ignore)
          .scroll(scrollmode.forward_only);
      int count = 0;
      while(student.next()){
        student s = (student)student.get(0);
        s.setname("haha");
        if(++count%3 == 0){
          sess.flush();
          sess.clear();
        }
      }
      tx.commit();
    } catch (exception e) {
      if (tx != null) {
        tx.rollback();
      }
    } finally {
      sess.close();
      sf.close();
    }
  }
  public static void main(string[] args) {
    new sessionutil().hibernatetest();
  }
}

通过这种方式,虽然可以执行批量更新,但效果非常不好,执行效率不高,需要先执行数据查询,然后再执行数据更新,而且这种更新将是逐行更新,即每更新一行记录,都要执行一条update语句,性能非常低;

2. 绕过hibernate,调用jdbc api

(1)方式1:

package com.anlw.util;
import java.sql.connection;
import java.sql.preparedstatement;
import java.sql.sqlexception;
import java.sql.statement;
import org.hibernate.session;
import org.hibernate.sessionfactory;
import org.hibernate.transaction;
import org.hibernate.boot.registry.standardserviceregistrybuilder;
import org.hibernate.cfg.configuration;
import org.hibernate.jdbc.work;
import org.hibernate.service.serviceregistry;
public class sessionutil {
  configuration conf = null;
  serviceregistry st = null;
  sessionfactory sf = null;
  session sess = null;
  transaction tx = null;
  public void hibernatetest() {
    conf = new configuration().configure();
    st = new standardserviceregistrybuilder().applysettings(conf.getproperties()).build();
    sf = conf.buildsessionfactory(st);
    try {
      sess = sf.opensession();
      tx = sess.begintransaction();
      //执行work对象指定的操作,即调用work对象的execute()方法
      //session会把当前使用的数据库连接传给execute()方法
      sess.dowork(new work() {
        @override
        public void execute(connection arg0) throws sqlexception {//需要注意的是,不需要调用close()方法关闭这个连接
          string sql = "update student set name = 'oracle'";
          //创建一个satement对象
          statement st = arg0.createstatement();
          //调用jdbc的update进行批量更新
          st.executeupdate(sql);
        }
      });
      tx.commit();
    } catch (exception e) {
      if (tx != null) {
        tx.rollback();
      }
    } finally {
      sess.close();
      sf.close();
    }
  }
  public static void main(string[] args) {
    new sessionutil().hibernatetest();
  }
}

(2)方式2:

package com.anlw.util;
import java.sql.connection;
import java.sql.preparedstatement;
import java.sql.sqlexception;
import java.sql.statement;
import org.hibernate.session;
import org.hibernate.sessionfactory;
import org.hibernate.transaction;
import org.hibernate.boot.registry.standardserviceregistrybuilder;
import org.hibernate.cfg.configuration;
import org.hibernate.jdbc.work;
import org.hibernate.service.serviceregistry;
public class sessionutil {
  configuration conf = null;
  serviceregistry st = null;
  sessionfactory sf = null;
  session sess = null;
  transaction tx = null;
  public void hibernatetest() {
    conf = new configuration().configure();
    st = new standardserviceregistrybuilder().applysettings(conf.getproperties()).build();
    sf = conf.buildsessionfactory(st);
    try {
      sess = sf.opensession();
      tx = sess.begintransaction();
      //执行work对象指定的操作,即调用work对象的execute()方法
      //session会把当前使用的数据库连接传给execute()方法
      sess.dowork(new work() {
        @override
        public void execute(connection arg0) throws sqlexception {//需要注意的是,不需要调用close()方法关闭这个连接
          string sql = "update student set name = ? where name=?";
          preparedstatement ps = arg0.preparestatement(sql);
          for(int i=0;i<10;i++){
            ps.setstring(1,"tom");
            ps.setstring(2, "oracle");
            ps.addbatch();
          }
          ps.executebatch();
        }
      });
      tx.commit();
    } catch (exception e) {
      if (tx != null) {
        tx.rollback();
      }
    } finally {
      sess.close();
      sf.close();
    }
  }
  public static void main(string[] args) {
    new sessionutil().hibernatetest();
  }
}

三、批量删除(两种方式)

1. 使用hibernate直接进行批量删除

(1)方式1:(hibernate的hql直接支持update/delete的批量更新语法)

package com.anlw.util;
import org.hibernate.query;
import org.hibernate.session;
import org.hibernate.sessionfactory;
import org.hibernate.transaction;
import org.hibernate.boot.registry.standardserviceregistrybuilder;
import org.hibernate.cfg.configuration;
import org.hibernate.service.serviceregistry;
public class sessionutil {
  configuration conf = null;
  serviceregistry st = null;
  sessionfactory sf = null;
  session sess = null;
  transaction tx = null;
  public void hibernatetest() {
    conf = new configuration().configure();
    st = new standardserviceregistrybuilder().applysettings(conf.getproperties()).build();
    sf = conf.buildsessionfactory(st);
    try {
      sess = sf.opensession();
      tx = sess.begintransaction();
      //在hql查询中使用delete进行批量删除,下面的的语句是hql语句,不是sql
      query query = sess.createquery("delete student");//也可以是delete from,from关键字是可选的,可以不要,加条件的时候可以指定类的别名
      query.executeupdate();
      tx.commit();
    } catch (exception e) {
      if (tx != null) {
        tx.rollback();
      }
    } finally {
      sess.close();
      sf.close();
    }
  }
  public static void main(string[] args) {
    new sessionutil().hibernatetest();
  }
}

(2)方式2:(强烈不推荐)

package com.anlw.util;
import java.sql.connection;
import java.sql.sqlexception;
import java.sql.statement;
import org.hibernate.cachemode;
import org.hibernate.query;
import org.hibernate.scrollmode;
import org.hibernate.scrollableresults;
import org.hibernate.session;
import org.hibernate.sessionfactory;
import org.hibernate.transaction;
import org.hibernate.boot.registry.standardserviceregistrybuilder;
import org.hibernate.cfg.configuration;
import org.hibernate.jdbc.work;
import org.hibernate.service.serviceregistry;
import com.anlw.entity.student;
public class sessionutil {
  configuration conf = null;
  serviceregistry st = null;
  sessionfactory sf = null;
  session sess = null;
  transaction tx = null;
  public void hibernatetest() {
    conf = new configuration().configure();
    st = new standardserviceregistrybuilder().applysettings(conf.getproperties()).build();
    sf = conf.buildsessionfactory(st);
    try {
      sess = sf.opensession();
      tx = sess.begintransaction();
      //查询表中的所有数据
      scrollableresults student = sess.createquery("from student")
          .setcachemode(cachemode.ignore)
          .scroll(scrollmode.forward_only);
      int count = 0;
      while(student.next()){
        student s = (student)student.get(0);
        sess.delete(s);
      }
      tx.commit();
    } catch (exception e) {
      if (tx != null) {
        tx.rollback();
      }
    } finally {
      sess.close();
      sf.close();
    }
  }
  public static void main(string[] args) {
    new sessionutil().hibernatetest();
  }
}

通过这种方式,虽然可以执行批量删除,但效果非常不好,执行效率不高,需要先执行数据查询,然后再执行数据删除,而且这种删除将是逐行删除,即每删除一行记录,都要执行一条delete语句,性能非常低;

2. 绕过hibernate,调用jdbc api

(1)方式1:

package com.anlw.util;
import java.sql.connection;
import java.sql.sqlexception;
import java.sql.statement;
import org.hibernate.query;
import org.hibernate.session;
import org.hibernate.sessionfactory;
import org.hibernate.transaction;
import org.hibernate.boot.registry.standardserviceregistrybuilder;
import org.hibernate.cfg.configuration;
import org.hibernate.jdbc.work;
import org.hibernate.service.serviceregistry;
import com.anlw.entity.student;
public class sessionutil {
  configuration conf = null;
  serviceregistry st = null;
  sessionfactory sf = null;
  session sess = null;
  transaction tx = null;
  public void hibernatetest() {
    conf = new configuration().configure();
    st = new standardserviceregistrybuilder().applysettings(conf.getproperties()).build();
    sf = conf.buildsessionfactory(st);
    try {
      sess = sf.opensession();
      tx = sess.begintransaction();
      sess.dowork(new work() {
        @override
        public void execute(connection arg0) throws sqlexception {
          string sql = "delete from student where age > 5"; //mysql中删除语句不能省略from
          statement st = arg0.createstatement();
          st.executeupdate(sql);
        }
      });
      tx.commit();
    } catch (exception e) {
      if (tx != null) {
        tx.rollback();
      }
    } finally {
      sess.close();
      sf.close();
    }
  }
  public static void main(string[] args) {
    new sessionutil().hibernatetest();
  }
}

2)方式2:

package com.anlw.util;
import java.sql.connection;
import java.sql.preparedstatement;
import java.sql.sqlexception;
import java.sql.statement;
import org.hibernate.query;
import org.hibernate.session;
import org.hibernate.sessionfactory;
import org.hibernate.transaction;
import org.hibernate.boot.registry.standardserviceregistrybuilder;
import org.hibernate.cfg.configuration;
import org.hibernate.jdbc.work;
import org.hibernate.service.serviceregistry;
import com.anlw.entity.student;
public class sessionutil {
  configuration conf = null;
  serviceregistry st = null;
  sessionfactory sf = null;
  session sess = null;
  transaction tx = null;
  public void hibernatetest() {
    conf = new configuration().configure();
    st = new standardserviceregistrybuilder().applysettings(conf.getproperties()).build();
    sf = conf.buildsessionfactory(st);
    try {
      sess = sf.opensession();
      tx = sess.begintransaction();
      sess.dowork(new work() {
        @override
        public void execute(connection arg0) throws sqlexception {
          string sql = "delete from student where age = ?"; //mysql中删除语句不能省略from
          preparedstatement ps = arg0.preparestatement(sql);
          for(int i=0;i<10;i++){
            if(i%2 == 0){
              ps.setint(1, i);
              ps.addbatch();
            }
            ps.executebatch();
          }
        }
      });
      tx.commit();
    } catch (exception e) {
      if (tx != null) {
        tx.rollback();
      }
    } finally {
      sess.close();
      sf.close();
    }
  }
  public static void main(string[] args) {
    new sessionutil().hibernatetest();
  }
}

希望本文所述对大家基于hibernate的java程序设计有所帮助。