hibernate之加载策略
1. 对象(hibernate管理的对象)的三种状态:临时状态、持久状态、游离状态
a、hibernate通过管理对象来操作数据库,这里对象指的是持久态的对象
b、各种状态的对象是可以相互转换
2、一级缓存与快照
一级缓存又被成为session级别的缓存,相当于数据库中的某条数据在hibernate产生一个快照,并且将值封装进对象里,如果说对象发生了改变,那么它会与之前的hibernate中的快照进行对比,如果不一致,那么就会修改数据库中的数据,以下代码可体现:
package com.zking.three.test;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import com.zking.one.entity.User;
public class Demo1 {
public static void main(String[] args) {
Configuration cfg=new Configuration().configure();
SessionFactory sessionFactory=cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
User user = session.get(User.class, 3);//根据ID将user查出来
user.setUserName("小明");//给user重新赋一个name
transaction.commit();//提交事务
session.close();//关闭session
}
}
运行后数据库里的数据就会发生改变
3. 加载策略
a、立即加载,即session的get方法
b、延迟加载(懒加载),懒加载就是将查询的oid(object id)保存到session的代理proxy中,当真正要用到查询的对象时,再去执行查询的SQL语句,即session的load方法
package com.zking.three.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.zking.one.entity.User;
import com.zking.two.entity.Student;
import com.zking.two.util.SessionFactoryUtil;
public class UserDao {
/**
* 立即加载
* @author LJ
* @Date 2018年10月22日
* @Time 下午3:02:01
* @param user
* @return
*/
public User getUser(User user) {
Session session = SessionFactoryUtil.getSession();
Transaction transaction = session.beginTransaction();
User u = session.get(User.class, user.getId());
transaction.commit();
SessionFactoryUtil.closeSession();
return u;
}
/**
* 懒加载(延时加载)
* @author LJ
* @Date 2018年10月22日
* @Time 下午2:57:14
* @param user
* @return
*/
public User loadUser(User user) {
Session session = SessionFactoryUtil.getSession();
Transaction transaction = session.beginTransaction();
User u = session.load(User.class, user.getId());
transaction.commit();
SessionFactoryUtil.closeSession();
return u;
}
/**
* 并发修改例子所用
* @author LJ
* @Date 2018年10月23日
* @Time 下午1:44:58
* @param student
*/
public void updateStudent(Student student) {
Session session = SessionFactoryUtil.getSession();
Transaction transaction = session.beginTransaction();
session.update(student);
transaction.commit();
SessionFactoryUtil.closeSession();
}
}
测试立即加载:
@Test
public void testGetUser() {
User user=new User();
user.setId(3);
User u = new UserDao().getUser(user);
System.out.println(u.getUserName());
}
效果:
测试懒加载:
@Test
public void testLoadUser() {
User user=new User();
user.setId(3);
User u = new UserDao().loadUser(user);
System.out.println(u.getUserName());
}
效果:
报LazyInitializationException异常,是因为懒加载是当真正要用到查询的对象时,再去执行查询的SQL语句,但这时session已经关闭了,所以会出现异常
4、并发控制
业务场景:不同的两个用户同时对同一条数据进行修改,后提交的信息会覆盖先提交的信息,针对这一现象,hibernate提供了解决方法,就是在数据库里和实体类里加一个version列段(数据库里该列段须为int类型,默认值为1),再在xml里进行配置
注:配置时version属性要放在property属性的前面
测试:
@Test
public void testUpdateStudent() {
Student student=new Student();
student.setSid(5);
student.setVersion(2);
student.setSname("刘备");
new UserDao().updateStudent(student);
}
每一次修改成功后,数据库里version会自增1,若修改时version的值没有与数据库里的对应则会报错:ERROR: HHH000346: Error during managed flush [Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.zking.two.entity.Student#5]]