Hibernate分批插入数据后数据条目不一致

前几天在学习Hibernate批量插入数据时遇到了一个问题:原定插入100条数据,但是数据库中只有81条数据。

今天查了一下资料,发现了问题所在,总结如下



在实际应用中,有时需要同时向数据库中插入多条记录,每一条记录对应的持久化对象在保存到数据库之前,暂时存储在Session缓存中,但是如果存储的对象过多,程序可能会运行失败,并抛出OutOfMemoryException(内存溢出异常);为了解决这个问题,可以对要存储的数据进行分批存储。



例如:每插入20条数据,就提交一次事务,然后清空Session缓存。演示如下:



持久化类:Customer.class   主键生成方式:native



package pojo;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

public class Customer implements Serializable{
	private Integer id;
	private String userName;
	private String password;
	private String realName;
	private String address;
	private String mobile;
	private IdCard idCard;
	
	private Set<Order> orders=new HashSet<Order>(0);
	
	public IdCard getIdCard() {
		return idCard;
	}
	public void setIdCard(IdCard idCard) {
		this.idCard = idCard;
	}
	public Set<Order> getOrders() {
		return orders;
	}
	public void setOrders(Set<Order> orders) {
		this.orders = orders;
	}
	public Customer(String userName,String password,String realName,
			String address,String mobile)
	{
		this.userName=userName;
		this.password=password;
		this.realName=realName;
		this.address=address;
		this.mobile=mobile;
	}
	public Customer()
	{
		
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getRealName() {
		return realName;
	}
	public void setRealName(String realName) {
		this.realName = realName;
	}
	public String getAddress() {
		return address;
	}
	public void setAddress(String address) {
		this.address = address;
	}
	public String getMobile() {
		return mobile;
	}
	public void setMobile(String mobile) {
		this.mobile = mobile;
	}
}



<span style="font-size:24px;">测试类:InsertTest.class</span>

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public class InsertTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		//Configuration对象实例化
		Configuration configuration=new Configuration();
		//解析并加载配置文件
		configuration.configure("hibernate.cfg.xml");
		//创建SessionFactory对象
		SessionFactory sessionFactory=configuration.buildSessionFactory();
		//创建Session对象
		Session session=sessionFactory.openSession();
		//打开事务
		Transaction trans=session.beginTransaction();
		//进行插入操作	
		for(int i=0;i<100;i++)
		{
			Customer customer=new Customer();
			customer.setUserName(""+(i));
			customer.setPassword(""+i);
			session.save(customer);	
			if(i%20==0)
			{					
				session.flush();
				session.clear();					
				trans.commit();
				trans=session.beginTransaction();
			}
		}			
		//关闭Session对象
		session.close();
	}

}

运行结果如图:

数据库如下图:

可以从我标出的箭头看到,数据库里只有81条数据,而不是100条。


为什么会出现这种结果呢?


原因是for循环从0开始计数,数据库主键从1开始生成,当i=80时,存储的是第81个对象,此时i=80,80能被20 整除,因此提交了一次事务,Session缓存中的数据被插入到数据库中,for循环进入下一次循环,而i=81到i=99之间没有能被20整除的数,所以,虽然编号在82--99之间的18个对象虽然存储在Session缓存中,却没有被持久化到数据库中。


同时,因为Customer实体的主键生成方式为native,所以调用Session对象的save方法时Hibernate向数据库发送并执行了与对象相对应的insert语句,但是编号在82-99之间的对象的Insert操作完成后没有提交事务,所以数据没有保存到数据库中,但是主键依然增长了。


所以如果此时向数据库中插入数据的话,主键值会从101开始



再次向数据库插入10条数据,结果如图:


可以看到第二次插入的10条数据的第一条数据的ID值是101,这表明虽然没有插入ID值在82-100之间的数据,主键依然增长了。


这就验证了上面所说的,Hibernate向数据库发送并执行了编号在82-100之间的这18条数据的Insert语句,但是没有提交事务,所以数据没有被保存,而主键增长了。


至此就是出现插入100条数据,数据库中却只有81条数据的原因分析。



解决这个问题的办法很简单,就是在For循环执行结束后再提交一次事务。

    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值