// configuration hibernate - 获取Hibernate配置对象
String configPathByClassPath = "hibernate.cfg.xml";
Configuration cfg = new Configuration().configure(configPathByClassPath);
// 1.byXmlMapping -> *.hbm.xml - 1. Xml 映射方式
// add hibernate's mapping file (*.hbm.xml) from programmatically
// - 硬编码方式加入 xml映射文件到Hibernate的Configuration对象中
String mappingFileByClassPath = "";
cfg.addResource(mappingFileByClassPath);
// 2. byAnnotationMapping -> JPA Annotation (etc. @Entity)
// - 注解方式映射(JPA注解)
AnnotationConfiguration acfg = new AnnotationConfiguration().configure(configPathByClassPath);
// add hibernate's mapping file (entityClass) from programmatically
// - 硬编码方式加入 映射实体类到Hibernate的Configuration对象中
//acfg.addAnnotatedClass(Entity.class);
//build SessionFactory from Configuration Object
// - 根据Configuration对象构建SessionFactory对象
SessionFactory sf = cfg.buildSessionFactory();
// openSession(): Always return new Session Object.
// - openSession方法:总是返回一个新的Session对象.
Session session = sf.openSession();
// getCurrentSession():First get Session in SessionContext, if return null, then create new Session.
// - getCurrentSession方法:首先到Session上下文对象中去寻找需要的Session对象,如果没有找到,则创建Session并返回
//(etc. ThreadLocalSessionContext:在一个线程内总是只返回一个相同的Session对象)
session = sf.getCurrentSession();
// 首先返回一个CGLib by lazy loading的代理对象
// 当该实体真正被使用时, load 会在2级、一级缓存中加载实体对象,
// 如果实体不存在, 再去数据库查找数据, 而此时数据库也不存在的话,则抛出org.hibernate.ObjectNotFoundException
//session.load(Entity.class, pkValue);
// get 也会先在2级、一级缓存中加载实体对象,如果实体不存在,即到数据库中去查询,此时数据库也不存在的话,则返回null
//session.get(Entity.class, pkValue);
//Entity从Session获取后, 内部的Collection属性都变成Hibernate内部集合实现类用以完成Lazy Load.
// ---------- XML Configuration ------
//Hibernate3多了fetch属性,有两种状态select和join.
//当fetch=select的时候,我们查询从表数据时候,首先会根据主表查处主表对象,然后根据主表id生成另一个select语句去查询从表数据,产生1+N的查询效果
//当fetch=join的时候,hibernate会自动用一条外连接语句同时查询主表和从表数据
//cascade和inverse的区别:
//cascade定义的是关系两端对象到对象的级联关系. 而inverse定义的是关系和对象的级联关系
//inverse只对set+one-to-many(或many-to-many)有效, 对many-to-one, one-to-one无效. cascade对关系标记都有效.
// ---------- Query ---------------
// list默认不使用一、2级缓存,并且会往2级缓存中加入数据, 但是查询的时候并不使用2级缓存
// 可配置查询缓存, 这样就可让list也使用2级缓存
// iterator 默认使用1、2级缓存.
// ------------ Lock --------------------
// a) LockMode.None: 无锁的机制,Transaction结束时,切换到此模式
// b) LockMode.READ: 在查询的时候,Hibernate会自动获取锁
// c) LockMode.WRITE: insert、update实体时, hibernate会自动获取锁
// - 以上3中锁的模式,是hibernate内部使用的
// d) LockMode.UPGRADE: 查询时,对数据行加锁。利用数据库for update子句(悲观锁)
// 依靠数据库提供的锁机制方式。(也只有数据库层提供的锁机制才能真正保证数据访问的排它性,
// 否则, 即使在本地系统中实现了加锁机制, 也无法保证外部系统不会修改数据.)
// e) LockMode.UPGRADE_NOWAIT: Oracle 支持的锁方式
// Entity entity = session.load(Entity.class, pkValue, LockMode.UPGRADE);
//一个典型的依赖数据库的悲观锁调用:
// select * from account where name='Erica' for update
//这条SQL语句锁定了 account 表中所有符合检索条件 (name='Erica')的记录.
//本次事务提交之前(事务提交时会释放事务过程中的锁), 外界无法修改这些记录.
//Hibernate悲观锁实现(依赖与数据库锁机制):
// Query query = session.createQuery("from TUser where user.name='Erica'");
// query.setLockMode("user", LockMode.UPGRADE); -- 获取锁
// List userList = query.list();
//-- 释放锁