第十六章 批量插入,多类分页查询
批量插入
有时候我们需要做导入的功能,那么这个时候就需要批量插入数据到数据库,在Hibernate中怎么样达到一个批量插入的效果呢,很简单,请看下面的示例:
我们还是以学生班级为例子
请看下面的配置文件:
Student.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="chapter2.model">
<class name="Student" table="students">
<id name="id" type="string">
<column name="id" length="32" />
<generator />
</id>
<property name="name" type="string">
<column name="name" length="20" />
</property>
<property name="age" type="integer">
<column name="age" />
</property>
<property name="birthday" type="date">
<column name="birthday" length="10" />
</property>
<many-to-one name="myclass" length="32" />
</many-to-one>
</class>
</hibernate-mapping>
Myclass.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="chapter2.model">
<class name="Myclass" table="my_class">
<id name="id" type="string" column="id" length="32">
<generator />
</id>
<property name="name" type="string">
<column name="name" length="20" />
</property>
<set name="students">
<key column="class_id" />
<one-to-many />
</set>
</class>
</hibernate-mapping>
可以看到现在的配置文件和以前有点不一样了,可以看到这里:
<hibernate-mapping package="chapter2.model">
我们给标签加了一个package属性,这里指定了一个包名,那么此时在此文件中就可以不在引用包名,而可以直接使用类名.像我们以前
name="chapter1.model.Student"简写为: class name="Student"
还有就是指定属性类型时的变化:
以前写法: property name="name" type="java.lang.String"
现在写法: property name="name" type="string"
但是请看清楚java.lang.String和string的区别,一个大写,一个小写,可以使用alt+/自动提示将简写的代码提示出来,以下是几个常用的对应关系.
java.lang.String? string
java.lang.Integer? integer
java.util.Date? date
接下来,我们需要做一个操作,向数据库插入十万个学生信息,如果我们还是像以下面的create方法来插入数据,性能上肯定会有很大的问题,因为此时一个事务开始与提交之间只插入了一条数据
public void create(Student student) throws Exception {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
session.save(student);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
}
Hibernate中怎么样批量插入数据呢?
设置批量大小开关:
<property name="jdbc.batch_size">20</property>
保证插入动作在一个事务内完成, 通常批量插入用在导入功能上, 请看下面的示例:
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
Customer customer = new Customer(.....);
session.save(customer);
if ( i % 20 == 0 ) { //20, same as the JDBC batch size //20,与JDBC批量设置相同
//flush a batch of inserts and release memory:
//将本批插入的对象立即写入数据库并释放内存
session.flush();
session.clear();
}
}
tx.commit();
批量操作的核心就在于这一块
if ( i % 20 == 0 ) { //20, same as the JDBC batch size //20,与JDBC批量设置相同
//flush a batch of inserts and release memory:
//将本批插入的对象立即写入数据库并释放内存
session.flush();
session.clear();
}
因为在一个事务范围内,只有当tx.commit();事务提交时,数据才会保存到数据库中,并且我们还知道,在一个事务范围内,会有一级缓存存在,当你save一个对象时,就会保存一个对象到一级缓存,如果一级缓存内的对象容量超过了内存剩余容量大小时,就会出现内存溢出的问题,这时,我们就需要到达一定数量的时候就同步数据库,
session.flush();//刷新缓存,将缓存中的内容同步到数据库中
session.clear();//强制清除缓存
这就是批量操作的一个重点.
批量插入的代码:
public void batchCreate(Myclass myclass) throws Exception {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
for (int i = 0; i < 1000; i++) {
Student student = new Student(myclass, "张三" + i, i, new Date());
session.save(student);
if (i % 20 == 0) {
session.flush();
session.clear();
}
}
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
}
多类分页查询:
public List<Student> findByPage(int pageSize, int currentPageNo)
throws Exception {
Session session = null;
Transaction transaction = null;
List<Student> list = new ArrayList<Student>();
try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
Query query = session
.createQuery("from Student as s,Myclass as m where s.myclass.id = m.id");
query.setFirstResult((currentPageNo - 1) * pageSize); // 设置开始行数
query.setMaxResults(pageSize); // 设置每页大小
List<Object[]> temp = query.list(); // //这里每一行都是一个1维数组
for (int i = 0; i < temp.size(); i++) {
Object[] objtemp = temp.get(i);
Student student = (Student) (objtemp[0]);
student.setMyclass((Myclass) objtemp[1]);//这一句其实可以不需要
list.add(student);
}
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
return list;
}
一定要记住,返回的是一个Object[]数组,塞值给对象时,要记住强转.