一、创建SessionFactory的两种方式:(将下面其中一种封装成getSessionFactory方法)
1、通过进行创建Configuration:
//创建配置对象
Configuration cfg=new Configuration();
cfg.configure("hibernate.cfg.xml");
//创建session工厂
return cfg.buildSessionFactory();
2、通过服务注册类实现
StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.configure("hibernate.cfg.xml")
.build();
SessionFactory sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
二、创建一个Main测试类:
public static void main(String[] args) {
//获取session工厂
SessionFactory factory = getSessionFactory();
//打开一个新的session
Session session=factory.openSession();
//开始事务
Transaction t=session.beginTransaction();
//这里写操作数据库的代码(下面的测试代码均在此处写)
//提交事务
t.commit();
//关闭session
session.close();
//关闭session工厂
factory.close();
}
三、测试保存或更新api
Integer index = (Integer)session.save(employee);//返回数据库中的主键Id
session.persist(employee);//没有返回值
Object o = session.merge(employee);//返回整个对象
session.saveOrUpdate(employee);//没有返回值,如果有主键那么更新,没有则插入新纪录
注意上述的各种方法都会将对象存入到一级缓存session中(其实就是一个Map结构"EntityKey[domain.Employee#112]" -> obj,在变量persistenceContext中),此时的对象都是持久态的
四、各种查询
Employee employee = session.find(Employee.class,101);//直接跟进id查询
employee.setLastName("xtz");持久化的对象在提交事务后会主动把结果更新的到数据库
Employee employee = session.load(Employee.class,101);//通过id查询,通过懒加载的方式 employee.setLastName("jeff");//使用到这个对象的时候,才发送查询sql,同样的,在关闭事务也会刷线到数据库中
HQL Query<Employee> query = session.createQuery("from domain.Employee");//创建查询,可以加where order by 等,但是不能加limit
query.setMaxResults(10);//记录数,用于分页
query.setFirstResult(11);//记录开始的下标,从0开始,用于分页 List<Employee> list = query.list();//查询
使用具名参数: (我的hinernate 版本hibernate-core-5.4.5.Final.jar)
from domain.Employee where id = :id
query.setString("id","101");//这个版本已经不推荐使用了,代替的方案如下:
query.setParameter("id",101, IntegerType.INSTANCE);//什么类型就用xxxType.INSTANCE
使用Criteria对象
Criteria criteria = session.createCriteria(Employee.class); criteria.add(Restrictions.eq("id",101)); List<Employee> list = criteria.list();//不够这个版本已经不这样使用了,在后续的版本中会被移除
替代方式: https://stackoverflow.com/questions/40720799/deprecated-createcriteria-method-in-hibernate-5
//首先获取CriteriaBuilder CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder(); //获取CriteriaQuery对象 CriteriaQuery<Employee> criteriaQuery = criteriaBuilder.createQuery(Employee.class); //用于条件查询 Root<Employee> root = criteriaQuery.from(Employee.class); //拿id=101的记录 criteriaQuery.select(root).where(root.get("id").in(101)); //创建query对象 Query<Employee> query1 = session.createQuery(criteriaQuery); List<Employee> employees = query1.list();
使用本地sql
Query<Employee> query = session.createSQLQuery("select * from tb_employee where id = :id");
query.setParameter("id",101, IntegerType.INSTANCE);//设置具名参数
List<Employee> list = query.list();
五、hibernate的三种对象状态
1、瞬时态,(new 出来的对象处于瞬时态)
2、游离态,(数据库中存在,但是session中不存在的对象)
3、持久态,(数据库中存在,同时session中也存在的对象)
这里我提出一个问题,就是瞬时态和游离态的区分,感觉界限不太明显。持久态的最好区分,就是数据库中和都存在的实体,比如你save、find、load、list等等都是会把实体存在session中,此时就是持久态了。但是比如持久态的对象调用session的clear、evict、close等方法,都会将实体移除session,那么此时的实体,跟数据库是对应的,比如他们的主键是一样。那么这个对应就是游离态的话。存在一种情况,我new一个对象(将游离态的实体传入赋值),那么这个新new的对象是瞬时态的还是游离态的呢?(这个是我一直不太理解的地方,知道的大神麻烦指点一下)(其实可不可这样理解,就针对实体的主键而言,如果session的有一个实体和数据库实体主键一致,那么这个session的实体就是持久态;如果一个实体不存在session中,同时它的的主键在数据库中有一条记录跟它对应,那么这个就是游离态的实体;如果一个实体不存在主键或者主键在数据库中找不和它相对的记录,那么这个就是瞬时态)
六、在工作记得,在一个会话中,如果如果操作多张表,比如A表和B表。A表呢,你需要返回一些数据,然后你通过find的方式找到entity,然后你在entity中某个字段的值改了,比如image="www.xxxx.jpg",你要加水印,改了image="www.xxxx.jpg-image_big"
然后你返回给前端,就可以展示有水印的图片。一开始你发现没啥问题的,但是突然又有一个需求,说是要对这个请求进行记录,比如要保存这个请求的访问时间啥的,那么就需要往B表插入一条数据。此时你会发现A表中,数据库image的值也被改了。
这是因为,当持久态的实体,被修改后,执行flush、session.close等操作,会将数据更新到数据库中(工作中被坑过几次)。