技术干货程序猿阵线联盟-汇总各类技术干货

SSH框架之旅-hibernate(4)

2017-09-27  本文已影响52人  Wizey
hibernate

1.hibernate 查询方式


2.基本代码


下面的例子也是基于班级和学生一对多关系说明的。

2.1 实体类代码

package cc.wenshixin.entity;

public class Student {
    private Integer id; // 学号
    private String name; // 姓名
    private Integer age; // 年龄

    private Banji banji; // 所属班级

    public Student() {

    }

    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    //get,set方法在此省略,必须要写的
}

package cc.wenshixin.entity;

import java.util.HashSet;
import java.util.Set;

public class Banji {
    private Integer id; //编号
    private String name; //名称
    
    private Set<Student> setStudent = new HashSet<Student>(); //班级里的学生

    public Banji() {

    }

    public Banji(String name) {
        this.name = name;
    }
    //get,set方法在此省略,必须要写的
}

package cc.wenshixin.utility;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtility {
    private static Configuration cfg = null;
    private static SessionFactory sessionFactory = null;

    static{
        cfg = new Configuration().configure();
        sessionFactory = cfg.buildSessionFactory();
    }
    
    //获得sessionFactory对象的方法
    public static SessionFactory getSessionFactory()
    {
        return sessionFactory;
    }   
}

2.2 映射文件

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="cc.wenshixin.entity.Student" table="student">
        <id name="id" type="java.lang.Integer" column="sid">
            <generator class="native" />
        </id>
        <property name="name" type="java.lang.String" column="sname">
        </property>
        <property name="age" type="java.lang.Integer" column="age">
        </property>
        <many-to-one name="banji" class="cc.wenshixin.entity.Banji" column="sbid">
        </many-to-one>
    </class>
</hibernate-mapping>

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="cc.wenshixin.entity.Banji" table="banji">
        <id name="id" type="java.lang.Integer" column="bid">
            <generator class="native" />
        </id>
        <property name="name" type="java.lang.String" column="bname">
        </property>
        <set name="setStudent" table="student" cascade="save-update">
            <key column="sbid">
            </key>
            <one-to-many class="cc.wenshixin.entity.Student" />
        </set>
    </class>
</hibernate-mapping>

<?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">
<hibernate-configuration>
    <session-factory>
      <!-- 数据库信息配置 -->
      <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
      <property name="connection.url">jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=UTF-8</property>
      <property name="connection.username">用户名</property>
      <property name="connection.password">密码</property>
      
      <!-- hibernate功能选择 -->
      <property name="show_sql">true</property>
      <property name="format_sql">true</property>
      <property name="hbm2ddl.auto">update</property>
      <property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
      
      <!-- 加载映射文件 -->
      <mapping resource="cc/wenshixin/entity/Student.hbm.xml"/>
      <mapping resource="cc/wenshixin/entity/Banji.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

2.3 数据初始化

    @Test
    //初始化数据
    public void initData()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            //插入数据
            Banji banji1 = new Banji("计科一班");
            Banji banji2 = new Banji("计科二班");
            Banji banji3 = new Banji("计科三班");
            Banji banji4 = new Banji("计科四班");
            
            Student student1 = new Student("小明", 20);
            Student student2 = new Student("小红", 19);
            Student student3 = new Student("小智", 21);
            Student student4 = new Student("小张", 20);
            Student student5 = new Student("小李", 19);
            Student student6 = new Student("老王", 23);
            Student student7 = new Student("小魏", 20);
            
            banji1.getSetStudent().add(student1);
            banji1.getSetStudent().add(student3);
            banji2.getSetStudent().add(student2);
            banji2.getSetStudent().add(student5);
            banji2.getSetStudent().add(student4);
            banji3.getSetStudent().add(student6);
            banji4.getSetStudent().add(student7);
            
            session.save(banji1);
            session.save(banji2);
            session.save(banji3);
            session.save(banji4);
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

2.4 对象导航查询测试

    @Test
    //对象导航查询方式
    public void test()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            Banji banji = session.get(Banji.class, 2);
            Set<Student> setStudent = banji.getSetStudent();

            System.out.println(setStudent.size());
            for (Student student : setStudent) {
    System.out.println(student.getId()+":"+student.getName()+":"+student.getAge());
            }
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

3.HQL 查询


常用的 hql 语句(关键字大小写都可以的):

hql语句查询步骤:

3.1 查询所有

    @Test
    //HQL查询表中所有数据
    public void testQueryAll()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            Query<Banji> query = session.createQuery("FROM Banji");
            
            List<Banji> list = query.list();
            
            for(Banji banji:list)
            {
                System.out.println(banji.getId()+":"+banji.getName());
            }
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

