Hibernate的基本增删改查(二)

本节代码点击这里:https://github.com/MarsOu1998/HibernateWeb

1.Hibernate的基本开发流程

Configuration这个类先去读取配置文件,其实在这个类的源码中可以看见,hibernate.cfg.xml是默认的配置文件,所以读取时不需要指定。然后用Configuration这个类生成一个SessionFactory,然后SessionFactory打开一个session,最后根据增删改查,判断是否需要生成事务,然后提交。

2.Configuration类

Configuration负责管理Hibernate的配置文件,在配置文件里面又注册了映射文件(*.hbm.xml),所以Configuration是可以管理两个配置文件的。

从源码中可以看到,配置文件是默认的。
在这里插入图片描述
也可以通过在configure里面指定文件名字修改读取的配置文件
在这里插入图片描述

3.SessionFactory

应用程序从SessionFactory里获得Session实例,一般情况下,一个数据库只有一个SessionFactory,例如在应用被初始化的时候被创建,因为SessionFactory比较耗费内存。SessionFactory,也就是会话工厂,里面缓存了SQL语句和Hibernate在运行时使用的映射元数据。

SessionFactory目的是为每一个客户生成链接,所以放在application里面比较合适。

4.Session

Session通过SessionFactory打开,在所有的工作完毕之后,需要关闭。

它与Web层的HttpSession没有任何关系。

我们可以自己编写Session类,对日常利用Hibernate进行增删改查的代码做一些优化:

util.HibernateSessionFactory.java:

package util;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;

/**
 * Configures and provides access to Hibernate sessions, tied to the
 * current thread of execution.  Follows the Thread Local Session
 * pattern, see {@link http://hibernate.org/42.html }.
 */
public class HibernateSessionFactory {

    /**
     * Location of hibernate.cfg.xml file.
     * Location should be on the classpath as Hibernate uses
     * #resourceAsStream style lookup for its configuration file.
     * The default classpath location of the hibernate config file is
     * in the default package. Use #setConfigFile() to update
     * the location of the configuration file for the current session.
     */
    private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
    private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
    private  static Configuration configuration = new Configuration();
    private static org.hibernate.SessionFactory sessionFactory;
    private static String configFile = CONFIG_FILE_LOCATION;

    static {
        try {
            configuration.configure(configFile);
            sessionFactory = configuration.buildSessionFactory();
        } catch (Exception e) {
            System.err
                    .println("%%%% Error Creating SessionFactory %%%%");
            e.printStackTrace();
        }
    }
    private HibernateSessionFactory() {
    }

    /**
     * Returns the ThreadLocal Session instance.  Lazy initialize
     * the <code>SessionFactory</code> if needed.
     *
     *  @return Session
     *  @throws HibernateException
     */
    public static Session getSession() throws HibernateException {
        Session session = (Session) threadLocal.get();

        if (session == null || !session.isOpen()) {
            if (sessionFactory == null) {
                rebuildSessionFactory();
            }
            session = (sessionFactory != null) ? sessionFactory.openSession()
                    : null;
            threadLocal.set(session);
        }

        return session;
    }

    /**
     *  Rebuild hibernate session factory
     *
     */
    public static void rebuildSessionFactory() {
        try {
            configuration.configure(configFile);
            sessionFactory = configuration.buildSessionFactory();
        } catch (Exception e) {
            System.err
                    .println("%%%% Error Creating SessionFactory %%%%");
            e.printStackTrace();
        }
    }

    /**
     *  Close the single hibernate session instance.
     *
     *  @throws HibernateException
     */
    public static void closeSession() throws HibernateException {
        Session session = (Session) threadLocal.get();
        threadLocal.set(null);

        if (session != null) {
            session.close();
        }
    }

    /**
     *  return session factory
     *
     */
    public static org.hibernate.SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    /**
     *  return session factory
     *
     *	session factory will be rebuilded in the next call
     */
    public static void setConfigFile(String configFile) {
        HibernateSessionFactory.configFile = configFile;
        sessionFactory = null;
    }

    /**
     *  return hibernate configuration
     *
     */
    public static Configuration getConfiguration() {
        return configuration;
    }

}
查询:

优化前的查询代码:

TEST.Query1.java:

package TEST;

import PO.Student;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class Query1 {
    public static void main(String[] args) {
        Configuration configuration=new Configuration().configure();
        SessionFactory sessionFactory=configuration.buildSessionFactory();
        Session session=sessionFactory.openSession();
        Student student=new Student();
        session.load(student,"oushile2");
        System.out.println(student.getName());
        System.out.println(student.getSex());
        session.close();

    }
}

优化后的查询代码:

TEST.Query1.java:

package TEST;

import PO.Student;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class Query1 {
    public static void main(String[] args) {

        Session session=util.HibernateSessionFactory.getSession();
        Student student=new Student();
        session.load(student,"oushile2");
        System.out.println(student.getName());
        System.out.println(student.getSex());
        util.HibernateSessionFactory.closeSession();

    }
}

效果是一样的。

更新:

在更新操作里面需要用到事务,最好是利用try和catch包围代码,和平时JDBC的链接风格类似。

Update1.java:

package TEST;

import PO.Student;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public class Update1 {
    public static void main(String[] args) {

        Session session=util.HibernateSessionFactory.getSession();
        Student student=new Student();
        session.load(student,"oushile2");

        student.setSex("男");
        Transaction transaction=session.beginTransaction();
        try{
            session.update(student);
            transaction.commit();

        }catch (Exception e){
           transaction.rollback();
        }finally {
            util.HibernateSessionFactory.closeSession();
        }

    }
}
Session的一些API

