hibernate

介绍

概述
    ORM体现
    是JBoss公司的产品
下载
    http://www.hibernate.org
    http://hibernate.org/orm/downloads/
    https://sourceforge.net/projects/hibernate/files/hibernate-orm/
    https://sourceforge.net/projects/hibernate/files/
解压后文件夹说明
    documentation : 全部的文档
        devguide : 开发指导.
        javadocs : api文档.
        manual : 开发指南.
        quickstart : 快速开始.
    lib: 存放了所有的jar(第三方的、自己的).
        required : 必须要的jar.
        jpa : jpa实现的jar.
        optional: 可选的.
            c3p0 : 连接池(现在企业用得最多的连接池).
            ehcache : 缓存框架.
        proxool : 连接池.
    project : 存放了Hibernate框架的源码、测试用例、资源文件、示例.
        project/etc : 存放了配置文件的模版.
基础的jar包
    required + jpa + mysql数据库连接
使用步骤:
    1.建库、建表
    2.写实体类
    3.映射实体类
        1.映射文件(不流行)-hibernate包中搜索*.hbm.xml。配置文件要和实体类在一个包下。
        2.使用jpa注解(流行)
    4.写hibernate配置文件
        配置属性 hibernate-release-4.3.11.Final\project\etc\hibernate.properties
    5.测试api

hibernate配置文件说明

参考 hibernate-distribution-3.6.0.Final\project\etc\hibernate.properties
hibernate.connection.driver_class
    指定数据库连接参数
    com.mysql.jdbc.Driver
hibernate.connection.url
    如果数据库不存在就建库
    jdbc:mysql:///hib_demo?createDatabaseIfNotExist=true
hibernate.connection.username
    数据库用户名
hibernate.connection.password
    数据库密码
hibernate.dialect
    配置数据库方言(指定使用哪一种数据库,hibernate会根据这里指定的方言,生成符合当前数据库语法的sql语句)
    org.hibernate.dialect.MySQL5Dialect
hibernate.show_sql
    显示hibernate在运行的时候生成的sql语句!
    true
hibernate.format_sql
    格式化sql
    true
hibernate.hbm2ddl.auto
    自动建表
    update
        表不存在则创建,如果表已经存在就不创建表
    create
        先删除表,再创建一个新表
    create-drop
        在创建SessionFactory时候建表;在执行其close方法的时候删除表
    validate
        验证;检查映射配置与表结构是否一致,不一致报错!更严格!
javax.persistence.validation.mode
    关闭java对象注解验证!(如果新建web项目,使用javaee6.0以上版本,必须要加上这行!)
    none

基本使用代码一