3.2 条件查询

    @Test
    //HQL带条件的查询
    public void testQueryWhere1()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            Query<Banji> query = session.createQuery("FROM Banji AS banji WHERE banji.id=?");
            query.setParameter(0, 2);
            
            List<Banji> list = query.list();
            
            for(Banji banji:list)
            {
                System.out.println(banji.getId()+":"+banji.getName());
            }
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

    @Test
    //模糊条件查询
    public void testQueryWhere2()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            Query<Banji> query = session.createQuery("FROM Banji AS banji WHERE banji.name LIKE ?");
            query.setParameter(0, "%计科%");
            
            List<Banji> list = query.list();
            
            for(Banji banji:list)
            {
                System.out.println(banji.getId()+":"+banji.getName());
            }
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

3.3 排序查询

    @Test
    //排序查询
    public void testQueryOrder()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            Query<Banji> query = session.createQuery("FROM Banji AS banji ORDER BY banji.id DESC");
            
            List<Banji> list = query.list();
            
            for(Banji banji:list)
            {
                System.out.println(banji.getId()+":"+banji.getName());
            }
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

3.4 分页查询

    @Test
    //分页查询
    public void testQueryPage()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            Query<Student> query = session.createQuery("FROM Student");
            
            query.setFirstResult(2);
            query.setMaxResults(3);
            
            List<Student> list = query.list();
            
            for(Student student : list)
            {
                System.out.println(student.getId()+":"+student.getName()+":"+student.getAge());
            }
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

3.5 投影查询

听起来很高大上,其实就是查询数据表中的某一列。。。

@Test
    //投影查询
    public void testQueryShade()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            //注意返回的结果是一个object类型,而不是一个实体类的类型
            Query<Object> query = session.createQuery("SELECT name FROM Student");
            
            List<Object> list = query.list();
            
            for(Object object : list)
            {
                System.out.println(object);
            }
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

3.6 函数查询

需要类型转换

    @Test
    //函数查询
    public void testQueryFunction()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            Query<Object> query = session.createQuery("SELECT COUNT(id) FROM Student");
            
            Object object = query.uniqueResult(); //获取查询结果唯一值
            
            //先转换为long类型,再转换成int类型
            Long obj = (Long)object;
            int count = obj.intValue();
            System.out.println(count);
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

4.QBC 查询


QBC 查询是通过 Restrictions 类的静态方法来实现的,具体的方法如下表所示。

静态方法 说明
Restrictions.eq() 等于
Restrictions.allEq() 使用 Map,使用 key/value 进行多个等于的比较
Restrictions.gt() 大于 >
Restrictions.ge() 大于等于 >=
Restrictions.lt() 小于 <
Restrictions.le() 小于等于 <=
Restrictions.between() 对应 sql 语句中的 between 语句
Restrictions.like() 对应 sql 的like 语句
Restrictions.in() 对应 sql 的 in 语句
Restrictions.and() and 关系
Restrictions.or() or 关系
Restrictions.sqlRestriction() sql 限定查询

4.1 查询所有

    @Test
    public void testAll()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;      
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            //查询所有
            Criteria criteria = session.createCriteria(Student.class);
            List<Student> list = criteria.list();
            
            for (Student student : list) {
                System.out.println(student.getId()+":"+student.getName()+":"+student.getAge());
            }
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

4.2 条件查询

    @Test
    public void testWhere1()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;      
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            //条件查询
            Criteria criteria = session.createCriteria(Student.class);
            criteria.add(Restrictions.eq("id", 4)); //相当于where sid = 4
            criteria.add(Restrictions.eq("age", 19)); 
            List<Student> list = criteria.list();
            
            for (Student student : list) {
                System.out.println(student.getId()+":"+student.getName()+":"+student.getAge());
            }
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

    @Test
    public void testWhere2()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;      
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            //模糊查询
            Criteria criteria = session.createCriteria(Student.class);
            criteria.add(Restrictions.like("name", "%小%"));
            List<Student> list = criteria.list();
            
            for (Student student : list) {
                System.out.println(student.getId()+":"+student.getName()+":"+student.getAge());
            }
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

4.3 排序查询

    @Test
    public void testOrder()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;      
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            //排序查询
            Criteria criteria = session.createCriteria(Student.class);
            criteria.addOrder(Order.desc("id"));
            List<Student> list = criteria.list();
            
            for (Student student : list) {
                System.out.println(student.getId()+":"+student.getName()+":"+student.getAge());
            }
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

4.4 分页查询

话不多说,请看代码。

    @Test
    public void testPage()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;      
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            //分页查询
            Criteria criteria = session.createCriteria(Student.class);
            criteria.setFirstResult(1);
            criteria.setMaxResults(4);
            List<Student> list = criteria.list();
            
            for (Student student : list) {
                System.out.println(student.getId()+":"+student.getName()+":"+student.getAge());
            }
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

4.5 函数查询

同 HQL 一样,QBC 也有函数查询,通过 Projections 类中的静态方法实现。

    @Test
    public void testFunction()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;      
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            //函数查询
            Criteria criteria = session.createCriteria(Student.class);
            criteria.setProjection(Projections.rowCount());
            List<Student> list = criteria.list();
            
            Object obj = criteria.uniqueResult();
            Long lobj = (Long)obj;
            int count = lobj.intValue();
            
            System.out.println(count);
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