保存的方法

  1. save,如果主键冲突会报错
  2. saveOrUpdate,如果主键重复了,会覆盖原先的数据。

不存在会抛出异常的方法

  1. load,如果查找的主键不存在或者多余1个,控制台会显示出异常

不存在不会抛出异常但是返回值为空的方法

  1. get方法,查找的主键没找到,但是如果需要打印或者做其他的操作会返回空指针异常。

修改

  1. update

删除

  1. delete

4.批量操作

批量查询——HQL,Hibernate查询语言

批量查询学生信息中年龄小于18的人:

Query2.java:

package TEST;

import PO.Student;
import org.hibernate.Session;

import org.hibernate.query.Query;

import java.util.List;

public class Query2 {
    public static void main(String[] args) {
        Session session=util.HibernateSessionFactory.getSession();
        String sql="from Student where age<18";
        Query query=session.createQuery(sql);
        List list=query.list();
        for (int i = 0; i <list.size() ; i++) {
            Student student=(Student)list.get(i);
            System.out.println(student.getName()+" "+student.getSex());
        }
        util.HibernateSessionFactory.closeSession();
    }
}

第一次接触的时候,就很奇怪,Hibernate不是号称毫无SQL痕迹的吗?怎么还是需要动手编写SQL语句呢。

原来这里的SQL语句和数据库没有关系,而是与配置文件有关系,这里数据库的属性名字都是根据*.hbm.xml的。

也就是说,如果数据库发生了迁移,开发者是不需要修改类内的源代码的,只需要在配置文件里面改一下映射关系即可。

精确批量查询

批量查询学生信息中年龄小于18的人,只挑选其中的姓名和性别属性:

Query3.java:

package TEST;

import org.hibernate.Session;
import org.hibernate.query.Query;

import java.util.List;

public class Query3 {

    public static void main(String[] args) {
        Session session=util.HibernateSessionFactory.getSession();

        String sql="select name,sex from Student where age<18";
        Query query=session.createQuery(sql);
        List list=query.list();
        for (int i = 0; i < list.size(); i++) {
            Object[] obj=(Object[])list.get(i);
            System.out.println(obj[0]+" "+obj[1]);
        }
        util.HibernateSessionFactory.closeSession();
    }
}

因为指定了查询的内容,所以返回在list里面已经不是属性而是对象了,通过获取对象,get到里面的属性值,就可以在控制台上打印信息了。

指定参数:

package TEST;

import org.hibernate.Session;
import org.hibernate.query.Query;

import java.util.List;

public class Query3 {

    public static void main(String[] args) {
        Session session=util.HibernateSessionFactory.getSession();

        int age=14;
        String sql="select name,sex from Student where age<:age";
        Query query=session.createQuery(sql);
        query.setInteger("age",age);

        List list=query.list();
        for (int i = 0; i < list.size(); i++) {
            Object[] obj=(Object[])list.get(i);
            System.out.println(obj[0]+" "+obj[1]);
        }
        util.HibernateSessionFactory.closeSession();
    }
}

不过jdk从1.9开始就不赞同使用Integer去构建包了。

批量查询——准则查询(Criteria )

Query4.java:

package TEST;

import PO.Student;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;

import java.util.List;

public class Query4 {
    public static void main(String[] args) {
        Session session=util.HibernateSessionFactory.getSession();
        Criteria criteria=session.createCriteria(Student.class);
        criteria.add(Restrictions.le("age",18));
        List list=criteria.list();

        for (int i = 0; i < list.size(); i++) {
            Student student=(Student)list.get(i);
            System.out.println(student.getName()+" "+student.getSex());
        }

        util.HibernateSessionFactory.closeSession();
    }
}

不过Criteria方法已经过时,现在批量查询建议使用jpa做。

Criteria看上去比较麻烦,但是在一复合查询中,criteria有着无与伦比的优势。比如分页技术,可以利用criteria的setFirstResult和setMaxResult。

setFirstResult表示从第几条记录开始显示。

setMaxResult表示显示几条记录。

Query5.java:

package TEST;

import PO.Student;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;

import java.util.List;

public class Query4 {
    public static void main(String[] args) {
        Session session=util.HibernateSessionFactory.getSession();
        Criteria criteria=session.createCriteria(Student.class);
        criteria.add(Restrictions.le("age",18));
        criteria.setFirstResult(1);//从第一条开始显示
        criteria.setMaxResults(3);//显示3条记录

        List list=criteria.list();

        for (int i = 0; i < list.size(); i++) {
            Student student=(Student)list.get(i);
            System.out.println(student.getName()+" "+student.getSex());
        }

        util.HibernateSessionFactory.closeSession();
    }
}
批量查询——SQL查询

如果使用SQL查询,就不怎么使用Hibernate了。

Query5.java:

package TEST;

import PO.Student;
import org.hibernate.SQLQuery;
import org.hibernate.Session;

import java.util.List;

public class Query5 {

    public static void main(String[] args) {
        Session session=util.HibernateSessionFactory.getSession();

        SQLQuery sqlQuery=session.createSQLQuery("select * from user");
        sqlQuery.addEntity(Student.class);
        List list=sqlQuery.list();
        for (int i = 0; i < list.size(); i++) {
            Student student=(Student)list.get(i);
            System.out.println(student.getAccount());
        }
        util.HibernateSessionFactory.closeSession();
    }
}
如何在Hibernate里面调用存储过程
java.sql.Connection conn=session.connection();
conn.prepareCall(arg0);

小结

Hibernate的深入学习,有许多的API可供开发者调用,无需精通数据库操作,十分方便。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值