• Hibernate框架


    1.Hibernate的概述

    1.1 Hibernate框架的作用  

    Hibernate框架是一个数据访问框架(也叫持久层框架,可将实体对象变成持久对象,详见第5章)。通过Hibernate框架可以对数据库进行增删改查操作,为业务层构建一个持久层。可以使用它替代以前的JDBC访问数据。

    1.2 Hibernate访问数据库的优点

    1 简单,可以简化数据库操作代码。

    2 Hibernate可以自动生成SQL,可以将ResultSet中的记录和实体类自动的映射(转化)。

    3Hibernate不和数据库关联,是一种通用的数据库框架(支持30多种数据库),可以方便数据库移植。任何数据库都可以执行它的API。因为HibernateAPI中是不涉及SQL语句的,它会根据Hibernate的配置文件,自动生成相应数据库的SQL语句

    1.3 JDBC访问数据库的缺点

    1)需要编写大量的复杂的SQL语句、表字段多时SQL也繁琐、设置各个问号值。

    2)需要编写实体对象和记录之间的代码,较为繁琐。

    3)数据库移植时需要修改大量的SQL语句。

    1.4 Hibernate的设计思想

    Hibernate是基于ORMObject Relation Mapping)思想设计的,称为对象关系映射。负责Java对象和数据库表数据之间的映射。

    Hibernate是一款主流的ORM工具,还有其他很多ORM工具,如:MyBatis(以前叫iBatis)、JPAHibernate功能比MyBatis强大些,属于全自动类型,MyBatis属于半自动。但全自动会有些不可控因素,因此有些公司会用MyBatis

    ORM工具在完成Java对象和数据库之间的映射后: HQL

    1)在查询时,直接利用工具取出“对象”(不论是查询一条记录还是多条记录,取出的都是一个个对象,我们不用再去转化实体了)。

    2)在增删改操作时,直接利用工具将“对象”更新到数据库表中(我们不用再去把对象转成数据了)。

    3)中间的SQL+JDBC细节,都被封装在了工具底层,不需要程序员参与。

    u 注意事项:

    v Java程序想访问数据库,只能通过JDBC的方式,而Hibernate框架也就是基于ORM思想对JDBC的封装。

    v Hibernate是以“对象”为单位进行数据库的操作。

    2.Hibernate的基本使用

    2.1 Hibernate的主要结构

    1)hibernate.cfg.xml(仅1个):Hibernate的主配置文件,主要定义数据连接参数和框架设置参数。

    注意事项:就是个xml文件,只是名字比较奇葩!

    2)Entity实体类(n个,一个表一个):主要用于封装数据库数据。

    3hbm.xml映射文件(n个):主要描述实体类和数据表之间的映射信息。描述表与类,字段与属性的对应关系。

    注意事项:hbm.xml是个后缀,如:命名可写Cost.hbm.xml

    2.2 Hibernate主要的API

    1Configuration:用于加载hibernate.cfg.xml配置信息。用于创建SessionFactory

    2SessionFactory:存储了hbm.xml中描述的信息,内置了一些预编译的SQL,可以创建Session对象。

    3Session:负责对数据表执行增删改查操作。表示Java程序与数据库的一次连接会话,是对以前的Connection对象的封装。和JSP中的session不是一回事,就是名字一样而已。

    4Query:负责对数据表执行特殊查询操作+增删改

    5Transaction:负责Hibernate操作的事务管理。默认情况下Hibernate事务关闭了自动提交功能,需要显式的追加事务管理(如调用Transaction对象中的commit();提交事务)!

    u 注意事项:

    这些API都是在Hibernate包下的,导包别导错!

    v 第一次访问数据库比较慢,比较耗资源,因为加载的信息多。

    2.3 Hibernate使用步骤

    step1:建立数据库表。

    step2:建立Java工程(Web工程也可),引入Hibernate开发包和数据库驱动包。必须引入的包:hibernate3.jarcglib.jardom4j.jarcommons-collections.jarcommons-logging.jar…等,下载地址:http://hibernate.org/orm/downloads/

    step3:添加hibernate.cfg.xml配置文件,文件内容如下:

    <?xml version='1.0' encoding='UTF-8'?>
    
    <!DOCTYPE hibernate-configuration PUBLIC
    
              "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    
              "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
    
    <!-- Generated by MyEclipse Hibernate Tools.                   -->
    
    <hibernate-configuration>
    
    <session-factory>
    
        <!-- 指定方言,决定Hibernate生成哪种SQL -->
    
    <property name="dialect">
    
    org.hibernate.dialect.MySQLDialect
    
    </property>
    
    <property name="connection.url">
    
    jdbc:mysql://localhost:3306/hibdata
    
    </property>
    
    <property name="connection.username">root</property>
    
    <property name="connection.password">root</property>
    
    <property name="connection.driver_class">
    
    com.mysql.jdbc.Driver
    
    </property>
    
    <property name="myeclipse.connection.profile">mysql</property>
    
     
    
    <!-- 框架参数,将hibernate底层执行的SQL语句从控制台显示 -->
    
    <property name="show_sql">true</property>
    
    <!-- 格式化显示的SQL -->
    
     <property name="format_sql">true</property>
    
    <!-- 指定映射描述文件 -->
    
            <mapping resource="com/hxh/pojo/News.hbm.xml" />
    
    </session-factory>
    
     
    
    </hibernate-configuration>
     

    注意事项:应该放在源文件的src目录下,默认为hibernate.cfg.xml。文件内容是Hibernate工作时必须用到的基础信息。

    step4:编写Entity实体类(也叫POJO),例如:新闻实体类News

    private Integer nid;
    
    private String title;
    
    private String content;
    
    private String photo;
    
    private Integer ntid;……getter/setter方法

    注意事项:POJO类表示普通类(Plain Ordinary Old Object),没有格式的类,只有属性和对应的getter/setter方法,而没有任何业务逻辑方法的类。这种类最多再加入equals()hashCode()toString()等重写父类Object的方法。不承担任何实现业务逻辑的责任。

    step5:编写hbm.xml映射(文件)描述信息:映射文件用于指明POJO类和表之间的映射关系(xx属性对应xx字段)一个类对应一个映射文件。例如:News.hbm.xml内容如下:

    <?xml version="1.0" encoding="utf-8"?>
    
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    
      "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    
    <!-- 定义COST_CHANG表和Cost类型之间的映射信息   -->
    
    <hibernate-mapping><!-- <hibernate-mapping package="包名写这也行"> -->
    
    <!-- name:包名.类名,指定是哪个类;table:数据库中哪个表;catalog:对Oracle而言为哪个数据库,对MySQl而言为某个用户(MySQl是在用户下建表,Oracle是在库中建表),
    
    不写也行(若用工具则会自动生成)。例如,select * from news_chang则会在hibernate.cfg配置文件中定义的库(或用户)下去找表。若写了则为select * from system.news_chang  -->
    
       <?xml version="1.0" encoding="utf-8"?>
    
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    
    <!-- 此处表示的是进行POJO类与数据表之间的映射 -->
    
    <hibernate-mapping>
    
    <!-- 配置的是类的相关定义,name表示类的名字,同时设置table对应的数据表,catalog表示的是数据库的名字 -->
    
    <class name="com.offcn.pojo.News" table="news" catalog="hibdata">
    
    <!-- 配置主键,name表示的是类之中的属性名称,type表示的是News类的nid类型 -->
    
    <id name="nid" type="java.lang.Integer">
    
    <!-- News类中的nid属性与数据表之中对应的列,列名称是nid -->
    
    <column name="nid" />
    
    <!-- 主键的生成方式,本次使用的是数据表数据的自增长 -->
    
    <generator class="native"></generator>
    
    </id>
    
    <!-- 配置类之中的其它普通属性信息,name表示的是News类中的属性名称 -->
    
    <property name="title" type="java.lang.String">
    
    <!-- 定义类中的属性与表之中的映射字段 -->
    
    <column name="title" length="50" not-null="true" />
    
    </property>
    
    <property name="content" type="java.lang.String">
    
    <column name="content" length="65535" />
    
    </property>
    
    <property name="photo" type="java.lang.String">
    
    <column name="photo" length="200" />
    
    </property>
    
    <property name="ntid" type="java.lang.Integer">
    
    <column name="ntid" />
    
    </property>
    
    </class>
    
    </hibernate-mapping>
    
     

    注意事项:

     映射文件默认与POJO类放在一起;命名规则为类名.hbm.xml。

       hbm.xml中已写出的属性与字段的映射要一一对应,若表中没有某个字段,却写了映射关系,则报错:找不到实体类。

    step6:利用Hibernate API实现DAO

    1)新建HibernateUtil类,用于封装创建Session的方法。如下:每个用户会对应一个Session,但是SessionFactory是共享的。

    public class HibernateUtil {
    
    private static SessionFactory sf;
    
    static{//不用每次都加载配置信息,所以放static块中,否则每次都加载会耗费资源
    
    Configuration conf=new Configuration();//加载主配置hibernate.cfg.xml
    
    conf.configure("/hibernate.cfg.xml");
    
    sf=conf.buildSessionFactory();//获取SessionFactory }
    
    public static Session getSession(){//获取Session
    
    Session session =sf.openSession(); return session; }     }

    2)新建NewsDao接口

    package com.hxh.dao;
    
     
    
    import java.util.List;
    
     
    
    import com.hxh.pojo.News;
    
     
    
    public interface NewsDao {
    
    public News findById(int id);
    
    public void save(News news);
    
    public void delete(int id);
    
    public void update(News news);
    
      public List<News> findAll();
    
     
    
    }
    
     

    3)新建NewsDaoImpl类,用于实现NewsDao接口

    package com.hxh.dao;
    
     
    
    import java.util.List;
    
     
    
    import org.hibernate.Query;
    
    import org.hibernate.Session;
    
    import org.hibernate.Transaction;
    
     
    
    import com.hxh.pojo.News;
    
    import com.hxh.utils.HibernateUtil;
    
     
    
    public class NewsDaoImpl implements NewsDao {
    
        private Session session;
    
    public NewsDaoImpl(){
    
    session=HibernateUtil.getSession();
    
    }
    
     
    
     
    
    /*
    
     * @see com.offcn.dao.NewsDao#findById(int)
    
     * /** get方法执行查询,按主键当条件查询,如何判断是主键,是根据写的描述文件来定,
    
     * get方法就是findById,就是按主键去查,需指定:操作哪个类和id(主键)条件值即可,其他条件查询做不了
    
     */
    
    @Override
    
    public News findById(int id) {
    
    // TODO Auto-generated method stub
    
    News news=(News) session.get(News.class, id);
    
    session.close();
    
    return news;
    
    }
    
     
    
    /** save方法执行增加操作,注意1:获取事务并开启,增删改要注意,查询可以不管事务,因为没对数据库进行修改;注意2:主键值根据hbm.xml中的<generator>定义生成,执行后,会先获取序列值,再去做insert操作。
    
    即先:select COST_SEQ_CHANG.nextval from dual; 然后:insert into ……  */
    
    @Override
    
    public void save(News news) {
    
    // TODO Auto-generated method stub
    
    News vo = new News() ;
    
    vo.setTitle("今天是周五啦,高兴不?");
    
    vo.setPhoto("nophoto.jpg");
    
    vo.setContent("据说今天有中到大雨,小心被淹死哦,哈哈哈,可以免费游泳!");
    
    // 6、打开事务
    
    Transaction tran = session.beginTransaction() ;
    
    // 7、执行更新
    
    session.save(vo);
    
    // 8、提交事务
    
    tran.commit();
    
    // 9、关闭连接
    
    session.close() ;
    
    }
    
     
    
    /** delete方法执行删除操作,由于Hibernate以“对象”为单位进行数据库操作,
    
     * 所以这里要传进去一个对象,虽然是个对象,但还是按主键做条件删除,只要把主键值设置上就行,其他非主键值不用管。也可先通过id查再删 */
    
    @Override
    
    public void delete(int id) {
    
    // TODO Auto-generated method stub
    
       Transaction tx=session.beginTransaction();
    
       News news=new News();
    
       news.setContent("ijikij即可立即");
    
           session.delete(news);
    
           tx.commit();
    
           session.close();
    
    }
    
     
    
    /*
    
     * @see com.offcn.dao.NewsDao#update(com.offcn.pojo.News)
    
     */
    
    @Override
    
    public void update(News news) {
    
    // TODO Auto-generated method stub
    
    session=HibernateUtil.getSession();
    
    Transaction tx=session.beginTransaction();
    
    session.update(news);//将cost对象更新到数据库
    
    tx.commit();
    
    session.close();
    
     
    
    }
    
     
    
    /*
    
     * ** 特殊查询,SQL语句:String sql="select * from COST_CHANG";
    
           HQL语句:String hql="from Cost"; (Hibernate Query Language)是面向对象的查询语句。
    
           from后写映射的类名,它是Hibernate中特有的查询语句,根据映射的类去查询。 */
    
    @Override
    
    public List<News> findAll() {
    
    session=HibernateUtil.getSession();
    
    String hql="from News";//HQL语句
    
    Query query=session.createQuery(hql);
    
    List<News> list=query.list();//执行查询,返回List集合
    
    session.close();
    
    return list;
    
    }
    
     
    
    }

    4)新建TestCostDAO类,使用junit测试

    package hxh.offcn.test;
    
     
    
    import java.sql.Date;
    
    import java.util.List;
    
     
    
    import org.junit.Test;
    
     
    
    import com.hxh.dao.NewsDao;
    
    import com.hxh.dao.NewsDaoImpl;
    
    import com.hxh.pojo.News;
    
     
    
    public class TestDao {
    
    @Test
    
    public void testFindById(){//当get方法没有记录时,返回null
    
    NewsDao NewsDao = new NewsDaoImpl();
    
    News News = NewsDao.findById(1);
    
    System.out.println(News);
    
    }
    
    @Test
    
    public void testSave(){//id主键列由Hibernate管理,这里不用设置
    
    News vo = new News() ;
    
    vo.setTitle("w今天是周五啦,高兴不?");
    
    vo.setPhoto("nophoto.jpg");
    
    vo.setContent("据说今天有中到大雨,小心被淹死哦,哈哈哈,可以免费游泳!");
    
    NewsDao NewsDao = new NewsDaoImpl();
    
    NewsDao.save(vo);
    
      }
    
    @Test
    
    public void testUpdate(){
    
    NewsDao NewsDAO=new NewsDaoImpl();
    
    /** 注意事项:更新部分字段,不能和实现类中的删除那样,做一个对象出来!否则没设置的字段将被改为空! 即不能:News News=new News();  News.setId(90);  
    
       News.setStatus("1");   News.setStartTime(new Date(System.currentTimeMillis()));   */
    
    News news=NewsDAO.findById(1);//只能先通过id找到带有所有值的对象
    
    news.setContent("我跟发新股够了");
    
    NewsDAO.update(news);
    
    }
    
    @Test
    
    public void testDelete(){
    
    NewsDao NewsDAO=new NewsDaoImpl();  
    
    NewsDAO.delete(1);
    
    }
    
    @Test
    
    public void testFindAll(){
    
    NewsDao NewsDAO=new NewsDaoImpl();
    
    List<News> list=NewsDAO.findAll();
    
    for(News c:list){
    
    System.out.println(c);
    
    }
    
    }
    
     
    
    }

    3.关联映射

    3.1一对多关系one-to-many

    step1:新建项目,导入Hibernate开发包,借用学生班级实体:StudentGrade,配置hibernate.cfg.xml和两个实体的hbm.xml映射文件。

    step2:一个年级对应多个学生,所以为一对多关系。因此为OneGrade实体类添加Set集合属性,以及对应的get/set方法。

        //追加属性,用于存储相关联的学生信息
    
    private Set<Student> students = new HashSet<Student>();

    step3:在OneGrade.hbm.xml映射文件中,加入Set节点的映射

    简单说明:

     <set name="属性名">
    
    <!-- 关联条件,column写外键字段,会默认的与其表的主键相关联 -->
    
    <key column="指定关联条件的外键字段"></key>
    
    <!-- 指定采用一对多关系,class指定关联的类型 -->
    
    <one-to-many class="要关联的另一方(N方)"/>
    
    </set>

    具体实现:

    <!-- 描述services属性,采用一对多关系加载service记录 -->
    
    <!-- 是list集合用<list name=""></list>  set集合用<set name=""></set>  -->
    
    <set name="students" cascade="all" lazy="false">
    
          <key column="gid"/>        
    
          <one-to-many class="com.hxh.pojo.Student"/>
    
    </set>

    step4:借用5.174)中的step1中的HibernateUtil

    step5:新建TestOneToMany.java类用于测试

    /**
    
     * 功能1:查询一个班级的所有学生信息
    
     */
    
    @Test
    
    public  void findById(){
    
    Session session = HibernateUtil.getSessionFactory().openSession();
    
    Grade g = (Grade)session.get(Grade.class, 1);
    
    System.out.println(g.getGid()+" "+ g.getGname()+" "+ g.getGdesc());
    
    Set <Student>students =g.getStudents();
    
    for(Student stu:students){
    
    System.out.println(stu.getSid()+" "+stu.getSname()+" "+stu.getSex());
    
    }
    
    session.close();
    
    }
    
    /**
    
     * 功能2:一名新生加入到一个现有的班中
    
     */
    
    @Test
    
    public  void update() {
    
    Student stu = new Student();
    
    stu.setSid(3);
    
    stu.setSname("李婷3");
    
    stu.setSex("女");
    
     
    
    Session session = HibernateUtil.getSessionFactory().openSession();
    
    Transaction tr = session.beginTransaction();
    
     
    
    Grade g = (Grade)session.get(Grade.class, 1);
    
     
    
    /*Set studentset=g.getStudents();
    
    System.out.println(studentset);*/
    
    g.getStudents().add(stu);
    
     
    
    session.save(g);
    
    session.save(stu);
    
     
    
    tr.commit();
    
    session.close();
    
    }
    
     
    
    /**
    
     * 功能3:删除现有班级中一名学生
    
     */
    
    @Test
    
    public  void deleteStudent(){
    
    Session session = HibernateUtil.getSessionFactory().openSession();
    
    Transaction tr = session.beginTransaction();
    
     
    
    Grade g = (Grade)session.get(Grade.class, 1);
    
    Student stu = (Student)session.get(Student.class, 1);
    
        
    
    g.getStudents().remove(stu);
    
     
    
    session.update(g);
    
    session.update(stu);
    
    tr.commit();
    
    session.close();
    
    }
    
    /**
    
     * 功能4:查询一个学生的班级信息
    
     */
    
    @Test
    
    public  void findById2(){
    
    Session session = HibernateUtil.getSessionFactory().openSession();
    
    Student stu = (Student)session.load(Student.class, 1);
    
    System.out.println(stu.getSid() + " " + stu.getSname());
    
    Grade grade = stu.getGrade();
    
    System.out.println(grade.getGname());
    
    System.out.println(grade.getGdesc());
    
    session.close();
    
    }
    
     
    
    /**
    
     * 功能5:一名现有学生转入到另一个现有班级中
    
     */
    
    @Test
    
    public  void update2() {
    
     
    
    Session session = HibernateUtil.getSessionFactory().openSession();
    
    Transaction tr = session.beginTransaction();
    
     
    
    Grade g = (Grade)session.get(Grade.class, 2);
    
    Student stu = (Student)session.get(Student.class, 3);
    
        
    
    g.getStudents().add(stu);
    
     
    
    session.update(g);
    
    //session.update(stu);
    
     
    
    tr.commit();
    
    session.close();
    
    }
    
     
    
    }

    6.2一对一关系one-to-one

    step1:新建项目,导入Hibernate开发包,借用学生和考卷两个实体:StudentPaper,配置hibernate.cfg.xml和两个实体的hbm.xml映射文件。

    step2:可一个学生对应一份考卷,所以为一对一关系。因此为Student实体类添加Paper属性,以及对应的get/set方法,同时为Paper实体类添加Student属性,以及对应的get/set方法。

         //追加属性,用于存储关联的Paper信息

    private Paper paper;//

    Paper实体类

    package com.hxh.pojo;
    
     
    
    public class Paper {
    
    private int pid;
    
    private String pdesc;
    
    private Student student;
    
     
    
    public int getPid() {
    
    return pid;
    
    }
    
    public void setPid(int pid) {
    
    this.pid = pid;
    
    }
    
    public String getPdesc() {
    
    return pdesc;
    
    }
    
    public void setPdesc(String pdesc) {
    
    this.pdesc = pdesc;
    
    }
    
    public Student getStudent() {
    
    return student;
    
    }
    
    public void setStudent(Student student) {
    
    this.student = student;
    
    }
    
     
    
    }


    step3:配置Student.hbm.xml映射文件和Paper.hbm.xml 

    简单说明:

    <one-to-one name="属性名" class="要关联的另一方类型Account"
    
    column="关联条件的外键字段"/>   <!-- 指明外键字段,不写主键 -->

    注意事项:此时没有<set name="属性名"></set>标签。

    具体实现:

    <one-to-one name="paper" class="com.hxh.pojo.Paper" lazy="false" cascade="all"/>


     

     <?xml version="1.0" encoding="utf-8"?> 
    
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    
     
    
    <hibernate-mapping>
    
        <class name="com.hxh.pojo.Paper" table="PAPER" >
    
            <id name="pid" type="java.lang.Integer">
    
                <column name="PID" />
    
                <generator class="assigned" />
    
            </id>
    
            <property name="pdesc" type="java.lang.String">
    
                <column name="PDESC" length="50" not-null="true" />
    
            </property>
    
            <many-to-one name="student" class="com.hxh.pojo.Student" unique="true" >
    
             <column name="sid"/>
    
            </many-to-one>      
    
        </class>
    
    </hibernate-mapping>

    step4:借用5.174)中的step1中的HibernateUtil

    step5:新建TestOne2one .java类用于测试

    package com.hxh.test;
    
     
    
     
    
    import org.hibernate.Session;
    
    import org.hibernate.Transaction;
    
     
    
    import com.hxh.pojo.Paper;
    
    import com.hxh.pojo.Student;
    
    import com.hxh.utils.HibernateUtil;
    
     
    
    public class TestOne2one {
    
    public static void main(String[] args) {
    
    //save();
    
    findById2();
    
    }
    
    /**
    
     * 功能1:新增一个学生及其学生证信息
    
     */
    
    public static void save() {
    
    Student  stu = new Student();
    
    stu.setSid(11070130);
    
    stu.setSname("赵飞");
    
    stu.setSex("男");
    
     
    
    Paper paper = new Paper();
    
    paper.setPid(123456);
    
    paper.setPdesc("北京大学学生证");
    
     
    
    paper.setStudent(stu);
    
    stu.setPaper(paper);
    
     
    
    Session session = HibernateUtil.getSessionFactory().openSession();
    
    Transaction tr = session.beginTransaction();
    
     
    
    session.save(stu);
    
     
    
    tr.commit();
    
    session.close();
    
    }
    
     
    
     
    
    /**
    
     * 功能2:根据学生证查询相应学生信息 
    
     */
    
    public static void findById2() {
    
    Session session = HibernateUtil.getSessionFactory().openSession();
    
    Paper paper= (Paper)session.get(Paper.class, 123456);
    
    System.out.println(paper.getPdesc());
    
    System.out.println(paper.getStudent().getSname());
    
    session.close();
    
    }
    
    
    }
  • 相关阅读:
    蛋糕多少钱?
    【FJOI2015】金币换位问题
    撞车
    【BZOJ 1097】旅游景点atr
    codeforces 434D
    codeforces 480D
    bzoj网络流
    bzoj2039
    bzoj1927
    bzoj1070
  • 原文地址:https://www.cnblogs.com/masterhxh/p/13897682.html
Copyright © 2020-2023  润新知