当我学完这个之后 我仿佛都懂了 = =或许这就是 hibernate的力量吧.
操纵持久化对象(Session)
1.1. 在hibernate中java对象的状态
Hibernate 把对象分为 4 种状态:
¨ 持久化状态,
¨ 临时状态,
¨ 游离状态,
¨ 删除状态.
Session 的特定方法能使对象从一个状态转换到另一个状态
1.2. 临时对象(transient)
¨ 在使用代理主键的情况下, OID 通常为 null
¨ 不处于 Session 的缓存中
¨ 在数据库中没有对应的记录
1.2.1. 删除对象(Removed)
¨ OID 不为 null
¨ 从一个 Session实例的缓存中删除
¨ Session 已经计划将其从数据库删除, Session 在清理缓存时, 会执行 SQL delete 语句, 删除数据库中的对应记录
¨ 一般情况下, 应用程序不该再使用被删除的对象
1.2.2. 持久化对象(也叫”托管”)(Persist)
1.2.3.
¨ OID 不为 null
¨ 位于 Session 缓存中
¨ 持久化对象和数据库中的相关记录对应
¨ Session 在清理缓存时, 会根据持久化对象的属性变化, 来同步更新数据库
¨ 在同一个 Session 实例的缓存中, 数据库表中的每条记录只对应唯一的持久化对象
1.2.4. 游离对象(也叫”脱管”)(Detached)
¨ OID 不为 null
¨ 不再处于 Session 的缓存中
¨ 一般情况需下, 游离对象是由持久化对象转变过来的, 因此在数据库中可能还存在与它对应的记录
1.2.5. 对象的状态转换说明(图)
对象的状态转换图
测试hibernate中java对象的状态
程序代码 |
生命周期 |
状态 |
tx = session.beginTransaction(); Customer c = new Customer); |
开始生命周期 |
临时状态 |
Session.save(c) |
处于生命周期中 |
转变为持久化状态 |
Long id=c.getId(); c = null; Customer c2 = (Customer)session.load(Customer.class,id); tx.commit(); |
处于生命周期中 |
处于持久化状态 |
session.close(); |
处于生命周期中 |
转变为游离态 |
c2.getName(); |
处于生命周期中 |
处于游离态 |
c2 = null; |
结束生命周期 |
结束生命周期 |
1.2.6. 对象的状态总结
|
Session缓存存在对应的记录 |
数据中存在对应的记录 |
临时态 |
no |
no |
持久态 |
yes |
可能有也可能没有 |
游离态 |
no |
可能有(数据没有删除)也可能没有 |
1.2.7. 操纵持久化对象的方法(Session中)
1.2.8. save()
Session 的 save() 方法使一个临时对象转变为持久化对象。
¨ Session 的 save() 方法完成以下操作:
- 把 News 对象加入到 Session 缓存中, 使它进入持久化状态
- 选用映射文件指定的标识符生成器, 为持久化对象分配唯一的 OID. 在使用代理主键的情况下, setId() 方法为 News 对象设置 OID 使无效的.
- 计划执行一条 insert 语句,把Customer对象当前的属性值组装到insert语句中
¨ Hibernate 通过持久化对象的 OID 来维持它和数据库相关记录的对应关系. 当 News 对象处于持久化状态时, 不允许程序随意修改它的 ID
@Test public void save() throws Exception{ Session session = sessionFactory.openSession(); Transaction tc = null; User user = null; try { tc = session.beginTransaction(); user = new User();//临时状态 user.setName("张张"); session.save(user);//持久化状态 tc.commit(); } catch (Exception e) { tc.rollback(); throw e; }finally{ session.close(); } user.setName("王王");//游离状态 System.out.println(user.getName()); }
1.2.9. update()
Session 的 update() 方法使一个游离对象转变为持久化对象, 并且计划执行一条 update 语句。
@Test public void update() throws Exception{ Session session = sessionFactory.openSession(); Transaction tc = null; User user = null; try { tc = session.beginTransaction(); user = (User) session.get(User.class, 1); //session.clear(); //session.evict(user);//清楚某一个对象。 user.setName("冯芬1"); //session.update(user);//执行完才提交给数据库 session.flush();//一执行立即提交 System.out.println("执行"); tc.commit(); } catch (Exception e) { tc.rollback(); throw e; }finally{ session.close(); } }Session 的 update() 方法使一个游离对象转变为持久化对象, 并且计划执行一条 update 语句。
若希望 Session 仅当修改了 News 对象的属性时, 才执行 update() 语句, 可以把映射文件中 <class> 元素的 select-before-update(更新之前先查询) 设为 true. 该属性的默认值为 false
当 update() 方法关联一个游离对象时, 如果在 Session 的缓存中已经存在相同 OID 的持久化对象, 会抛出异常
原因是:两个不同的对象拥有相同的OID
当 update() 方法关联一个游离对象时, 如果在数据库中不存在相应的记录, 也会抛出异常
1.2.10. saveOrUpdate()
该方法同时包含save和update方法,如果参数是临时对象就用save方法,如果是游离对象就用update方法,如果是持久化对象就直接返回。
判定对象为临时对象的标准
¨ Java 对象的 OID 为 null
¨ 映射文件中为 <id> 设置了 unsaved-value 属性, 并且 Java 对象的 OID 取值与这个 unsaved-value 属性值匹配(在hbn3中基本用不到了)
@Test public void saveOrUpdate() throws Exception { Session session = sessionFactory.openSession(); Transaction tc = null; User user = null; try { tc = session.beginTransaction(); //临时对象执行插入 // user = new User(); // user.setName("洋洋"); // session.saveOrUpdate(user); //游离对象执行修改 // user = (User) session.get(User.class,1); // session.evict(user); // session.saveOrUpdate(user); //如果是持久化对象就直接返回,不执行操作 user = (User) session.get(User.class,1); session.saveOrUpdate(user); tc.commit(); } catch (Exception e) { tc.rollback(); throw e; }finally{ session.close(); } }
如果参数是临时对象就会用save方法
如果是游离对象就用update方法
如果是持久化对象就直接返回,不执行操作
判定对象为临时对象的标准
¨ Java 对象的 OID 为 null
¨ 映射文件中为 <id> 设置了 unsaved-value 属性, 并且 Java 对象的 OID 取值与这个 unsaved-value 属性值匹配,执行插入操作
根据以上判断临时对象的标准id=null是临时对象。但可以定义属性为int id
* 此时id默认值是0而不是null,应该执行更新操作
* 但实际我们要执行的插入操作。这时,可以在id中设置unsaved-value=0(默认值)
1.2.11. get()、load()
都可以根据给定的 OID 从数据库中加载一个持久化对象
@Test public void getOrLoad() throws Exception { Session session = sessionFactory.openSession(); Transaction tc = null; User user = null; try { tc = session.beginTransaction(); //get方式会马上执行sql语句 user = (User) session.get(User.class,1); System.out.println("aaaaa"); System.out.println(user.getName()); //load方式不会马上执行sql语句 user = (User) session.load(User.class,2); System.out.println("bbbbbbbbbbbb"); System.out.println(user.getName()); tc.commit(); } catch (Exception e) { tc.rollback(); throw e; }finally{ session.close(); } }
区别:
¨ 当数据库中不存在与 OID 对应的记录时, load() 方法抛出 ObjectNotFoundException 异常, 而 get() 方法返回 null
¨ 两者采用不同的延迟检索策略
get():获取数据,是持久化状态
1. 会生成:select ... where id=?
2. 会马上执行sql语句
3. 如果数据不存在,就返回null
load():获取数据,是持久化状态
1.会生成:select ... where id=?
2. load()后返回的是一个代理对象,要求类不能是final的,否则不能生成子类代理,就不能使用懒加载功能了。
3.让懒加载失效的方式:一、把实体写成final的;二、在hbm.xml中写<class ... lazy="false">
4. 不会马上执行sql语句,而是在第1次使用非id或class属性时执行sql。
5. 如果数据不存在,就抛异常:ObjectNotFoundException
1.2.12. delete()
Session 的 delete() 方法既可以删除一个游离对象, 也可以删除一个持久化对象。
¨ 如果参数是持久化对象,就执行一个delete语句,若为游离对象,先使游离对象被session关联,使他变为持久化对象
¨ 计划执行一条 delete 语句
¨ 把对象从 Session 缓存中删除, 该对象进入删除状态.
1.2.13. 与触发器协同工作
Session.save(c);
Session.flush();
Session.refresh(c);
------------------------------------------------------
触发器的行为导致缓存与数据库中的数据不一致。解决办法是执行完
操作后,立即调用session的flush方法和refresh方法,迫使缓存与
数据库同步。
Session的update操作方法盲目的激活触发器
如果游离状态的对象的属性和数据库一致,则更新操作是多余的。
为避免这种情况:
<class name=“” table=“” select-before-update=“true”>
……
</class>
1.2.14. DML(数据操作语言)风格的操作
,Hibernate 提供通过 Hibernate 查询语言(HQL)来执行大
批量 SQL 风格的 DML 语句的方法。
UPDATE 和 DELETE 语句的伪语法为:( UPDATE | DELETE ) FROM? EntityName (WHERE
where_conditions)?。
要注意的事项:
•在 FROM 子句(from-clause)中,FROM 关键字是可选的
•在 FROM 子句(from-clause)中只能有一个实体名,它可以是别名。如果实体名是别名,那么
任何被引用的属性都必须加上此别名的前缀;如果不是别名,那么任何有前缀的属性引用都是
非法的。
•不能在大批量 HQL 语句中使用 joins 连接(显式或者隐式的都不行)。不过在 WHERE 子句中
可以使用子查询。可以在 where 子句中使用子查询,子查询本身可以包含 join。
•整个 WHERE 子句是可选的。
使用 Query.executeUpdate() 方法执行一个 HQL UPDATE语句
由 Query.executeUpdate() 方法返回的整型值表明了受此操作影响的记录数量
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
String hqlDelete = "delete Customer c where c.name = :oldName";
// or String hqlDelete = "delete Customer where name = :oldName";
int deletedEntities = s.createQuery( hqlDelete )
.setString( "oldName", oldName )
.executeUpdate();
tx.commit();
session.close();
6.HQL介绍
SQL(表和字段) HQL(对象和属性)
使用HQL查询
HQL: Hibernate Query Language.
特点:
1,与SQL相似,SQL中的语法基本上都可以直接使用。
2,SQL查询的是表和表中的列;HQL查询的是对象与对象中的属性。
3,HQL的关键字不区分大小写,类名与属性名是区分大小写的。
4,SELECT可以省略.
案例:
1,简单的查询
hql = "FROM Employee";
hql = "FROM Employee AS e"; 使用别名
hql = "FROM Employee e"; 使用别名,as关键字可省略
执行查询
List list = session.createQuery(hql).list();
显示结果
while(itr.hasNext()){ //System.out.println(itr.next().getName()); Object[] object = (Object[]) itr.next(); System.out.println(object[0]+":"+object[1]); }
2,带上过滤条件的(可以使用别名):Where
hql = "FROM Employee WHERE id<10"; hql = "FROM Employee e WHERE e.id<10"; hql = "FROM Employee e WHERE e.id<10 AND e.id>5";
3,带上排序条件的:Order By
hql = "FROM Employee e WHERE e.id<10 ORDER BY e.name"; hql = "FROM Employee e WHERE e.id<10 ORDER BY e.name DESC"; hql = "FROM Employee e WHERE e.id<10 ORDER BY e.name DESC, id ASC";
4,指定select子句(不可以使用select *)
hql = "SELECT e FROM Employee e"; 相当于"FROM Employee e" hql = "SELECT e.name FROM Employee e"; 只查询一个列,返回的集合的元素类型就是这个属性的类型 hql = "SELECT e.id,e.name FROM Employee e"; 查询多个列,返回的集合的元素类型是Object数组 hql = "SELECT new Employee(e.id,e.name) FROM Employee e"; 可以使用new语法,指定把查询出的部分属性封装到对象中
5,执行查询,获得结果(list、uniqueResult、分页 )
Query query = session.createQuery("FROM Employee e WHERE id<3"); query.setFirstResult(0); query.setMaxResults(10); List list = query.list(); 查询的结果是一个List集合 Employee employee = (Employee) query.uniqueResult(); 查询的结果是唯一的一个结果,当结果有多个,就会抛异常 System.out.println(employee);
6,函数的使用
hql = "select count(id) from Department"; Number num = (Number) session.createQuery(hql).uniqueResult(); System.out.println(num);
7,分组查询
hql = "select d.name,count(d.name) from Department d group by d.name"; hql = "select d.name,count(d.name) from Department d group by d.name having count(d.name)>5";
8,参数查询
第一种:使用“?”
hql = "from Department d where d.id between ? and ? "; List list = session.createQuery(hql) .setParameter(0, 2) .setParameter(1, 8) .list();
第二种:使用变量名
hql = "FROM Employee e WHERE id BETWEEN :idMin AND :idMax"; List list = session.createQuery(hql)// .setParameter("idMax", 15)// .setParameter("idMin", 5)// .list();
第三种:当参数是集合时,使用setParameterList()设置参数值
hql = "FROM Employee e WHERE id IN (:ids)"; List list = session.createQuery(hql)// .setParameterList("ids", new Object[] { 1, 2, 3, 5, 8, 100 })// .list();
9在映射文件配置HQL语句
为了使程序具有更大的灵活性,Hibernate可以在映射文件中配置HQL语句。如下所示为在Student.hbm.xml中的配置。
<hibernate-mapping> <class name="hibernate.ch06.Student" table="student" catalog="joblog"> <!--此处省略了配置--> </class> <query name="searchStudent"><![CDATA[ from Student s where s.sage>22 ]]>(<![CDATA[ ]]>表示一些特殊字符不需要转义) </query> </hibernate-mapping>
可以用如下代码访问配置文件中的HQL语句。
Session session=HibernateSessionFactory.currentSession();//创建Session Query query=session.getNamedQuery("searchStudent"); //用getNamedQuery得到查询 List list=query.list(); //执行查询 Iterator it=list.iterator(); while(it.hasNext()){ Student stu=(Student)it.next(); System.out.println(stu.getSname()); }
其中,getNamedQuery()函数用来访问映射文件Student.hbm.xml中配置的HQL语句,参数为配置的名称。
Select s.id,s.name, c.name from t_student s,t_classes c where c.id = s.classId
Select s.id,s.name, c.name from t_student s right join t_classes c on s.classtId = c.id;
10.连接查询
//第一种:(内连接) //hql = "select s.id,s.name,c.name from Student s join s.classes c"; //第二种: //hql = "select s.id,s.name,s.classes.name from Student s"; //外连接: hql = "select s.id,s.name,c.name from Student s right join s.classes c"; hql = "select s.id,s.name,c.name from Student s left join s.classes c";
11.更新
//更新前: Student student = (Student)session.get(Student.class, 2); System.out.println(student.getName()); int num = session.createQuery("update Student s set s.name=? where s.id=2") .setParameter(0,"好人1") .executeUpdate(); System.out.println(num); //更新后: session.refresh(student); System.out.println(student.getName());
12.删除
/*int num1 = session.createQuery("delete Student s where s.id=1") .executeUpdate(); System.out.println(num1);*/
Criteria查询方式
// 创建Criteria对象 Criteria criteria = session.createCriteria(Student.class); // 增加过滤条件 criteria.add(Restrictions.ge("id", 2)); criteria.add(Restrictions.le("id", 5)); // 增加排序条件 criteria.addOrder(Order.desc("id")); criteria.addOrder(Order.desc("name")); // 执行查询 // criteria.setFirstResult(0); // criteria.setMaxResults(100); // criteria.uniqueResult(); // criteria.list() List list = criteria.list(); Iterator itr = list.iterator(); while(itr.hasNext()){ Student student = (Student)itr.next(); System.out.println(student.getName()+":"+student.getScore()); }
写完了 今天落枕了 起床也是在床底睁开眼 歪着脖子写了折磨一一篇, 真难受啊 不过这质量算是我写过最棒的一篇了吧.