4.6 离线查询

DetachedCriteria 翻译为离线条件查询,他不不依赖 Session 来创建,所以 DetachedCriteria 可以被其他层使用条件封装,在交给 DAO 层查询,在 SSH 框架的整合上经常使用。

    @Test
    public void testOutLine()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;      
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            //离线查询
            DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Student.class);
            Criteria criteria = detachedCriteria.getExecutableCriteria(session);
            List<Student> list = criteria.list();
            
            for (Student student : list) {
                System.out.println(student.getId()+":"+student.getName()+":"+student.getAge());
            }
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

5.hibernate 检索策略


5.1 多表连接查询。

在做表的查询时,有时要采用连接查询进行对表联合查询,下面是 mysql 中的多表查询写法。

5.2 HQL 连接查询

5.2.1 内连接查询

内连接有一般的内连接查询,还有迫切内连接查询,迫切连接查询比一般的内连接查询多了一个 fetch 关键字两种方式返回的结果集不同。

    @Test
    //内连接查询
    public void testQueryInner()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            Query<Object> query = session.createQuery("from Banji as b inner join b.setStudent");
            
            List<Object> list = query.list(); //返回的是一个二维对象数组,list的每部分包含两个表中的数据
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

    @Test
    //迫切内连接查询
    public void testQueryInnerFecth()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            Query<Object> query = session.createQuery("from Banji as b inner join fetch b.setStudent");
            
            List<Object> list = query.list(); //返回的是一个一维对象数组,只包含联合表student中的数据
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

5.2.2 外连接

外连接也分一般的外连接查询和迫切外连接查询,并且还有左外连接和右外连接之分。

    @Test
    //迫切外连接查询
    public void testQueryOuterFecth()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            Query<Object> query = session.createQuery("from Banji as b left outer join fetch b.setStudent");
            
            List<Object> list = query.list(); //返回的是一个一维对象数组,只包含联合表student中的数据
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }
    
    @Test
    //外连接查询
    public void testQueryOuter()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            Query<Object> query = session.createQuery("from Banji as b left outer join b.setStudent");
            
            List<Object> list = query.list(); //返回的是一个二维对象数组,包含两个表中的数据
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

5.3 HQL 检索(抓取)策略

hibernate 的检索策略也是提升性能的一种方式,可以在获取关联对象的时候,对发送的语句进行优化,但是抓取策略需要和延迟加载一起使用来提升性能。

在前面,使用的是 session 对象的 get() 方法来发送语句查询数据库,但还可以 load() 来做查询,两者的区别是:get() 方法会马上发送语句查询数据库,而 load() 方法只有在执行到使用查询对象语句时才会发送语句查询数据库,load的延迟方式就是延迟查询方式。

延迟查询分为两类:

延迟就是发送 sql 语句的时间是否是随写随发的,还是用到的数据值的时候再发。

关于类级别延迟就是方法的区别,而关联级别延迟需要在映射文件中进行配置,根据班级来得到所有学生,就需要在班级实体类的映射文件中配置。在 set 标签上使用fetch属性和 lazy 属性。fetch 的默认就是 select 值,如果 fetch 属性的值为 join 那么 lazy 里面的值设置就失效了。设置 lazy 的值:true:表示延迟(默认);false:表示不延迟;extra表示极其延迟。

下面是示例代码:

类级别延迟

    @Test
    //get查询方式
    public void testGet()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            Banji banji = session.get(Banji.class, 2);
            //这一句就发送sql语句
            Set<Student> setStudent = banji.getSetStudent();
            
            //这一句要打印的值只有在事务提交成功后才会显示
            System.out.println(setStudent.size()); 
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

    @Test
    //load查询方式
    public void testLoad()
    {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction tx = null;
        try{
            sessionFactory = HibernateUtility.getSessionFactory();
            session = sessionFactory.openSession();
            tx = session.beginTransaction();
            
            Banji banji = session.load(Banji.class, 2);
            //这一句没有发送sql语句
            Set<Student> setStudent = banji.getSetStudent();

            //这一句才发送了sql语句,在事务提交后显示需要打印的值
            System.out.println(setStudent.size());
            
            tx.commit();
        }catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally {
            session.close();
            sessionFactory.close();
        }
    }

关联级别延迟

在班级实体类的配置文件中增加如下配置:

<set name="setStudent" table="student" cascade="save-update" lazy="false">
    <key column="sbid">
    </key>
    <one-to-many class="cc.wenshixin.entity.Student" />
</set>

批量抓取配置

为了进一步的提高查询的效率,hibernate 还有批量抓取的配置,只需要在set文件中加上 batch-size 的属性,在里面写上数字,数字越大,查询时发送的语句就越少,最大一般写 10。

<set name="setStudent" table="student" cascade="save-update" lazy="false"  batch-size="10">
    <key column="sbid">
    </key>
    <one-to-many class="cc.wenshixin.entity.Student" />
</set>
上一篇 下一篇

猜你喜欢

热点阅读