User.java
    public class User {
        private String id;
        private String name;
        public String getId() {
            return id;
        }
        public void setId(String id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    }
User.hbm.xml
    
    
    
        
            
                
            
            
        
    
hibernate.cfg.xml
    
    
    
        
            com.mysql.jdbc.Driver
            jdbc:mysql:///hib_demo?createDatabaseIfNotExist=true
            root
            root
            org.hibernate.dialect.MySQL5Dialect
            true
            true
            update
            none 
            
        
    
AppTest.java
    @Test
    public void Save() throws Exception {
        User user = new User();
        user.setName("Jack");
        //1. 创建配置管理器对象
        Configuration config = new Configuration();
        //2. 加载主配置文件:hibernate.cfg.xml
        config.configure();
        //3. 创建SessionFactory对象
        SessionFactory sf = config.buildSessionFactory();
        //4. 创建Session  (会话,与数据库的连接的会话)
        Session session = sf.openSession();
        //5. 开启事务
        Transaction tx = session.beginTransaction();
        //6. -- 执行操作--
        session.save(user);
        //7. 提交事务/关闭
        tx.commit();
        session.close();
    }
    @Test
    public void get() throws Exception {
        Configuration config = new Configuration();
        config.configure();
        SessionFactory sf = config.buildSessionFactory();
        Session session = sf.openSession();
        Transaction tx = session.beginTransaction();
        User user = (User) session.get(User.class, 1);
        System.out.println(user);
        tx.commit();
        session.close();
    }

基本使用代码二

User.java
    @Entity
    public class User {
        @Id
        private int id;
        private String name;
        private int age;
        //getter/setter
    }
hibernate.cfg.xml
    
    
    
        
            org.hibernate.dialect.MySQL5InnoDBDialect
            true     
            true   
            update
            com.mysql.jdbc.Driver
            jdbc:mysql://localhost:3306/hibernate
            root
            32147
            10
            2
            
        
    
App.java
    public void testAdd(){
        // 第一步:创建Configuration配置信息对象 (加载全局的配置文件)
        Configuration configuration = new Configuration() // 默认会加载src/hibernate.properties属性文件
                    .configure(); // 默认会加载src/hibernate.cfg.xml 
        // 第二步:创建服务注册对象
        ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
        // 第三步:创建SessionFactory 
        SessionFactory sf = configuration.buildSessionFactory(serviceRegistry);
        // 第四步:创建Session
        Session session = sf.openSession();
        // 第五步:开启事务,得到事务对象
        Transaction transaction = session.beginTransaction();
        // 第六步:利用Session完成所有的持久化操作
        User user = new User();
        user.setId(1);
        user.setAge(20);
        user.setName("帅哥");
        session.save(user);
        // 第七步:事务提交或回滚 commit|rollback
        transaction.commit();
        // 第八步:关闭Session、SessionFactory
        session.close();
        sf.close();
    }

API

hibernate3API
    Configuration 管理管理文件的类
        Configuration configure()
            加载主配置文件,默认加载src/hibenrate.cfg.xml 
        SessionFactory buildSessionFactory()
            创建session的工厂(hibernate.cfg.xml中就是session工厂的配置!)
             一个应用程序只需要一个session工厂即可!单例对象!
        SessionFactory addClass(..) 
            加载指定类的字节码对应的映射文件!  (User.hbm.xml)
            注意:
                1.去对象所在的包下去找对应的映射文件;  
                2. 映射文件必须是*.hbm.xml后缀
                3. 测试使用才去使用,比较方便!
    SessionFactory session工厂
        Session openSession()   
            创建新的session对象
        Session getCurrentSession()
            创建session  (使用时候需要配置hibernate.cfg.xml)
            (thread)
    Session   与数据库连接的会话!(里面维护了一个数据库连接)
        hibernate中操作数据库就是通过session对象操作的!
        Serializable  save(obj);    
            保存对象  【主键自增长,就不用设置主键,设置了也没有!】
        void delete(obj);           
            删除对象  【对象的主键一定要存在】
        void update(obj);           
            修改对象  【对象的主键一定要存在】
        void saveOrUpdate(obj);     
            保存或修改【有设置主键执行更新,如果设置主键不存在就报错!  没有设置主键就保存!】
        Object get(Class clazz,Serializable id);
            主键查询
        查询方式
            1.写HQL语句查询【面向对象查询】
                hibernate query language    
                hibernate提供的面向对象的查询语句
                实现:session.createQuery(arg0);
            2.Criteria查询【面向对象查询】
                session.createCriteria(sql);
            3.本地sql查询【支持原生态的sql语句查询】
                session.createSQLQuery(sql)
    Transaction 事务
         hibernate要求对数据库数据的操作必须在一个事务环境内进行!
    Query
        List list();  
            执行的查询的hql
        int executeUpdate();  
            执行的更新的hql
hibernate4
    Configuration
        专门负责加载全局的配置文件,产生SessionFactory.
    ServiceRegistry
    SessionFactory
        它是当前数据库在内存中镜像。一个SessionFactory对应一个数据库,所以SessionFactory只能有一个,
        当应用一启动就获取SessionFactory,当应用关闭时才关闭SessionFactory.
        它是线程安全的.
        它是创建Session的工厂。
        它底层封装了数据源(连接池)。
        它还有一个可选的二级缓存. (默认是关闭的).
    Session
        概述
            它是应用程序与持久层进行交互的单线程对象。
            它是线程不安全。
            它存活的时间比较短.(因为它底层封装得是Connection,用完就要关闭).
            它是事务工厂.
            有一个必须开启的一级缓存. (一级缓存永远都是开启的).
        方法
            contains(object);
                判断一级缓存中是否包含这个对象,true为持久化状态
    Transaction
        Hibernate事务对象.
        JDBC事务(局部事务) : 只能对一个数据库中的表做事务. (web容器) tomcat jetty
        JTA事务(全局事务、分布式事务) : 可以对多个数据库中的表做事务.(EJB容器)
            WebSphere(IBM)、WebLogic(Oracle)、JBoss(jboss)
    ConnectionProvider
        数据库连接的提供者.
        一般指得是数据源DataSource(连接池).

持久化类的状态

Transient 瞬态
    new 持久化类(),刚new出来的,从来没有与Session关联过.
Persistent 持久化状态
    正在被Session管理中。调用Session的方法对它进行操作过,这个时候Session没有关闭.
    该对象在Session一级缓存中. (在内存中).
    如果你调用持久化状态对象的set方法,它会影响数据库表中的数据.
    你对持久化状态对象做的修改,会同步到底层的数据库表中,它不是立即同步到底层的数据库,默认是在事务提交时才同步。
Detached 脱管状态
    脱离了Session的管理,曾经被Session管理过,现在没被Session管理。

Hibernate的CRUD操作

Hibernate4添加:
    a. Serializable id = session.save();
       User user = new User(); // 瞬态
       user.setXxx();
       session.save(user); // user --> 持久化状态
    b. void session.persist();
       User user = new User(); // 瞬态
       user.setXxx();
       session.persist(user); // user --> 持久化状态
    c. session.saveOrUpdate(); // 添加与修改
       User user = new User(); // 瞬态
       user.setXxx(); // 不要设置主键列对应的属性.
       void = session.saveOrUpdate(user); // user --> 持久化状态
    d. session.merge(); // 混合集成了添加与修改.
       User user = new User(); // 瞬态
       user.setXxx(); // 不要设置主键列对应的属性.
       User u = session.merge(user); // user --> 瞬态,u --> 持久化状态
    注意:
        save()与persist()区别
            1.save方法有返回值,它返回的是主键id。
              persist没有返回值,需要通过对象的getId来获取
            2.save方法会立即往数据库表中插入数据
              persist方法会延迟往数据库表中插入数据(跟事务是否开启有关)
              在事务开启之后执行这两个方法做添加都会立即生成sql语句
Hibernate4根据主键查询:
    session.get(): 根据主键id查询
        User user = (User)session.get(User.class, 1); // user : 持久化状态
        立即从数据库表查询数据,返回对象.
    session.load(): 根据主键id查询
        User user = (User)session.load(User.class, 1); // user : 持久化状态
        延迟从数据库表查询数据,一开始返回代理对象,当你真正要用到它的属性时,
        才会生成查询语句到数据库表中查询数据。
        当你要用到它的时候,要保证Session不能关闭。
Hibernate4修改:
    持久化状态下:
        User user = (User)session.get(User.class, 1); // user : 持久化状态
        user.setXxx();
    脱管状态下:
        User u = new User(); // 瞬态
        u.setId(1); // 脱管
        session.update(u); // u --> 持久化状态
        session.saveOrUpdate(u);  // u --> 持久化状态
        User user = session.merge(u);  // u --> 脱管 user --> 持久化状态
Hibernate4删除:
    持久化状态下:
        User user = (User)session.get(User.class, 1); // user : 持久化状态
        session.delete(user); // user --> 瞬态
    脱管状态下:
        User u = new User(); // u  -> 瞬态
        u.setId(3); //  u  -> 脱管
        session.delete(u); // 瞬态

注解实现方式详细介绍

注解作用
    将持久化类转换成表的相关信息.(表名,索引,唯一约束,列名的相关信息、关联)
基础映射(注解加在持久化类上)
    entity/table/DynamicInsert/DynamicUpdate/SelectBeforeUpdate
主键映射/复合主键映射
    id/GeneratedValue/EmbeddedId
基本属性映射(持久化类中属性转化成数据库表中列的相关信息)
    Column/Lob/Temporal/Transient
集合属性映射
    
关联映射
继承映射

注解

第一类
    类名上
    @Entity
        将POJO转化成持久化类。
    @Table
        把持久化类转化成表的相关信息
        name:指定表名
        schema :指定将数据表存入哪个数据库,schema或者catalog只能指定一个.
        catalog:指定将数据表存入哪个数据库,schema或者catalog只能指定一个.
        indexes: 用于指定表的引索列
            @Index(columnList="数据表中的列名", name="索引名")
            indexes={@Index(), @Index()}
        uniqueConstraints:用于指定唯一约束
            @uniqueConstraint(columnNames={"列名","列名"}, name="唯一约束名")
    @DynamicInsert
        动态插入,根据持久化对象的属性是否有值明确生成insert语句。
    @DynamicUpdate
        动态修改,它会判断持久化对象中属性,哪些属性值发生了改变就会生成update的语句。(持久化状态下做修改)
    @SelectBeforeUpdate
        修改之前先查询,查询得到持久化对象再与脱管状态下的对象进行比较,哪些属性值发生了改变就会生成update的语句。(脱管状态下做修改)
第二类
    主键上
    @Id
        主键列
    @GeneratedValue(strategy=GenerationType.AUTO)
        指定了主键自增长策略
        GenerationType.IDENTITY: 适宜MySQL、SqlServer有自增长列的数据库。
        GenerationType.SEQUENCE:适宜Oracle这种没有自增长有sequence的数据库。
        GenerationType.AUTO:让Hibernate根据数据库方言自动选择主键生成策略。
        GenerationType.TABLE: 适宜所有的数据库,因为它会单独生成一张表来维护主键生成。
    @Embedded
        复合主键
    @AttributeOverrides
        指定复合主键中的列表
        @AttributeOverrides({@AttributeOverride(name="firstName", column=@Column(name="F_NAME")),@AttributeOverride(name="lastName", column=@Column(name="L_NAME"))})
第三类
    普通属性上
    @Column
        持久化类中属性转化成数据库表中列的相关信息
        name:指定列名。
        length: 该列支持的长度。
        precision:有效的总位数。(BigDecimal类型才有效)
        scale:小数点的位数。(BigDecimal类型才有效)
        unique: 唯一约束。
        nullable:非空约束。
        insertable:是否允许插入true:允许 false: 不允许。
        updatable:是否允许修改true:允许 false: 不允许。
        columnDefinition :指定列的定义。columnDefinition="int(11) not null default 20"
    @Lob
        映射大的二进制数或者文本
    @Temporal
        修饰日期类型Date
        TemporalType.DATE : yyyy-MM-dd
        TemporalType.TIME : HH:mm:ss
        TemporalType.TIMESTAMP : yyyy-MM-dd HH:mm:ss
    @Transient
        指定不是持久化属性
        transient关键字修饰不需要序列化的属性,同时用它也能指定不是持久化的属性。
第四类
    集合属性上(List/Set/Map/Array)
    当持久化中有一个属性是集合(Set、List、Map).
    集合属性会单独生成一张表
    定义集合属性时面向接口,并且集合属性需要程序员自己初始化
        private List list = new ArrayList();
    @ElementCollection
        指定加载策略/指定集合中的元素类型
        @ElementCollection(fetch=FetchType.LAZY,targetClass=String.class)
            fetch=FetchType.EAGER: 立即加载 / fetch=FetchType.LAZY: 延迟加载
            targetClass 集合中元素的类型
    @CollectionTable
        指定集合的表名
        @CollectionTable(name="info") 
    List集合(有序集合)
        @OrderColumn
            指定排序列
            @OrderColumn(name="o_id")
        @Embeddable
            说明此类是集合中的元素
            
    Set集合(无序集合)
        @Embeddable
        注意:
            Set集合生成表默认是没有主键列的。如果想要生成主键列,需要为Set集合的元素类的属性上添加非空约束!
                @Column(nullable:false)
            Set集合生成表的主键列:【外键列 + Set集合的元素列】
    Map集合(有Map的key)
        @MapKeyColumn
        @Embeddable
        注意
            Map集合生成表的主键列:【外键列 + Map的Key】
第五类
    关联映射
    单向关联
        一对一
            //学生表中增加一个关联id
            @OneToOne(fetch=FetchType.LAZY,targetEntity=Teacher.class)
            @JoinColumn(name="t_id",referencedColumnName="id")
            private Teacher teacher;
        一对多
            //学生表中增加一个关联id
            @OneToMany(fetch=FetchType.LAZY,targetEntity=Student.class,mappedBy="teacher")//延迟加载,指定关联的持久化类,指定哪些维护关联关系
            @JoinColumn(name="t_id",referencedColumnName="id")
            private Set students = new HashSet();
        多对一
            //学生表中增加一个关联id
            @ManyToOne(fetch=FetchType.LAZY,targetEntity=Teacher.class)
            @JoinColumn(name="t_id",referencedColumnName="id")
            private Set students = new HashSet();
        多对多
            @ManyToMany(fetch=FetchType.LAZY,targetEntity=Teacher.class)
            @JoinTable(name="t_tea_stu",joinColumns=@JoinColumn(name="s_id",referencedColumnName="id"),inverseJoinColumns=@JoinColumn(name="t_id",referencedColumnName="id"))
            private Set teachers = new HashSet();
    双向关联
        一对一
            注解:@OneToOne
            @OneToOne(fetch=FetchType.LAZY,targetEntity=Student.class,mappedBy="teacher")
            private Student student;
            @OneToOne(fetch=FetchType.LAZY,targetEntity=Teacher.class)
            @JoinColumn(name="t_id",referencedColumnName="id",unique=true)
            private Teacher teacher;
            
        一对多
            一端(主表):@OneToMany
                @OneToMany(fetch=FetchType.LAZY,targetEntity=Student.class,mappedBy="teacher")//延迟加载,指定关联的持久化类,指定哪些维护关联关系
                private Set students = new HashSet();
            多端(从表):@ManyToOne
                生成外键列
                @ManyToOne(fetch=FetchType.LAZY,targetEntity=Teacher.class)//延迟加载,指定关联的持久化类
                @JoinColumn(name="t_id",referencedColumnName="id",foreignKey=@ForeignKey(name="fk_tea_stu"))//生成外键列t_id,关联Teacher类中的id
                private Teacher teacher;
            保存主表,再保存从表
            级联级别
                @OneToMany(fetch=FetchType.LAZY,targetEntity=Student.class,mappedBy="teacher",cascade=CascadeType.REMOVE,orphanRemoval=true)
                    CascadeType.REMOVE 级联删除
                    orphanRemoval=true 删除孤儿记录
                        在不删除老师的基础上,把学生删除
                以后千万不要配置@ManyToOne(fetch=FetchType.LAZY,targetEntity=Teacher.class,cascade=CascadeType.REMOVE)
                    CascadeType.REMOVE 级联删除,以后千万不要配置
        多对多
            注解
                @ManyToMany
            生成中间表来维护关联关系
            用Set集合定义关联属性, set集合中的元素是关联的持久化类
            @ManyToMany(fetch=FetchType.LAZY,targetEntity=Student.class,mappedBy="teachers")
            private Set students = new HashSet();
            @ManyToMany(fetch=FetchType.LAZY,targetEntity=Teacher.class)
            @JoinTable(name="t_tea_stu",joinColumns=@JoinColumn(name="s_id",referencedColumnName="id"),inverseJoinColumns=@JoinColumn(name="t_id",referencedColumnName="id"))
            private Set teachers = new HashSet();
第六类
    继承映射
    第一种方式(SINGLE_TABLE):所有子类中属性都生成到父类表中(一张表)
        @Entity @Table(name="parent")
        @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
        @DiscriminatorColumn(name="DC", discriminatorType=DiscriminatorType.INTEGER)// 辨别者列
        @DiscriminatorValue("1") // 辨别者列值
        public class Person{}
        //子类
        @Entity
        @DiscriminatorValue("2") // 辨别者列值
        public class Teacher{}
        注意:
            所有子类属性中不能加非空约束
    第二种方式(JOINED):所有的子类与父类都会单独生成表(子类表的中主键列同时也是外键列,它引用顶级父类表中的主键列).
        @Entity @Table(name="parent")
        @Inheritance(strategy=InheritanceType.JOINED)
        public class Person{}
        //子类
        @Entity @Table(name="teacher")
        public class Teacher{}
        注意:查询时会出现很多join语句
    第三种方式(TABLE_PER_CLASS):所有的子类与父类都会单独生成表,子类会把父类中的属性继承过来生成在自己的表中。
        @Entity @Table(name="parent")
        @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
        public class Person{}
        //子类
        @Entity @Table(name="teacher")
        public class Teacher{}
        注意:
            这种策略主键不能用自增长
            查询时会出现union运算

映射文件说明

hibernate-mapping 根元素
    package 
        指定包名,如果没有指定,本文件出现的所有实体类必须带上完整包名.如果指定,就可以不带完整包名。
    auto-import
        默认为true 自动导入,在进行hql查询的时候不用写包名!
         如果设置为false,在hql查询的时候需要指定包名,如:session.createQuery("from cn.itcast.entity.User");
    schema
        库名
class 类映射一个表
    name 类名,是否指定完整路径看package
    table 表名
id 主键映射
    name 属性名
    column 表字段名,不写也可以
generator 主键策略
    native 自增长(根据底层数据库的能力选择 identity、sequence )
    identity  MySql中自增长的方式
    sequence  Oracle中以序列的方式实现自增长!
    increment  也是自增长但不能处理并发问题!
    assigned  手动指定主键的值
    uuid       uuid值作为主键
    foreign  外键策略(一对一映射时候用到)
property 其它字段映射
    name 属性名
    column 表字段名,不写也可以。如果字段是数据的关键字使用反引号 `desc`
    length 指定字符类型的长度,默认255
    type 指定字段类型
        hibernate支持的类型默认都是小写 
            string/java.lang.String
            date/timestamp/ 如果属性是java.util.Date类型,字段映射没有指定类型,默认是datetime类型
    unique
        唯一约束
    not-null
        不能为空约束

代码方式建表

加载hibernate.cfg.xml
    Configuration cfg = new Configuration().configure();
工具类
    SchemaExport export = new SchemaExport(cfg);
建表-参数1:是否打印生成的sql到控制台-参数2:是否执行生成的sql
    export.create(true, true);

查询方式

get主键查询
    User user = (User) session.get(User.class, 1);
    立即从数据库表中查询数据
load对象导航查询(懒加载查询)
    user = (User) session.load(User.class, 1);
    延迟从数据库表查询数据,一开始返回一个代理对象,当真正用到属性的时候,再到数据库表中查询
    注意:用它时保证session不要被关闭
Hql查询 
    Hibernate Query Language 
    Hibernate查询语句 
    步骤:
        获得Session
        写hql语句
        查询数据库获得Query对象
        如果有占位符,就需要对占位符赋值 query.setParameter();
            如果需要分页limit赋值 query.setFirstResult(start); query.setMaxResults(size);
        获取查询查询结果
            如果本次查询有多条记录返回:query.list();
            如果本次查询只有一条记录返回:query.uniqueResult();
    from字句
        List students = session.createQuery("from Student").list();
        List students = session.createQuery("from Student as stu").list();
        List students = session.createQuery("from Student stu").list();
        User user =(User) session.createQuery("from User where id=1").uniqueResult();
    select字句
        List students = session.createQuery("select s from Student as s").list();
        List names = session.createQuery("select s.name from Student s").list();
        List lists = session.createQuery("select s.name,s.age from Student s").list();
        List lists = session.createQuery("select name,age from Student").list();
    分页
        Query query = session.createQuery("select s from Student s");
        query.setFirstResult(0);
        query.setMaxResults(5);
        List students = query.list();
    select new 字句
        可以改变List集合中存放什么
        List> list = session.createQuery("select new map(s.name,s.age) from Student s").list();
        List> list = session.createQuery("select new list(s.name,s.age) from Student s").list();
        List list = session.createQuery("select new com.shuai.domain.User(name,age) from Student").list();
    关联(持久化类)与连接(数据库表)
        隐式关联(不需要写join语句)
            查询时,关联的属性是一个持久化类。
            List students = session.createQuery("select s from Student s where s.teacher.id=?").setParameter(0,1).list();
        显示关联(需要写join语句)
            查询时,关联属性是一个Set集合
            Teacher t = (Teacher)session.createQuery("select t from Teacher t inner join t.students where t.students.id=?").setParameter(1,1).uniqueResult();
        抓取连接(查询延迟的属性)
            查询时,关联属性配置了延迟加载的,但本次查询要查询出来 join fetch关联的属性
            List students = session.createQuery("select s from Student s join fetch s.teacher").list();
    排序 order by
        List students = session.createQuery("select s from Student s order by s.age asc").list();
    分组 group by
        List list = session.createQuery("select count(s),s.teacher.name from Student s group by s.teacher.name").list();
    分组过滤 having
        List list = session.createQuery("select count(s),avg(s.score),sum(s.score),s.teacher.name from Student s group by s.teacher.name having s.teacher.id=?").setParameter(0,1).list();
    聚合函数 count/sum/max/min/avg
        count
            Long count = (Long)session.createQuery("select count(*) from Student").uniqueResult();
        sum
            Double sum = (Double)session.createQuery("select sum(score) from Student").uniqueResult();
        max
            Float max = (Float)session.createQuery("select max(score) from Student").uniqueResult();
        min
            Float min = (Float)session.createQuery("select min(score) from Student").uniqueResult();
        avg
            Float avg = (Float)session.createQuery("select avg(score) from Student").uniqueResult();
    where字句部分(查询过滤部分)
        Hibernate的where子句部分能支持的运算符,表达式、函数特别多,用法与sql语句是一样的
        常用的表达式、运算符、函数
            =、<、<=、>、>=、!=、and、or、distinct、between...and 、like、concat()、is null, is not null, is empty, is not empty、second(...),minute(...), hour(...), day(...), month(...)
        支持EJB-QL 3.0的函数
            trim(), lower(), upper(), length(), abs(), sqrt(), bit_length(), mod()
        支持操作集合属性的函数
            size()|size, minelement(), maxelement(), minindex(), maxindex()
        使用
            List students = session.createQuery("select s from Student s where s.name like ?8").setParameter("9","%小%").list();
            List students = session.createQuery("select s from Student s where s.name like concat('%',?2,"%")").setParameter("2","小").list();
            List students = session.createQuery("select s from Student s where s.name is not null").list();
            List students = session.createQuery("select s from Student s where trim(s.name) like ?").setParameter(0,"%帅%").list();
            List students = session.createQuery("select s from Student s where length(s.name) = ?").setParameter(0,"%帅%").list();
            List students = session.createQuery("select s from Student s where sqrt(s.id)=?").setParameter(0,1.0d).list();
            List students = session.createQuery("select s from Student s where bit_length(s.name)=?").setParameter(0,32L).list();
            List students = session.createQuery("select s from Student s where mod(s.id,?)=?").setParameter(0,2).setParameter(1,0).list();
            List orders = session.createQuery("select o from Order o where size(o.orderItems) =?").setParameter(0,3).list();
            List orders = session.createQuery("select o from Order o where minelement(o.orderItems) =?").setParameter(0,100).list();
            List orders = session.createQuery("select o from Order o where maxelement(o.orderItems) =?").setParameter(0,100).list();
            List orders = session.createQuery("select o from Order o where maxindex(o.orderItems) =?").setParameter(0,1).list();
            List orders = session.createQuery("select o from Order o where minindex(o.orderItems) =?").setParameter(0,1).list();
    子查询
        hibernate的子查询与SQL语句的中子查询一样,子查询部分放在in、not in里面
        使用
            List students = session.createQuery("select s from Student as s where s.id in(select t.id from Teacher t)").list();
    多态查询
        当你的持久化类存在继承关系时,你查询父类时,它会把父类所有的对象查询出来,而且也会把所有子类对象查询出来。
        使用
            List lists = session.createQuery("from java.lang.Object").list();
    命名查询
        把所有hql语句写在一个单独的配置文件中
        一般在实际的项目中用得比较多,它会把比较复杂的hql语句写在一个单独的配置文件中
        方便以后对hql语句进行优化,也方便统一管理
        第一种方式
            1.创建xxx.hbm.xml
                
                
                
                    select s from Student s where s.name like ?
                
            2.在hibernate.cfg.xml文件中配置xxx.hbm.xml
                
            3.使用
                List students = session.getNamedQuery("hql_1").setParameter(0, "%小%").list();
        第二种方式
            1.在持久化类上加注解
                @NamedQuery(name="hql_1", query="select s from Student s where s.name like ?");
                public class Student{}
            2.使用
                List students = session.getNamedQuery("hql_1").setParameter(0, "%小%").list();
Criteria查询
    说明
        完全面向对象的,不需要写任可查询语句
    查询步骤
        1.获取Session
        2.Criteria criteria = session.createCriteria(持久化类)
        3.如果需要分页查询就需要为limit ?,? 这两个问号赋值
            第一个问号:criteria.setFirstResult(start);
            第二个问号:criteria.setMaxResults(size);
        4.获取查询查询结果
            如果本次查询有多条记录返回:criteria.list();
            如果本次查询只有一条记录返回:criteria.uniqueResult();
    API
        add(Criterion criterion)
            添加查询条件.Criterion : 代表一个查询条件.
            Restrictions 工具类,专门负责生成查询条件对象,它把where部分都改成了静态方法。
            Property工具类,专门负责生成查询条件对象.
        addOrder(Order order)
            添加排序
            Order.asc("属性名") | Order.desc("属性名")
            Property.forName("age").asc()|Property.forName("age").desc()
        setProjection(Projection projection)
            查询哪些列
        createAlias(String associationPath, String alias)
            创建关联查询
            用它创建出来的关联查询,添加查询条件时,如果不加别名,它是为目标持久类添加查询条件.
        createCriteria(String associationPath)
            创建关联查询
            用它创建出来的关联查询,添加查询条件时,它是为关联的持久化类添加查询条件.
        setFetchMode(String associationPath, FetchMode mode)
            抓取连接(join fetch)
            FetchMode: 抓取模式
                FetchMode.JOIN     FetchMode.EAGER 立即查询
                FetchMode.SELECT   FetchMode.LAZY  延迟查询
        DetachedCriteria.
            离线查询
            用它就可以定义一条查询语句.
            用得时候需要与Session关联起来.
            离线查询的主要作用就是为了做子查询. in 、not in(离线查询对象)
    使用
        List students = session.createCriteria(Student.class).list();
        List students = session.createCriteria("com.shuai.domain.Student").list();
        List students = session.createCriteria(Student.class).add(Restrictions.like("name","%帅%")).list();
        List students = session.createCriteria(Student.class).add(Restrictions.like("name","%帅%")).add(Restrictions.between("age",20,30)).list();
        List students = session.createCriteria(Student.class).add(Property.forName("name").like("%帅%")).list();
        List students = session.createCriteria(Student.class).add(Property.forName("age").between(20,30)).list();
        List students = session.createCriteria(Student.class).add(Restrictions.sqlRestriction("length(name)=4")).list();
        List students = session.createCriteria(Student.class).addOrder(Order.asc("age")).list();
        List students = session.createCriteria(Student.class).addOrder(Property.forName("age").asc()).list();
        List names = session.createCriteria(Student.class).setProjection(Projections.property("name")).list();
        ProjectionList pl = Projections.projectionList();
        pl.add(Projections.property("name"));
        pl.add(Projections.property("age"));
        List names = session.createCriteria(Student.class).setProjection(pl).list();
        Object res = session.createCriteria(Student.class).setProjection(Projections.rowCount()).uniqueResult();
        Object res = session.createCriteria(Student.class).setProjection(Projections.avg("score")).uniqueResult();
        Object res = session.createCriteria(Student.class).setProjection(Projections.max("score")).uniqueResult();
        List lists = session.createCriteria(Student.class).setProjection(Projections.projectionList().add(Projections.rowCount()).add(Projections.property("teacher.id")).add(Projections.groupProperty("teacher.id"))).list();
        List students = session.createCriteria(Student.class).createAlias("teacher","t").add(Restrictions.eq("t.id",1)).list();
        List students = session.createCriteria(Student.class).createCriteria("teacher").add(Restrictions.eq("t.id",1)).list();
        List students = session.createCriteria(Student.class).createAlias("teacher","t").add(Restrictions.gt("age",100)).add(Restrictions.eq("t.id",1)).list();
        List students = session.createCriteria(Student.class).add(Restrictions.gt("age",100)).createCriteria("teacher").add(Restrictions.eq("id",1)).list();
        List students = session.createCriteria(Student.class).setFetchMode("teacher",FetchMode.JOIN).list();
        DetachedCriteria dc = DetachedCriteria.forClass(Student.class);
        List students = dc.getExecutableCriteria(session).list();
        DetachedCriteria dc = DetachedCriteria.forClass(Teacher.class);
        dc.setProjection(Projections.property("id"));
        List students = session.createCriteria(Student.class).add(Property.forName("id").in(dc)).list();
本地sql查询
    说明
        Native Sql Query原生的sql查询
        要求写sql语句
        SQLQuery 是 Query的子类
    步骤
        1.获取Session
        2.写sql语句
        3.SQLQuery sqlquery = session.createSQLQuery(sql);
        4.如果hql语句中有占位符,就需要为占位符赋值. sqlquery.setParameter("索引号", "值");
            如果需要分页查询就需要为limit ?,? 这两个问号赋值
            第一个问号:sqlquery.setFirstResult((pageIndex - 1) * pageSize);
            第二个问号:sqlquery.setMaxResults(pageSize);
        5.获取查询查询结果
            如果本次查询有多条记录返回:sqlquery.list();
            如果本次查询只有一条记录返回:sqlquery.uniqueResult(); 
    API
        addEntity(Class entityType)
            实体查询
        addScalar(String columnAlias)
            标量查询
        addJoin(String tableAlias, String path)
            关联查询
    使用
        List students = session.createSQLQuery("select * from student").addEntity(Student.class).list();
        List students = session.createSQLQuery("select * from student").addEntity("com.shuai.domain.Student").list();
        List lists = session.createSQLQuery("select s.name,s.age from student as s").list();
        List lists = session.createSQLQuery("select * from student as s").addScalar("s.name").addScalar("s.age").list();
        List lists = session.createSQLQuery("select s.*,t.* from student s,teacher t where s.id = t.id").addEntity("s",Student.class).addEntity("t",Teacher.class).addJoin("t","s.teacher").addScalar("s.name").list();
    命名查询
        第一种方式
            用xxx.hbm.xml
            步骤
                1.提供一个配置文件(xxx.hbm.xml)
                    
                    
                    
                        
                            SELECT s.*,t.* FROM stu_info AS s, tea_info AS t WHERE s.t_id = t.tea_id
                            
                            
                            
                            
                            
                            
                            
                        
                        
                            {call query_stu(?)}
                            
                        
                    
                2.在hibernate.cfg.xml文件中配置xxx.hbm.xml
                    
                3.使用
                    List lists = session.getNamedQuery("sql_1").list();
        第二种方式
            在持久化类上加注解
            步骤
                1.在实体类上加注解
                    @NamedNativeQuery(name="sql_2", resultSetMapping="rs", query="SELECT s.*,t.* FROM stu_info AS s, tea_info AS t WHERE s.t_id = t.tea_id")
                    @SqlResultSetMapping(name="rs", entities={@EntityResult(entityClass=Student.class), // 实体查询
                                          @EntityResult(entityClass=Teacher.class)},
                                columns={@ColumnResult(name="s.stu_name")}) // 标量要询
                    public class Student{}
                2.使用
                    List lists = session.getNamedQuery("sql_2").list();
                    List lists = session.getNamedQuery("call_proc").setParameter(0, 20).list();
    Hibernate调用存储过程
        第一种方式:用命名查询的方法
            List lists = session.getNamedQuery("call_proc").setParameter(0, 20).list();
        第二种方式:直接用session.createSQLQuery()调用.
            List lists = session.createSQLQuery("{call query_stu(?)}").addEntity(Student.class).setParameter(0, 20).list();
 
 

hibernate批处理

概述
    如果有10w条数据需要一次性插入到数据库表.这个时候用Hibernate做添加的话有可能会出现内存溢出
批量添加
    for(int i = 0; i < 100000; i++){
        Teacher t = new Teacher();
        session.save(t);    
        // t : 持久化状态,持久化状态的对象是放在Session的一级缓存中,因为一级缓存是放在内存中.(10w对象存放在内存中)
        // 当一级缓存中的对象达到一定数量,那就把一级缓存中的对象同步到底层的数据库,再清空一级缓存,释放内存
        if (i % 10 == 0){
            // 把一级缓存中的对象同步到底层的数据库
            session.flush();
            // 清空一级缓存,释放内存
            session.clear();
        }
    }
    session.commit();
批量修改
    for (int i = 1; i <= 100000; i++){
        // t : 持久化状态,持久化状态的对象是放在Session的一级缓存中,因为一级缓存是放在内存中.(10w对象存放在内存中)
        Teacher t = (Teacher)session.get(Teacher.class, i);
        t.setAge(28);
        // 当一级缓存中的对象达到一定数量,那就把一级缓存中的对象同步到底层的数据库,再清空一级缓存,释放内存
        if (i % 10 == 0){
            // 把一级缓存中的对象同步到底层的数据库
            session.flush();
            // 清空一级缓存,释放内存
            session.clear();
        }
    }
    session.commit();
批量删除
    for (int i = 1; i <= 100000; i++){
        // t : 持久化状态,持久化状态的对象是放在Session的一级缓存中,因为一级缓存是放在内存中.(10w对象存放在内存中)
        Teacher t = (Teacher)session.get(Teacher.class, i);
        session.delete(t);
        // 当一级缓存中的对象达到一定数量,那就把一级缓存中的对象同步到底层的数据库,再清空一级缓存,释放内存
        if (i % 10 == 0){
            // 把一级缓存中的对象同步到底层的数据库
            session.flush();
            // 清空一级缓存,释放内存
            session.clear();
        }
    }
    session.commit();

DML风格的HQL语句

概述
    DML : Data Manipulation Language (DML) the statements: INSERT, UPDATE, DELETE
    语法 :( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?. 
操作DML风格HQL的步骤
    获取Session
    写DML风格的hql语句
    Query query = session.createQuery(hql);
        如果hql语句中有占位符需要设置参数值: query.setParameter(i, "值").
    int res = query.executeUpdate();
使用
    全部修改
        String sql = "update from Teacher set age = ?";
        int res = session.createQuery(sql).setParameter(0,20).executeUpdate();
    条件修改
        String sql = "update from Teacher set age = ? where id < ?";
        int res = session.createQuery(sql).setParameter(0,20).setParameter(1,100).executeUpdate();
    条件删除
        String sql = "delete from Teacher t where t.age = ?";
        int res = session.createQuery(sql).setParameter(0,40).executeUpdate();

hibernate数据过滤

概述
    当你做查询时,有一个查询条件永远是固定的
使用数据过滤的步骤
    1.定义数据过滤
        @FilterDef()
    2.指定哪些持久类使用该数据过滤
        @Filter()
    3.开启该数据过滤
        session.enableFilter("数据过滤的名称").setParameter("定义的过滤字段名称",过滤字段的值);
使用
    1.
        @FilterDef(name="ageFilter", parameters={@ParamDef(name="minAge", type="int")})
        public class Teacher{}
    2.
        @Filter(name="ageFilter", condition="age > :minAge")
        public class Student{}
    3.
        session.enableFilter("ageFilter").setParameter("minAge", 20);
        List students = session.createQuery("select t from Student t").list();

hibernate连接池

支持c3p0.
使用时配置hibernate.cfg.xml
    3
        最小连接数
    6
        最大连接数
    100
        一次执行的最大sql命令的个数
    2
        连接不够用一次增加多少个连接
    5000
        连接超时时间
    3000
        连接空闲测试时间

hibernate缓存

为什么使用缓存
    减少数据库访问次数,提高程序运行效率
一级缓存 
    session
    缓存不共享,每个session维护自己独立的缓存区,session关闭后,缓存销毁
    特点:缓存时间短范围小,效果不太明显.
    跟Session相关(存放在内存中)
    默认是开启的
    作用:提高CUD操作的性能
    操作
        boolean contains(Object object)
            判断Session的一级缓存中是否包含一个对象,包含的话这个对象就是持久化状态。
        void  evict(Object object)
            从Session的一级缓存中逐出一个对象.(该对象就不是持久化状态的对象).
        void  flush()
            将Session的一级缓存中的对象,同步到底层数据库表中.(立即同步)
        void  clear()
            清空Session的一级缓存,所有的持久化状态的对象都清空。(释放内存)
        void close()
            关闭Session,先调用flush(),再调用clear().
二级缓存
    基于sessionFactory的缓存
    二级缓存的内容,可以给多个session访问,二级缓存数据可以给所有的session共享.
    跟SessionFactory相关,因为SessionFactory存活的时间长。
    默认是关闭的.
    作用:提高查询效率.
    特点:缓存资源,整个应用程序都可以使用.范围比较大.
    使用二级缓存:
        1.需要指定哪些类需要放入二级缓存区域
        2.放入缓存的数据,要符合这样的特点,不要经常修改
    hibernate的二级缓存是以插件的形式提供给开发程序员使用的,且有已经实现好的插件.
    用的时候直接引入即可(hibernate.cfg.xml)配置.
    二级缓存中的对象存放到哪里,这个需要配置.
    一般会配置内存中存放一些对象,超出了内存中放存的对象个数,就写入磁盘.
    ehcache.xml (配置二级缓存对象存放的配置文件).
    HashtableCacheProvider使用步骤:
        1.hibernate.cfg.xml配置开启二级缓存
            true
        2.hibernate.cfg.xml配置使用哪个二级缓存框架
            org.hibernate.cache.HashtableCacheProvider
        3.配置指定哪些类加入缓存
            第一种配置hibernate.cfg.xml
                
                    read-only/read-write
            第二种配置User.hbm.xml
                
        4.开启对象中的集合缓存-注意集合中的对象也要加入缓存
            
            
        5.注意:
            以上配置是对get查询方式配置的.
        6.如果需要对Hql查询也可以读取二级缓存,还需要配置
            true
        7.并且使用HQL查询时写法要注意
            User user =(User) session.createQuery("from User where id=1").setCacheable(true);//数据要加入二级缓存/数据从二级缓存中取
    EhCacheRegionFactory使用
        1.配置开启二级缓存hibernate.cfg.xml文件中配置开启二级缓存.
            true
            org.hibernate.cache.ehcache.EhCacheRegionFactory
        2.拷贝二级缓存需要的jar包
            ehcache-core-2.4.3.jar、hibernate-ehcache-4.3.8.Final.jar、slf4j-api-1.7.2.jar、slf4j-jdk14-1.7.2.jar
        3.拷贝ehcache.xml文件
            
                
                
                
            
        4.配置哪些持久化类用二级缓存
            第一种方式:hibernate.cfg.xml文件中配置
                
            第二种方式:注解配置
                @Cache(usage=CacheConcurrencyStrategy.READ_WRITE,region="shuaiCache")
        5.操作二级缓存的方法
            Cache cache =  SessionFactory.getCache();
                获取缓存对象
            boolean containsEntity(Class entityClass, Serializable identifier)
                判断二级缓存中在是否包含一个对象
                boolean containsEntity(String entityName, Serializable identifier)
            void evictAllRegions();
                清空二级缓存中所有对象
            void evictEntity(Class entityClass, Serializable identifier)
                从二级缓存中踢出指定的对象
                void evictEntity(String entityName, Serializable identifier)
            void evictEntityRegion(Class entityClass)
                从二级缓存中踢出指定类型所有的对象
                void evictEntityRegion(String entityName)   
        6.查询缓存(缓存的是查询语句)
            
        7.获取二级缓存的统计信息
            1.配置生成统计信息(hibernate.cfg.xml)
                true
                true
            2.获取统计信息
                Statistics statistics = sessionFactory.getStatistics();
                命中的数量:statistics.getSecondLevelCacheHitCount()
                错失的数量:statistics.getSecondLevelCacheMissCount()
        8.对象在二级缓存中用什么格式保存
            Map集合
                key:主键列的值
                value:缓存对象,该对象对需要缓存的对象中的数据做了封装.
            SecondLevelCacheStatistics scs = statistics.getSecondLevelCacheStatistics("com.shuai.domain.Student");
            scs.getEntries();
查询缓存(缓存的是查询语句)
    概述
        默认也是关闭的
        它是在二级缓存的基础之上
    使用步骤
        1.配置开启查询缓存(hibernate.cfg.xml)
            true
        2.在创建查询时需要设置是否缓存这条语句.
            query.setCacheable(true);
            List students = session.createQuery("select s from Student s join fetch s.teacher").setCacheable(true).list();
    查询缓存的缓存数据格式
        {"sql语句" : {"org.fkjava.hibernate.domain.Student" : [1,2,3,4,5,6],"org.fkjava.hibernate.domain.Teacher" : [1,2]}}
        注意:它要求hql语句要一致,而且hql语句中的占位符赋值也要一致,才能命中!     

Session的线程安全问题

概述
    如果是Hibernate3.1之前版本,它提供了HibernateUtil工具类可以获取当前线程相关的Session.
    如果是Hibernate3.1之后版本,它提供了可配置的方式,让我们把Session配置成线程相关的Session.
把Session配置成线程安全
    在hibernate.cfg.xml中配置
    jta|thread
        org.hibernate.context.internal.JTASessionContext : jta (全局事务)
        org.hibernate.context.internal.ThreadLocalSessionContext : thread (jdbc事务)
使用
    Session session = session.getCurrentSession();
    注意:
        不要调用session.close();

面向JPA编程

Hibernate4编程
    Configuration
    SessionFactory
    Session
    Transaction
    Query query = session.createQuery(hql);
    Criteria criteria = session.createCriteria();
    SQLQuery sqlquery = session.createSQLQuery(sql);
    src/hibernate.cfg.xml
JPA编程
    Persistence
    EntityManagerFactory
    EntityManager
    EntityTransaction
    Query query = entityManager.createQuery(jpql);
    Query query = entityManager.createQuery(CriteriaQuery);
    Query query = entityManager.createNativeQuery(sql);
    src/META-INF/persistence.xml
JPQL
    Java Persistence Query Language  
    java持久化查询语言.
web项目引入jpa
    1.创建JPA项目
        new --> jpa --> jpa project --> jpa fact(jpa implementation type:disable library configuration)
        需要项目src中的META-INF文件夹和文件夹中的persistence.xml
        把这个文件夹拷贝到我们自己的web项目的src目录即可。
    2.修改persistence.xml
        在hibernate-entitymanager-xxx.jar/org.hibernate.jpa/persistence_2_1.xsd文件中拷贝文件头即可
        
        
    3.配置持久化单元persistence-unit
        
        
        name : 持久化单元名称
        transaction-type : JTA|RESOURCE_LOCAL事务
    4.配置JPA的提供商(实现商)
        org.hibernate.jpa.HibernatePersistenceProvider
    5.配置持久化类
        com.shuai.domain.Teacher
    6.配置属性
        
            
            
            
            
            
            
            
            
            
            
        
    7.使用
        public void oneTest(){
            // 第一步:创建EntityManagerFactory
            EntityManagerFactory emf = Persistence.createEntityManagerFactory("shuaijpa");
            // 第二步:创建EntityManager 
            EntityManager em = emf.createEntityManager();
            // 第三步:获取事务
            EntityTransaction transaction = em.getTransaction();
            // 第四步:开启事务
            transaction.begin();
            // 第五步:利用 EntityManager完成所有的持久化操作
            Teacher t = new Teacher();
            t.setName("帅哥");
            t.setDept("开发部");
            t.setAge(30);
            em.persist(t);
            // 第七步:事务提交或回滚
            transaction.commit();
            // 第八步:关闭EntityManager与EntityManagerFactory
            em.close();
            emf.close();
        }
增加
    第一种方式
        Teacher t = new Teacher(); // 瞬态
        t.setAge(20);
        t.setName("帅哥");
        t.setDept("开发部");
        t.setJob("项目经理");
        em.persist(t); // 持久化状态
        System.out.println(em.contains(t)); // 判断一个对象是不是持久化状态
    第二种方式
        Teacher t = new Teacher(); // 瞬态
        t.setAge(20);
        t.setName("帅哥");
        t.setDept("开发部");
        t.setJob("项目经理");
        Teacher t1 = em.merge(t); // t1 持久化状态
        System.out.println(em.contains(t1));
删除
    Teacher t = em.find(Teacher.class, 4); // t 持久化状态
    em.remove(t);
修改
    持久化状态下
        Teacher t = em.find(Teacher.class, 1); // t 持久化状态
        t.setAge(300);
    脱管状态下
        Teacher t = new Teacher();
        t.setId(1);
        t.setAge(100);
        t.setName("admin");
        em.merge(t);
查询
    Teacher t = em.find(Teacher.class, 1); // t 持久化状态 
    System.out.println(em.contains(t)); // 判断一个对象是不是持久化状态
操作一级缓存中的方法
    boolean contains(Object object)
        判断EntityManager的一级缓存中是否包含一个对象,包含的话这个对象就是持久化状态。
    void  detach(Object object)
        从EntityManager的一级缓存中逐出一个对象.(该对象就不是持久化状态的对象).
    void  flush()
        将EntityManager的一级缓存中的对象,同步到底层数据库表中.(立即同步)
    void  clear()
        清空EntityManager的一级缓存,所有的持久化状态的对象都清空。(释放内存)
    void close()
        关闭EntityManager,先调用flush(),再调用clear().
三套查询
    第一套查询(JPQL查询)
        查询步骤
            1.获取EntityManager
            2.写jpql语句
            3.Query query = entityManager.createQuery(jpql);
            4.如果hql语句中有占位符,就需要为占位符赋值. query.setParameter("索引号", "值");
                如果需要分页查询就需要为limit ?,? 这两个问号赋值
                第一个问号:query.setFirstResult(start);
                第二个问号:query.setMaxResults(size);
            5.获取查询查询结果
                如果本次查询有多条记录返回:query.getResultList();
                如果本次查询只有一条记录返回:query.getsingleResult();
        使用
            List lists = em.createQuery("select s from Student as s", Student.class).getResultList();
            List lists = em.createQuery("from Student", Student.class).getResultList();
            List> lists = em.createQuery("select new map(name as name, age as age) from Student").getResultList();
            List lists = em.createQuery("from Student", Student.class).setFirstResult(start).setMaxResults(size).getResultList();
        命名查询
            @NamedQuery(name="query_1", query="select s from Student s join fetch s.teacher")
            public class Teacher {}
            List lists = em.createNamedQuery("query_1").getResultList();
    第二套查询(sql查询)
        查询步骤
            1.获取EntityManager.
            2.写sql语句.
            3.查询
                Query query = createNativeQuery(String sqlString); // 查询多列
                Query query = createNativeQuery(String sqlString, Class resultClass); // 实体查询
                Query query = createNativeQuery(String sqlString, String resultSetMapping); // 关联查询
            4.如果hql语句中有占位符,就需要为占位符赋值. query.setParameter("索引号", "值");
                如果需要分页查询就需要为limit ?,? 这两个问号赋值
                第一个问号:query.setFirstResult((pageIndex - 1) * pageSize);
                第二个问号:query.setMaxResults(pageSize);
            5.获取查询查询结果:
                如果本次查询有多条记录返回:query.getResultList();
                如果本次查询只有一条记录返回:query.getsingleResult();
        使用
            List lists = em.createNativeQuery("select * from stu_info", Student.class).getResultList();
            List lists = em.createNativeQuery("select * from stu_info").getResultList();
            List lists = em.createNativeQuery("select s.*, t.* from stu_info as s, tea_info as t where s.t_id = t.tea_id", "rs").getResultList();
            @SqlResultSetMapping(name="rs" , entities={@EntityResult(entityClass=Student.class),@EntityResult(entityClass=Teacher.class)},columns={@ColumnResult(name="s.stu_name")})
            public class Student {}
    第三套查询(CriteriaQuery查询)
        查询步骤
            1.获取EntityManager.
            2.Query query = entityManager.createQuery(CriteriaQuery);
            3.如果需要分页查询就需要为limit ?,? 这两个问号赋值
                第一个问号:query.setFirstResult(start);
                第二个问号:query.setMaxResults(size);
            4.获取查询查询结果:
                如果本次查询有多条记录返回:query.getResultList();
                如果本次查询只有一条记录返回:query.getsingleResult();
        API
            CriteriaBuilder
                构建查询对象的类.
                构建CriteriaQuery
                生成查询条件
                生成排序
                生成聚集函数
            CriteriaQuery 
                查询对象类
                Root from(Class entityClass) : 指定查询哪个持久化类.
                groupBy(Expression... grouping) : 分组
                multiselect(Selection... selections) : 查询多列 
                select(Selection selection) : 查询一列
                where(Predicate... restrictions) :  添加查询条件
                orderBy(Order... o): 排序
            Root
                对查询的持久化类中的属性做了封装.
                Path path =  root.get("属性名");
                join() : 关联查询 root.join("teacher", JoinType.INNER);
                fetch() : 抓取连接.
            Path
                代表一个属性
        使用
            查询所有的学生
                CriteriaBuilder builder = em.getCriteriaBuilder();
                CriteriaQuery cq = builder.createQuery(Student.class);
                Root root = cq.from(Student.class);
                List lists = em.createQuery(cq).getResultList();
            查询一列
                CriteriaBuilder builder = em.getCriteriaBuilder();
                CriteriaQuery cq = builder.createQuery(String.class);
                Root root = cq.from(Student.class);
                Path name = root.get("name");
                cq.select(name);
                List lists = em.createQuery(cq).getResultList();
            查询多列
                CriteriaBuilder builder = em.getCriteriaBuilder();
                CriteriaQuery cq = builder.createQuery(Object[].class);
                Root root = cq.from(Student.class);
                Path name = root.get("name");
                Path age = root.get("age");
                cq.multiselect(name, age);
                List lists = em.createQuery(cq).getResultList();
            添加查询条件
                CriteriaBuilder builder = em.getCriteriaBuilder();
                CriteriaQuery cq = builder.createQuery(Student.class);
                Root root = cq.from(Student.class);
                Path name = root.get("name");
                Path age = root.get("age");
                cq.where(builder.like(name, "%小%"), builder.between(age, 19, 200));
                List lists = em.createQuery(cq).getResultList();
            排序
                CriteriaBuilder builder = em.getCriteriaBuilder();
                CriteriaQuery cq = builder.createQuery(Student.class);
                Root root = cq.from(Student.class);
                Path age = root.get("age");
                cq.orderBy(builder.desc(age));
                List lists = em.createQuery(cq).getResultList();
            统计函数
                CriteriaBuilder builder = em.getCriteriaBuilder();
                CriteriaQuery cq = builder.createQuery(Integer.class);
                Root root = cq.from(Student.class);
                Path age = root.get("age");
                cq.select(builder.sum(age));
                Integer res = em.createQuery(cq).getSingleResult();
            关联查询
                CriteriaBuilder builder = em.getCriteriaBuilder();
                CriteriaQuery cq = builder.createQuery(Student.class);
                Root root = cq.from(Student.class);
                root.join("teacher", JoinType.INNER);
                Path t_id = root.get("teacher").get("id");
                cq.where(builder.equal(t_id, 1));
                List lists = em.createQuery(cq).getResultList();
            抓取连接
                CriteriaBuilder builder = em.getCriteriaBuilder();
                CriteriaQuery cq = builder.createQuery(Student.class);
                Root root = cq.from(Student.class);
                root.fetch("teacher", JoinType.INNER);
                List lists = em.createQuery(cq).getResultList();

hibernate逆向工程

1.准备myeclipse
2.window-->show view-->DB browser
3.在db browser中 new 数据库
    Driver timplate 选择 mysql
    Driver name 直接写一个别名
    Connection URL :jdbc:mysql:///test
    user name:root
    password:root
    Driver JARS:驱动包位置
    Driver className:com.mysql.jdbc.Driver
4.创建一个新的webhibernate项目
5.右键webhibernate项目-->myeclipse-->project facts[capabilities]-->install hibernate facet
6.设置hibernate版本 hibernate specification version :3.3
7.设置targer runtime :myeclipse generic runtime for javaee 6.0
8.需要配置文件hibernate.cfg.xml
9.java源码配置java.package:com.shuai.test
10.className:HibernateSessionFactory
11.设置一个DB driver:第三步配置过了
12.添加包
13.选择要逆向的表
    右键-->hibernate reverse Engineering
14.选择java package 选择路径
15.create pojo
16.create data object
17.finish即可

OpenSessionInView

在过滤器/拦截器中开启session,在jsp页面处理完数据之后,再关闭session即可
Interceptor
    public class SessionInterceptor  extends AbstractInterceptor {
        @Override
        public String intercept(ActionInvocation invocation) throws Exception {
            Transaction tx = null;
            try {
                // 1. 创建session
                Session session = HibernateUtils.getSession();
                // 2. 开启事务
                tx = session.beginTransaction();
                // 3. 放行
                String result = invocation.invoke();  //  // execute处理完,就表示 jsp已经处理完毕
                return result;
            } catch (Exception e) {
                tx.rollback();
                e.printStackTrace();  // 打印错误信息!
                return "error";
            } finally {
                // 4. (执行完action.execute方法), 提交事务
                tx.commit();
            }
        }
    }
HibernateUtils
    public class HibernateUtils {
        private static SessionFactory sf;
        static {
            sf = new Configuration().configure().buildSessionFactory();
        }
        public static Session getSession() {
            return sf.getCurrentSession();
        }
    }
Controller
    public class DeptAction extends ActionSupport{
        private int id;
        public void setId(int id) {
            this.id = id;
        }
        private Dept dept;
        public Dept getDept() {
            return dept;
        }
        public void setDept(Dept dept) {
            this.dept = dept;
        }
        // 创建service
        private DeptService deptService = new DeptService();
        @Override
        public String execute() throws Exception {
            // 主键查询
            dept = deptService.findById(id);
            return SUCCESS; // execute处理完,就表示 jsp已经处理完毕
        }
    }
jsp使用
    
        
            
            
            
        
    

session的创建方式

第一种方式-openSession 
    Session session = sf.openSession();
    注意:
        1.每次获取的Session不同
        2.可以不使用事务
第二种方式-线程方式创建Session
    Session session = sf.getCurrentSession();
    注意:
        1.一定要配置以线程的方式创建Session
            thread
        2.创建的Session,提交事务,自动关闭session
        3.使用getCurrentSession方法必须要有事务环境

联合主键

Keys.java - 联合主键,必须实现可序列化标记
    public class Keys implements Serializable{
        private String name;
        private String address;
    }
User.java
    public class User {
        private Keys key;
        private int age;
    }
User.hbm.xml
    
    
    
        
            
                
                
            
            
        
    
AppTest.java
    @Test
    public void save() {
        Session session = sf.openSession();
        session.beginTransaction();
        Keys key = new Keys();
        key.setName("Jack");
        key.setAddress("gz");
        User user = new User();
        user.setKey(key);
        user.setAge(20);
        session.save(user);
        session.getTransaction().commit();
        session.close();
    }
    @Test
    public void get() {
        Session session = sf.openSession();
        session.beginTransaction();
        Keys key = new Keys();
        key.setName("Jack");
        key.setAddress("gz");
        User user = (User) session.get(User.class, key);
        System.out.println(user.getKey().getName());
        System.out.println(user.getKey().getAddress());
        System.out.println(user.getAge());
        session.getTransaction().commit();
        session.close();
    }

基础hql查询

//查询全部
@Test
public void queryAll() {
    Session session = sf.openSession();
    session.beginTransaction();
    Query q = session.createQuery("from User");
    List list = q.list();
    session.getTransaction().commit(); 
    session.close();
}
//删除
@Test
public void delete() {
    Session session = sf.openSession();
    session.beginTransaction();
    Query q = session.createQuery("delete from User where id=1)");
    q.executeUpdate();
    session.getTransaction().commit(); 
    session.close();
}
//分页
@Test
public void page() {
    Session session = sf.openSession();
    session.beginTransaction();
    Query q = session.createQuery("from User");
    // 设置分页参数
    q.setFirstResult(0);  //相当于 limit 第一个参数  查询的其实行
    q.setMaxResults(2);   //相当于 limit 第二个参数 查询返回的行数
    List list = q.list();
    session.getTransaction().commit(); 
    session.close();
}

Hql查询

API
    Query
        list();//查询全部
    
Query query = session.createQuery("from User");
List list = query.list();//会懒加载 
    注意:会有一级缓存,缓存数据.一个id的数据只查询一次
连接查询
    Query query = session.createQuery("from Address a inner join a.user");
    List list = query.list();//即时查询,连接查询可以解决懒加载问题.

fetch查询
    把右表的数据填充到左表
    添加fetch查询语句sql没有任何变化,变化的是封装数据的方式
    Query query = session.createQuery("from Address a inner join a.user"); 
    Query query = session.createQuery("from Address a inner join fetch a.user"); 

你可能感兴趣的:(hibernate)