Hibernate 笔记总结

zjhdreams

贡献于2014-09-23

字数:28953 关键词: Hibernate 持久层框架

 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn u hibernate是什么? 1. hibernate 是一个框架(framework) 2. hibernate 是一个orm框架 [] l orm (object relation mapping) 对象关系映射 框架 o object -> 业务层(只对对象操作) r relation-> 关系数据库 m mapping 对象关系映射文件 3. hibernate 处于我们项目的持久层位置(正因为如此,所以有人又把hibernate称为 持久层框架) 4. hibernate 实际上就是对jdbc进行了轻量级的封装. 5. hibernate 的基础还是我们java 反射机制 l 除了hiberante 这个orm框架,还有一些: apache ojb / toplink / ibatis / ejb cmp Apache OJB ()   Cayenne ()   Jaxor ()   Hibernate ()   iBatis ()   jRelationalFramework ()   mirage ()   SMYLE ()   TopLink () 把对象持久化: 把对象的信息保存到数据库或者是文件. 总结: hibernate 是对jdbc进行轻量级封装的 orm 框架,充当项目的持久层. u 为什么需要hibernate? u 快如入门案例: hiberante 可以用在 j2se 项目,也可以用在 j2ee (web项目中) struts是web框架,所以用在 web项目 我们使用手动配置hibernate方式开发一个hibernate 项目,完成crud操作 。 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn 开发流程 1. 创建一个项目 2. 画出一个简单项目框架示意图 3. 引入hibernate 开发包 (从网上下载 google hibernate http://www.hibernate.org),完后我们 4. 开发hibernate 有三种方法(开发顺序) 我们使用第二种开发项目 创建employe 表. create table employee( id number primary key, name varchar2(64) not null, email varchar2(64) not null, hiredate date not null) 创建一个序列,将来用于主键的自增长 : --创建一个序列 create sequence emp_seq start with 1 increment by 1 minvalue 1 nomaxvalue nocycle nocache 5. 开发domain对象和对象关系映射文件 对象关系映射文件: 作用是用于指定 domain对象和表的映射关系. ,该文件的取名有规范: domain对象.hbm.xml,一般我们放在 和domain对象同一个文件夹下(包下) 我们的Employee.hbml.xml配置文件 : emp_seq 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn 6. 手动配置我们的hibernate.cfg.xml文件,该文件用于配置 连接的数据库的类型,driver, ,用户名,密码 ,url ....同时管理 对象关系映射文件 ,该文件的名称,我们一般不修改. hibernate.cfg.xml配置文件 oracle.jdbc.driver.OracleDriver scott tiger jdbc:oracle:thin:@127.0.0.1:1521:orclhsp org.hibernate.dialect.OracleDialect true 7. 测试文件TestMain.java package com.hsp.view; import com.hsp.util.*; import java.util.Date; 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.*; import com.hsp.domain.Employee; public class TestMain { /** * @param args */ public static void main(String[] args) { //查询[load]->hql语句(hibernate query language) } public static void delEmp() { //删除 //获取一个session Session session=MySessionFactory.getSessionFactory().openSession(); Transaction ts=session.beginTransaction(); //删除1.先获取该雇员,然后删除 Employee emp=(Employee) session.load(Employee.class, 3); session.delete(emp); ts.commit(); session.close(); } public static void updateEmp() { // TODO Auto-generated method stub //修改用户 //获取一个会话 Session session=MySessionFactory.getSessionFactory().openSession(); Transaction ts=session.beginTransaction(); //修改用户1. 获取要修改的用户,2.修改 //load是通过主键属性,获取该对象实例.<--->表的记录对应 Employee emp=(Employee) session.load(Employee.class, 3); emp.setName("韩顺平8");//update... emp.setEmail("abc@sohu.com"); ts.commit(); session.close(); 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn } public static void addEmployee() { //我们使用hibernate完成crud操作[这里我们只见对象,不见表] //现在我们不是用service ,直接测试. //1。创建Configuration,该对象用于读取hibernate.cfg.xml,并完成初始化 Configuration configuration=new Configuration().configure(); //2.创建SessoinFactory[这是一个会话工厂,是一个重量级的对象] SessionFactory sessionFactory=configuration.buildSessionFactory(); //3.创建Sessoin 相当于jdbc Connection[ servelt HttpSession ,也不是 jsp session] Session session=sessionFactory.openSession(); //4.对hiberate而言,要求程序员,在进行 增加,删除,修改的时候使用事务提交, Transaction transaction = session.beginTransaction(); //添加一个雇员 Employee employee=new Employee(); employee.setName("shunping"); employee.setEmail("shunping@sohu.com"); employee.setHiredate(new Date()); //insert ............. //保存 session.save(employee);//save employee就是持久化该对象 (把对象保存到了数据库中称为一条记录) //==>insert into ....[被hiberante封装] //提交 transaction.commit(); session.close(); } } u 现在我们体验一下hibernate切换数据库的优势. 这次,我们使用 让hibernate自动完成 domain->映射文件->表 的工作. 1. 首先我们把 hibernate.cfg.xml文件重新配置. com.mysql.jdbc.Driver 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn root root jdbc:mysql:/localhost:3306/test org.hibernate.dialect.MySQLDialect true create 2. 对对象映射文件,做了相应的修改. 笔试题: 请列举出hibernate常见的接口和类 ?请解释什么事pojo类,它有什么要求: 1. pojo类是和一张表对应 2. 一般我们放在 com.xxx.domain下 3. pojo 需要一个主键属性(用于标示一个pojo对象) 4. 除了主键属性外,它应当还有其属性,属性的访问权限是private 5. 提供 set /get 方法 6. 它应当有一个无参的构造方法(hibernate 反射) 7. pojo类其实就是javabean/ 有些老程序员 叫他 date对象 上机练习: 写一个简单的雇员管理系统. emp( id , name , tel , birthday ), 可以,进入主界面 请选择数据库类型 1. 表示 连接 oracle 2. 表示 连接 mysql 3. 表示 连接 sql server 请选择操作 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn 1. 显示所有雇员 2. 根据id查询指定雇员 3. 修改雇员信息(请先输入id) 4. 根据id 删除雇员. * 用户可以多次选择操作. u hibernate的核心类和接口 ① Configuration 类 它的用处是: 1. 读取hibernate.cfg.xml 2. 管理对象关系映射文件 3. 加载hibernate 的驱动,url ,用户.. 4. 管理hibernate配置信息 ② hibernate.cfg.xml ③ 对象关系映射文件 ④ SessionFactory (会话工厂) 1. 可以缓存sql语句和数据(称为session级缓存)!! 2. 是一个重量级的类,因此我们需要保证一个数据库,有一个SessionFactroy 这里我们讨论一个通过SessionFactory 获取 Session的两个方法 openSession() 一个 getCurrentSession(); 1. openSession() 是获取一个新的session 2. getCurrentSession () 获取和当前线程绑定的session,换言之,在同一个线程中,我们获取的session是同一session,这样可以利于事务控制 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn 如果希望使用 getCurrentSession 需要配置 hibernate.cfg.xml中配置. 3. 如何选择 原则: ①如果需要在同一线程中,保证使用同一个Session则,使用getCurrentSession() ②如果在一个线程中,需要使用不同的Session,则使用opentSession() 4. 通过 getCurrentSession() 获取的session在事务提交后,会自动关闭,通过openSession()获取的session则必须手动关闭 5. 如果是通过getCurrentSession() 获取 sesssion ,进行查询需要事务提交. 全局事务和本地事务 jndi l 如何确定你的session有没有及时关闭 windows cmd netstat –an [oracle 1521 mysql 3306 sql server 1433] linux/unix netstat –anp top ⑤ session接口 它的主要功能和作用是: 1. Session一个实例代表与数据库的一次操作(当然一次操作可以是crud组合) 2. Session实例通过SessionFactory获取,用完需要关闭。 3. Session是线程不同步的(不安全),因此要保证在同一线程中使用,可以用getCurrentSessiong()。 4. Session可以看做是持久化管理器,它是与持久化操作相关的接口 u get vs load 1. 如果查询不到数据,get 会返回 null,但是不会报错, load 如果查询不到数据,则报错ObjectNotFoundException 2. 使用get 去查询数据,(先到一级/二级)会立即向db发出查询请求(select ...), 如果你使用的是 load查询数据,(先到一级、二级))即使查询到对象,返回的是一个代理对象,如果后面没有使用查询结果,它不会真的向数据库发select ,当程序员使用查询结果的时候才真的发出select ,这个现象我们称为懒加载(lazy) 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn 3. 通过修改配置文件,我们可以取消懒加载 4. 如何选择使用哪个: 如果你确定DB中有这个对象就用load(),不确定就用get()(这样效率高) u 我们对获取session的工具类,升级,让它可以直接返回 全新的session和线程相关的session 代码: package com.hsp.util; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; final public class HibernateUtil { //SqlHelper private static SessionFactory sessionFactory=null; //使用线程局部模式 private static ThreadLocal threadLocal=new ThreadLocal(); private HibernateUtil(){}; static { sessionFactory=new Configuration().configure("com/hsp/config/hsp.cfg.xml").buildSessionFactory(); } //获取全新的全新的sesession public static Session openSession(){ return sessionFactory.openSession(); } //获取和线程关联的session public static Session getCurrentSession(){ Session session=threadLocal.get(); //判断是否得到 if(session==null){ session=sessionFactory.openSession(); //把session对象设置到 threadLocal,相当于该session已经和线程绑定 threadLocal.set(session); } return session; } } 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn u query接口 通过query接口我们可以完成更加复杂的查询任务. 举例: 通过用户来查询数据. 快如入门 : Session session=HibernateUtil.getCurrentSession(); Transaction ts=null; try { ts=session.beginTransaction(); //获取query引用[这里 Employee不是表.而是domain类名] //[where 后面的条件可以是类的属性名,也可以是表的字段,安照hibernate规定,我们还是应该使用类的属性名.] Query query=session.createQuery("from Employee where namehsp='shunping'"); //通过list方法获取结果,这个list会自动的将封装成对应的domain对象 //所以我们jdbc进行二次封装的工作没有. List list=query.list(); for(Employee e: list){ System.out.println(e.getAaaid()+" "+e.getHiredate()); } ts.commit(); } catch (Exception e) { if(ts!=null){ ts.rollback(); } throw new RuntimeException(e.getMessage()); }finally{ //关闭session if(session!=null&&session.isOpen()){ session.close(); } } u criteria 接口的简单使用 快如入门: Session session=HibernateUtil.getCurrentSession(); Transaction ts=null; try { 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn ts=session.beginTransaction(); Criteria cri=session.createCriteria(Employee.class). setMaxResults(2).addOrder(Order.desc("id") ); List list=cri.list(); for(Employee e: list){ System.out.println(e.getAaaid()); } ts.commit(); } catch (Exception e) { if(ts!=null){ ts.rollback(); } throw new RuntimeException(e.getMessage()); }finally{ //关闭session if(session!=null&&session.isOpen()){ session.close(); } } u 如何使用eclipse进行hibernate 快速开发 我们以前面讲的对employee表进行crud为例,演示具体用法 手动配置: db(table )-> 手写domain对象->对象关系映射文件 现在我们希望用工具完成 Domain对象和 关系映射文件的工作. 1. 创建web项目 2. 通过myeclipse 提供 数据库浏览器连接到我们的oracle数据库(多人开发) 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn * 这里请大家小心,如果我们测试 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn 你们把自己的数据库通过 db 浏览器连接上 引入hibernate开发包.,同时自动创建hibernate.cfg.xml文件,如果希望把hibernate开发包升级,我们可以重新引入包. 下面我们使用myeclipse提供的逆向工程,自动的创建domain类和对象关系映射文件. 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn java对象(属性) <---------1. java类型 2. hibernate types-------------> 表字段类型 拉通练习一把. u 为什么要学习hql(hibernate query language)->这个是官方推荐,功能强大 ? 删除 session.delete(对象) -> 批量删除 ? 添加 session.save session.persist ? 修改->批量修改 sessin.update(对象) 查询 对象 obj obj.setXXX(); ? 查询 load get 查询所有 性别是 男的雇员? 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn u hql的详解 为了讲解清楚,我模拟一个学生选课系统 ,创建三张表 从创建的三张表,我们看出: hibernate 设计者 推荐我们在设计表的时候,应当每张表有一个主键,而且该主键最好不含业务逻辑, product 表 id productNo name price 1 bi001 冰箱 1000 2 nj111 电脑 2000 我们现在使用hibernate工具,自动生成 domain 对象 和映射文件,如果我们的表有主外键的关系,则应当先映射主表,再映射从表 * uniqueResult方法 如果我们检索一个对象,明确知道最多只有一个对象,则建议使用该方法: 具体用法如下: Student s=(Student) session.createQuery("from Student where sid='20050003'").uniqueResult(); System.out.println(s.getSname()); *distinct的用法 过滤重复的记录 //比如,显示所有学生的性别和年龄. List list=session.createQuery("select distinct sage,ssex from Student").list(); for(int i=0;i list=session.createQuery("from Student where sdept in ('计算机系','外语系')").list(); //取出1. for 增强 for(Student s:list){ System.out.println(s.getSname()+" "+s.getSaddress()+" "+s.getSdept()); } 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn *group by使用 //显示各个系的学生的平均年龄 List list=session.createQuery("select avg(sage),sdept from Student group by sdept").list(); //取出1. for 增强 for(Object[] obj:list){ System.out.println(obj[0].toString()+" "+obj[1].toString()); } //having的使用 //1.对分组查询后的结果,进行筛选:比如请显示人数大于3的系名称 //a. 查询各个系分别有多少学生. List list=session.createQuery("select count(*) as c1,sdept from Student group by sdept having count(*)>3").list(); //取出1. for 增强 for(Object[] obj:list){ System.out.println(obj[0].toString()+" "+obj[1].toString()); } //2查询女生少于200人的系 //a.查询各个系的女生有多个个 List list=session. createQuery("select count(*) as c1,sdept from Student where ssex='F' group by sdept").list(); //取出1. for 增强 for(Object[] obj:list){ System.out.println(obj[0].toString()+" "+obj[1].toString()); } //1.查询计算机系共多少人?->如果我们返回的是一列数据 //这时我们的取法是直接取出list->object 而不是 list->Object[] List list=session. createQuery("select sage from Student where sdept='计算机系'").list(); //取出1. for 增强 for(Object obj:list){ System.out.println(obj.toString()); } 3.查询选修11号课程的最高分和最低分. List list=session. createQuery("select 11,max(grade),min(grade) from Studcourse where course.cid=11").list(); //取出1. for 增强 for(Object[] obj:list){ System.out.println(obj[0].toString()+" max="+obj[1].toString()+" min="+obj[2].toString()); 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn } //计算各个科目不及格的学生数量.(学生练习!) List list=session. createQuery("select count(*),student.sdept from Studcourse where grade<60 group by student.sdept").list(); //取出1. for 增强 for(Object[] obj:list){ System.out.println(obj[0].toString()+" "+obj[1].toString()); } u 参数绑定案例 (jdbc->PreparedStatement setXXX) 使用参数绑定的好处有3: 1. 可读性提高, 2 效果高 3,防止 sql注入漏洞 ? 面试题: 如果不使用参数绑定,怎样防止登录时, sql注入? name password 思路: 1. 通过用户名,查询出该用户名在数据库中对应的密码,然后再与用户输入的秘密比较,如果相等,则用户和法,否则,非法. 参数绑定有两种形式 Query q=session.createQuery(from Student where sdept=:dept and sage>:age) 如果我们的参数是 :冒号形式给出的,则我们的参数绑定应当这样: List list=session.createQuery("from Student where sdept=:a1 and sage>:sage") .setString("a1", "计算机系").setString("sage", "2").list(); 还有一种形式: Query q=session.createQuery(from Student where sdept=? and sage>?) 如果我们的参数是以 ? 形式给出的则,参数绑定应当: List list=session.createQuery("from Student where sdept=? and sage>?") .setString(0, "计算机系").setString(1, "2").list(); 参数的绑定,可以分开写:形式如下: Query query=session.createQuery("from Student where sdept=? and sage>?"); query.setString(0, "计算机系"); query.setString(1, "2"); List list=query.list(); for(int i=0;i 22]]> 在程序中,我们这样获取并执行: List list=session.getNamedQuery("myquerytest").list(); System.out.println(list.size()); Iterator it=list.iterator(); while(it.hasNext()){ Object obj[]=(Object[])it.next(); System.out.println("n="+obj[0]); } hibernate 对象的三种关系: 1. one – to – one : 身份证<--->人 2. one – to – many 部门 <---> 员工 3. many-to-one 员工<--->部门 4. many-to-many 学生<--->老师 criterial使用: //查询年龄大于10岁的学生 criteria Session s=HibernateUtil.getCurrentSession(); Transaction tx=s.beginTransaction(); Criteria cri=s.createCriteria(Student.class); //添加检索条件 cri.add(Restrictions.gt("sage", new Long(10))); List list=cri.list(); for(Student s1: list){ System.out.println(s1.getSname()); } 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn tx.commit(); hibernate开发的三种方式中的: 编写domain object + 映射文件 ------> 创建出对应的数据库, 这里我们说明如果要自动的创建出对应的数据库,需要做配置(hibernate.cfg.xml). create 这里有四个配置值: create , update , create-drop, validate create : 当我们的应用程序加载hibernate.cfg.xml [ new Configuration().config(); ]就会根据映射文件,创建出数据库, 每次都会重新创建, 原来表中的数据就没有!!! update: 如果数据库中没有该表,则创建,如果有表,则看有没有变化,如果有变化,则更新. create-drop: 在显示关闭 sessionFactory时,将drop掉数据库的schema validate: 相当于每次插入数据之前都会验证数据库中的表结构和hbm文件的结构是否一致 l 在开发测试中,我们配置哪个都可以测试,但是如果项目发布后,最好自己配置一次,让对应的数据库生成,完后取消配置, u domain对象的细节: 1. 需要一个无参的构造函数(用于hibernate反射该对象) 2. 应当有一个无业务逻辑的主键属性. 3. 给每个属性提供 get set方法. 4. 在domian对象中的属性,只有配置到了对象映射文件后,才会被hiberante管理. 5. 属性一般是private范围 u 对对象关系映射文件的说明 对象关系文件中,有些属性是可以不配,hibernate会采用默认机制,比如 table 值不配,则以类的小写做表名 type不配置,则hibernate会根据类的属性类型,选择一个适当的类型 hibernate对象的三种状态,转换图: 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn 面试图:如果判断一个对象处于怎样的状态? 主要的依据是: 1. 看该对象是否处于session, 2, 看在数据库中有没有对应的记录 瞬时态: 没有session管理,同时数据库没有对应记录 持久态: 有session管理,同时在数据库中有记录 脱管态/游离态: 没有session管理,但是在数据库中有记录. u 懒加载: 简述: 当我们查询一个对象的时候,在默认情况下,返回的只是该对象的普通属性,当用户去使用对象属性时,才会向数据库发出再一次的查询.这种现象我们称为 lazy现象. 解决方法可以这样: 1. 显示初始化 Hibernate.initized(代理对象) 2. 修改对象关系文件 lazy 改写 lazy=false 3. 通过过滤器(web项目) openSessionInView u hibernate对象的关系映射 1. many-to-one 2. one-to-many 看一个需求: 通过一个部门号(1),来获取该部门的所有学生? 这里请大家参考代码: 3 one-to-one 一对一有有两种方式 (1) 基于主键的一对一 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn 原理图 : (2) 基于外键的一对一 原理图 : 3. many-to-many 学生<--->课程 就是many-to-many 顾客<--->商品 qq<--->qq群 上机练习, 请自己想出 生活中 one-to-many many-to-one many-to-many one-to-one 的四组对象关系,并使用hibernate实现写出 对应的domain object和对象关系映射文件,并通过 hbm2ddl 自动创建成功对应的表 u 为什么要学习hql(hibernate query language)->这个是官方推荐,功能强大 ? 删除 session.delete(对象) -> 批量删除 ? 添加 session.save session.persist ? 修改->批量修改 sessin.update(对象) 查询 对象 obj obj.setXXX(); ? 查询 load get 查询所有 性别是 男的雇员? u hql的详解 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn 为了讲解清楚,我模拟一个学生选课系统 ,创建三张表 从创建的三张表,我们看出: hibernate 设计者 推荐我们在设计表的时候,应当每张表有一个主键,而且该主键最好不含业务逻辑, product 表 id productNo name price 1 bi001 冰箱 1000 2 nj111 电脑 2000 我们现在使用hibernate工具,自动生成 domain 对象 和映射文件,如果我们的表有主外键的关系,则应当先映射主表,再映射从表 * uniqueResult方法 如果我们检索一个对象,明确知道最多只有一个对象,则建议使用该方法: 具体用法如下: Student s=(Student) session.createQuery("from Student where sid='20050003'").uniqueResult(); System.out.println(s.getSname()); *distinct的用法 过滤重复的记录 //比如,显示所有学生的性别和年龄. List list=session.createQuery("select distinct sage,ssex from Student").list(); for(int i=0;i list=session.createQuery("from Student where sdept in ('计算机系','外语系')").list(); //取出1. for 增强 for(Student s:list){ System.out.println(s.getSname()+" "+s.getSaddress()+" "+s.getSdept()); } *group by使用 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn //显示各个系的学生的平均年龄 List list=session.createQuery("select avg(sage),sdept from Student group by sdept").list(); //取出1. for 增强 for(Object[] obj:list){ System.out.println(obj[0].toString()+" "+obj[1].toString()); } //having的使用 //1.对分组查询后的结果,进行筛选:比如请显示人数大于3的系名称 //a. 查询各个系分别有多少学生. List list=session.createQuery("select count(*) as c1,sdept from Student group by sdept having count(*)>3").list(); //取出1. for 增强 for(Object[] obj:list){ System.out.println(obj[0].toString()+" "+obj[1].toString()); } //2查询女生少于200人的系 //a.查询各个系的女生有多个个 List list=session. createQuery("select count(*) as c1,sdept from Student where ssex='F' group by sdept").list(); //取出1. for 增强 for(Object[] obj:list){ System.out.println(obj[0].toString()+" "+obj[1].toString()); } //1.查询计算机系共多少人?->如果我们返回的是一列数据 //这时我们的取法是直接取出list->object 而不是 list->Object[] List list=session. createQuery("select sage from Student where sdept='计算机系'").list(); //取出1. for 增强 for(Object obj:list){ System.out.println(obj.toString()); } 3.查询选修11号课程的最高分和最低分. List list=session. createQuery("select 11,max(grade),min(grade) from Studcourse where course.cid=11").list(); //取出1. for 增强 for(Object[] obj:list){ System.out.println(obj[0].toString()+" max="+obj[1].toString()+" min="+obj[2].toString()); 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn } //计算各个科目不及格的学生数量.(学生练习!) List list=session. createQuery("select count(*),student.sdept from Studcourse where grade<60 group by student.sdept").list(); //取出1. for 增强 for(Object[] obj:list){ System.out.println(obj[0].toString()+" "+obj[1].toString()); } u 参数绑定案例 (jdbc->PreparedStatement setXXX) 使用参数绑定的好处有3: 1. 可读性提高, 2 效果高 3,防止 sql注入漏洞 ? 面试题: 如果不使用参数绑定,怎样防止登录时, sql注入? name password 思路: 1. 通过用户名,查询出该用户名在数据库中对应的密码,然后再与用户输入的秘密比较,如果相等,则用户和法,否则,非法. 参数绑定有两种形式 Query q=session.createQuery(from Student where sdept=:dept and sage>:age) 如果我们的参数是 :冒号形式给出的,则我们的参数绑定应当这样: List list=session.createQuery("from Student where sdept=:a1 and sage>:sage") .setString("a1", "计算机系").setString("sage", "2").list(); 还有一种形式: Query q=session.createQuery(from Student where sdept=? and sage>?) 如果我们的参数是以 ? 形式给出的则,参数绑定应当: List list=session.createQuery("from Student where sdept=? and sage>?") .setString(0, "计算机系").setString(1, "2").list(); 参数的绑定,可以分开写:形式如下: Query query=session.createQuery("from Student where sdept=? and sage>?"); query.setString(0, "计算机系"); query.setString(1, "2"); List list=query.list(); for(int i=0;i 22]]> 在程序中,我们这样获取并执行: List list=session.getNamedQuery("myquerytest").list(); System.out.println(list.size()); Iterator it=list.iterator(); while(it.hasNext()){ Object obj[]=(Object[])it.next(); System.out.println("n="+obj[0]); } hibernate 对象的三种关系: 1. one – to – one : 身份证<--->人 2. one – to – many 部门 <---> 员工 3. many-to-one 员工<--->部门 4. many-to-many 学生<--->老师 criterial使用: //查询年龄大于10岁的学生 criteria Session s=HibernateUtil.getCurrentSession(); Transaction tx=s.beginTransaction(); Criteria cri=s.createCriteria(Student.class); //添加检索条件 cri.add(Restrictions.gt("sage", new Long(10))); List list=cri.list(); for(Student s1: list){ System.out.println(s1.getSname()); } 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn tx.commit(); hibernate开发的三种方式中的: 编写domain object + 映射文件 ------> 创建出对应的数据库, 这里我们说明如果要自动的创建出对应的数据库,需要做配置(hibernate.cfg.xml). create 这里有四个配置值: create , update , create-drop, validate create : 当我们的应用程序加载hibernate.cfg.xml [ new Configuration().config(); ]就会根据映射文件,创建出数据库, 每次都会重新创建, 原来表中的数据就没有!!! update: 如果数据库中没有该表,则创建,如果有表,则看有没有变化,如果有变化,则更新. create-drop: 在显示关闭 sessionFactory时,将drop掉数据库的schema validate: 相当于每次插入数据之前都会验证数据库中的表结构和hbm文件的结构是否一致 l 在开发测试中,我们配置哪个都可以测试,但是如果项目发布后,最好自己配置一次,让对应的数据库生成,完后取消配置, u domain对象的细节: 1. 需要一个无参的构造函数(用于hibernate反射该对象) 2. 应当有一个无业务逻辑的主键属性. 3. 给每个属性提供 get set方法. 4. 在domian对象中的属性,只有配置到了对象映射文件后,才会被hiberante管理. 5. 属性一般是private范围 u 对对象关系映射文件的说明 对象关系文件中,有些属性是可以不配,hibernate会采用默认机制,比如 table 值不配,则以类的小写做表名 type不配置,则hibernate会根据类的属性类型,选择一个适当的类型 hibernate对象的三种状态,转换图: 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn 面试图:如果判断一个对象处于怎样的状态? 主要的依据是: 1. 看该对象是否处于session, 2, 看在数据库中有没有对应的记录 瞬时态: 没有session管理,同时数据库没有对应记录 持久态: 有session管理,同时在数据库中有记录 脱管态/游离态: 没有session管理,但是在数据库中有记录. u 懒加载: 简述: 当我们查询一个对象的时候,在默认情况下,返回的只是该对象的普通属性,当用户去使用对象属性时,才会向数据库发出再一次的查询.这种现象我们称为 lazy现象. 解决方法可以这样: 1. 显示初始化 Hibernate.initized(代理对象) 2. 修改对象关系文件 lazy 改写 lazy=false 3. 通过过滤器(web项目) openSessionInView 通过openSessionInView来解决懒加载. many-to-one 的many这方,如果你配置了 那么hibernate就会在 查询学生 many 方时,把它相互关联的对象也查询,这里我们可以看出,对select语句查询影响不大, one-to-many 的one 的这方,如果你配置 当你去查询一个部门的时候,我们看到: Hibernate: select department0_.id as id0_0_, department0_.name as name0_0_ from Department department0_ where department0_.id=? 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn Hibernate: select stus0_.dept_id as dept3_1_, stus0_.id as id1_, stus0_.id as id1_0_, stus0_.name as name1_0_, stus0_.dept_id as dept3_1_0_ from Student stus0_ where stus0_.dept_id=? 这样就会把该部门关联的学生全部返回,不管你使用否? 矛盾: 如何让我们的session范围更大.(缺点是session关闭会延时.) u hibernate对象的关系映射 1. many-to-one 比如 Employe 和 Department 2. one-to-many 比如 Departmetn 和 Employee 看一个需求: 通过一个部门号(1),来获取该部门的所有学生? 这里请大家参考代码: 3 one-to-one 一对一有有两种方式 (1) 基于主键的一对一 Person IdCard 基于主键的one-to-one 指的就是 IdCard 这样主键值同时充当外键. 原理图 : (2) 基于外键的一对一 原理图 : 3. many-to-many 案例 学生《---》课程 学生<--->课程 就是many-to-many 顾客<--->商品 qq<--->qq群 上机练习, 请自己想出 生活中 one-to-many many-to-one many-to-many one-to-one 的四组对象关系,并使用hibernate实现写出 对应的domain object和对象关系映射文件,并通过 hbm2ddl 自动创建成功对应的表 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn u 级联操作 所谓级联操作就是说,当你进行某个操作(添加/修改/删除...),就由hibernate自动给你完成. 比如: Department <---->Student 对象关系,我希望当我删除一个department ,那么就自动删除该部门的所有学生? 再比如: bbs项目 主帖<---->回帖 , 把主帖删除,那我们就希望把该主帖的回帖自动删除,这样我们可以使用级联(cascade)操作 \ 案例:如何配置级联操作,当删除某个部门的时候,我们自动删除其学生. 首先我们在 配置文件中修改: java代码中操作: //演示删除级联 //获取到某个部分 Department department=(Department) s.get(Department.class, 41); s.delete(department); u 演示save-update 配置文件: 代码: //添加学生 Department department=new Department(); department.setName("业务部门3"); Student stu1=new Student(); stu1.setName("顺平6"); // stu1.setDept(department); Student stu2=new Student(); stu2.setName("小明6"); // stu2.setDept(department); 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn Set students=new HashSet(); students.add(stu1); students.add(stu2); department.setStus(students); s.save(department); 说明: ① 在集合属性和普通属性中都能使用cascade ② 一般讲cascade配置在one-to-many(one的一方,比如Employee-Department),和one-to-one(主对象一方) hibernate综合运用. 以一个内部留言本来讲解.本案例本身不复杂,通过该案例我们讲解 struts+hibernate+接口编程的方式, 主要听点是程序结构的设计. 开始: 1. 看需求 2. 根据需求文档,我们画出程序框架图, 框架图的三个接口,暂时不写,后面我们再引入. 3. 创建一个web项目. 4. 创写web层. 4.1引入struts 42.把web层的jsp 表单 action 编写完毕,并且打通这个登录的模块 5. 引入hibernate 使用手动的方法来开发domain和对象关系文件 6. 把hibernate.cfg.xml写好 7. 写成工具类 dao HibernateUtil.java 8. 测试一下看看能否映射ok 测试成功! 9. 我们使用接口来解耦. web---接口--业务层 10. hibernate中,取消lazy 不要在 one-to-many 的 one的一方的 ,可以在 many的一方配置 lazy=false; 11. 添加消息的功能.(假设用户是唯一的.,如果用户不唯一,我们可以通过id来发送信息) * 在jsp页面中获取当前项目名称可以 <%=this.getServletContext().getContextPath() %> 通过标签: ${pageContext.request.contextPath} 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn 1. 懒加载是什么? 为什么需要懒加载? 2. 如何解决懒加载问题 u 为什么需要缓存? 看一个案例:->原理图 从上图看出: 当我们去查询对象的时候,首先到一级缓存去取数据,如果有,则不到数据库中取,如果没有则到数据库中取,同时在一级缓存中放入对象. u 一级缓存的细节 ① 什么操作会向一级缓存放入数据 save,update,saveOrUpdate,load,get,list,iterate,lock save 案例: //添加一个学生 Student student=new Student(); student.setName("小东"); s.save(student);//放入一级缓存 //我马上查询 Student stu2=(Student) s.get(Student.class, student.getId()); //select System.out.println("你刚刚加入的学生名字是"+stu2.getName()); ② 什么操作会从一级缓存取数据. get / load / list 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn get / load 会首先从一级缓存中取,如没有.再有不同的操作[get 会立即向数据库发请求,而load 会返回一个代理对象,直到用户真的去使用数据,才会向数据库发请求] ?list 会不会从session缓存取数据? 案例: //查询45号学生 Student stu=(Student) s.get(Student.class, 45); System.out.println("|||||||||||||||||||"); String hql="from Student where id=45"; Student stu2=(Student) s.createQuery(hql).uniqueResult(); System.out.println(stu2.getName()); 从上面的案例,我看出 query.list() query.uniueResut() 不会从一级缓取数据! 但是query.list 或者query.uniqueRestu() 会向一级缓存放数据的. ③ 一级缓存不需要配置,就可以使用,它本身没有保护机制,所以我们程序员要考虑这个问题,我们可以同 evict 或者 clear来清除session缓存中对象. evict 是清除一个对象,clear是清除所有的sesion缓存对象 ④ session级缓存中对象的生命周期, 当session关闭后,就自动销毁. ⑤ 我们自己用HashMap来模拟一个Session缓存,加深对缓存的深入. package com.hsp.view; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class MyCache { //使用map来模拟缓存 static Map maps=new HashMap(); public static void main(String[] args) { // TODO Auto-generated method stub getStudent(1); getStudent(1); getStudent(1); getStudent(1); getStudent(3); getStudent(3); 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn } public static Student getStudent(Integer id){ //s.get() //先到缓存去 if(maps.containsKey(id)){ //在缓存有 System.out.println("从缓存取出"); return maps.get(id); }else{ System.out.println("从数据库中取"); //到数据库取 Student stu=MyDB.getStudentFromDB(id); //放入缓存 maps.put(id, stu); return stu; } } } //我的数据库 class MyDB{ static List lists=new ArrayList(); //初始化数据库,假设有三个学生 static{ Student s1=new Student(); s1.setId(1); s1.setName("aaa"); Student s2=new Student(); s2.setId(2); s2.setName("bbb"); Student s3=new Student(); s3.setId(3); s3.setName("ccc"); lists.add(s1); lists.add(s2); 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn lists.add(s3); } public static Student getStudentFromDB(Integer id){ for(Student s: lists){ if(s.getId().equals(id)){ return s; } } return null;// 在数据库中没有. } } class Student{ private Integer id; private String name; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } u 为什么需要二级缓存? 因为一级缓存有限(生命周期短),所以我们需要二级缓存(SessionFactory缓存)来弥补这个问题 1. 需要配置 2. 二级缓存是交给第三方去处理,常见的Hashtable , OSCache , EHCache 3. 二级缓存的原理 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn 4. 二级缓存的对象可能放在内存,也可能放在磁盘. u 快速入门案例 使用OsCache来演示二级缓存的使用. 1. 配置二级缓存 对配置说明: update true org.hibernate.cache.OSCacheProvider 2. 可以文件放在 src目录下,这样你可以指定放入二级缓存的对象capacity 大小. 默认1000 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn 3 使用 // TODO Auto-generated method stub //通过获取一个sesion,让hibernate框架运行(config->加载hibernate.cfg.xml) Session s=null; Transaction tx=null; try { //我们使用基础模板来讲解. s=HibernateUtil.openSession(); tx=s.beginTransaction(); //查询45号学生 Student stu1=(Student) s.get(Student.class, 45);//45->一级缓存 System.out.println(stu1.getName()); tx.commit(); } catch (Exception e) { e.printStackTrace(); if(tx!=null){ tx.rollback(); } }finally{ if(s!=null && s.isOpen()){ s.close(); } } System.out.println("*********************************"); try { //我们使用基础模板来讲解. s=HibernateUtil.openSession(); tx=s.beginTransaction(); //查询45号学生 Student stu1=(Student) s.get(Student.class, 45); System.out.println(stu1.getName()); Student stu3=(Student) s.get(Student.class, 46); 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn System.out.println(stu3.getName()); tx.commit(); } catch (Exception e) { e.printStackTrace(); if(tx!=null){ tx.rollback(); } }finally{ if(s!=null && s.isOpen()){ s.close(); } } //完成一个统计,统计的信息在Sessfactory //SessionFactory对象. Statistics statistics= HibernateUtil.getSessionFactory().getStatistics(); System.out.println(statistics); System.out.println("放入"+statistics.getSecondLevelCachePutCount()); System.out.println("命中"+statistics.getSecondLevelCacheHitCount()); System.out.println("错过"+statistics.getSecondLevelCacheMissCount()); 3. 在配置了二级缓存后,请大家要注意可以通过 Statistics,查看你的配置命中率高不高 u 主键增长策略 ① increment 自增,每次增长1, 适用于所有数据库. 但是不要使用在多进程,主键类型是数值型 select max(id) from Student ② identity 自增,每次增长1, 适用于支持identity的数据(mysql,sql server), 主键类型是数值 ③ sequence ④ native 会根据数据类型来选择,使用identity,sequence ,hilo select hibernate_sequence.nextval from dual 主键类型是数值long , short ,int ⑤ hilo hilo标识符生成器由Hibernate按照一种high/low算法生成标识符 用法: 欢迎下载韩顺平老师的PHP视频教程 ,详情查看 http://php.itcast.cn my_hi_value next_value ⑥ uuid 会根据uuid算法,生成128-bit的字串 主键属性类型不能是数值型,而是字串型 ⑦ assigned 用户自己设置主键值,所以主键属性类型可以是数值,字串 ⑧ 映射复合主键 ⑨ foreign 在one-to-one的关系中,有另一张表的主键(Person) 来决定 自己主键/外键( IdCard) 给出一个简单原则: 针对oracle [主键是int/long/short 建议使用 sequence] 主键是String 使用uuid或者assinged 针对 mysql [主键是 int/long/short 建议使用increment/assigend ,如果是字串 UUId/assigned] 针对 sql server [主键是 int/long/short 建议使用 identity/native/assinged ,如果主键是字串,使用uuid/assigned ] one-to-one 又是基于主键的则使用foreign u hibernate最佳实践(在什么项目中使用最好) 对于数据量大,性能要求高系统,不太使用使用hiberante. 主要用于事务操作比较多的项目(oa/某个行业软件[石油、税务、crm, 财务系统.] olap->hibernate用的比较少 oltp->hibernate

下载文档,方便阅读与编辑

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 8 金币 [ 分享文档获得金币 ]
0 人已下载

下载文档

相关文档