操作数据库7步骤 :
        1 创建一个SessionFactory对象
        2 创建Session对象
        3 开启事务Transaction : hibernate中,然后数据库操作,都必须是事务的,哪怕是查询
        4 执行数据保存操作(必须提交,才会执行对应的操作方法)
        5 提交事务
        6 关闭Session
                session.close();
                getCurrentSession();不需要手动关闭,opensession需要手动关闭
        7 关闭SessionFactory对象


//第一步
SessionFactory :

1 创建一个SessionFactory对象

    Configuration :
    
        //创建Configuration对象
    Configuration configuration = new Configuration().configuer();

    // 4.0之后为了分布式,用了这种设计  链接hibernate框架
        ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
                .applySettings(configuration.getProperties())
                .buildServiceRegistry();

    SessionFactory :

        //创建一个SessionFactor对象
         SessionFactory sessionFactiony = null;

         给SessionFactory对象赋值

            sessionFactory = configuration.buildSessionFactory(serviceRegistry);
                //或  SessionFactory sessionFactiony  = configuration.buildSessionFactory(serviceRegistry);//也行,一样
    
//第二步
Session :
   
    2 创建 Session对象
        //用上面创建好的SessionFactory对象,调用方法,创建一个session对象
    (1) Session session = sessionFactory.getCurrentSession();
    (2) Session session = sessionFactory.opensession();

    getCurrentSession :
        
        创建session对象 如果有,就不创建,如果没有就创建
        Session session = sessionFactory.getCurrentSession();
        并且,自动关闭资源 不用写 session.close();

    opensession :

        创建session对象,别管有没有,都创建
        Session session = sessionFactory.opensession();

        并且,用手动关闭资源,
            session.close();

//第三步
Transaction :

    3 开启事务:hibernate中,然后数据库操作,都必须是事务的,哪怕是查询
        Transaction transaction = session.beginTransaction();

//第四步

    4 执行数据保存操作

    //增
    Save :

     Save();//添加语句方法,生成insert into 表名(列,列)values(?,?)

    //删    
    Delete :

        Delete();//删除语句方法,生成delete from 表 where id=?;

    //改
    Update :

        Update();//修改语句,
            //如果表里面有对应的语句,就生成修改语句update 表名 set (列名,列名)=(列值,列值) where id = ?;

    //查
    Load :

        Load();//查询语句方法,生成查询语句,select * from 表 where id=?
        //如果不访问里面的属性,就只是查询一下,并不会执行到数据库,除非用里面每行对应的对象,去调用一个属性,才会真正的到数据库
        //如果只是提交了,没有访问里面的属性,不会生成查询语句,就是没有对数据库进行操作

    Get :

        Get();//查询语句方法,生成查询语句,select * from 表 where id=?
        //只要提交,就会生成查询语句,

//Get()和Load()的区别   Load()和Get()的区别

        Get() : 只要调用Get()方法并提交,就直接生成查询语句去访问数据库
        Load() : 要调用Load()方法并提交,且,如果没有访问对象里面的属性,不会生成查询语句,也不会操作数据库,一定要获取一下属性,获取对象引用,也算获取属性

//第五步
commit :
     5 提交事务
        transaction.commit();// 提交事务
        transaction是第三步,开启事务的对象

//第六步
Session_close :
    6 关闭Session
        // session.close();//getCurrentSession();不需要手动关闭,opensession需要手动关闭

 //第七步
    SessionFactory_close :
    7 关闭SessionFactory对象
        sessionFactory.close();

//强注解,强注释

  !!!对表来说,只有多的一方保存少的一方的引用,那些设置都是给程序看的,和数据库没有任何关系!!!

@ :
    @Entity 在类名上面加的,用于创建表 默认是类名
        创建实体类和数据标的映射,指定表名
        将一个类声明为一个实体bean(即一个持久化POJO类)。
        @Entity(name="表名")  这样也行,就规定了表名

        @Table :
            @Table(name="表名");也行
     //1 必须得加:
    
    @IdClass 让两个类关联起来 后面是类名  
        在类上面写
        联合主键,就是把主键都写在后面指定的类中
        @IdClass(value=StudentPK.class)
   
        
    @Column 设置当前列在修改的时候,是否可以被修改
        在实体类的get**()方法上写 , 就是对于的列
        @Column(updatable=false)  false就是修改的时候,这个列不能被修改
        里面对应的值 :
            
            name 指定列名(默认是属性名)

            unique 设置该列是否设置唯一约束 默认值是false

            nullable 设置该列的值是否可以为空,默认值是false

            insertable 该列是否作为生成insert语句中的一个列,默认值是true  就是添加的时候,不在此列添加值

            updatetable 该列是否作为生成updatetable语句中的一个列,默认是true  就是修改的时候,不修改此列

            columnDefinition   为这个特定列覆盖sql ddl片段(这可能导致无法在不同数据库间移植)  

            table 定义对应的表 默认为主表

            length 列长度, 默认值255

            precision 列十进制精度(decimal precision) 默认值0   此列最大值为N位  位数

            scale 如果列十进制数值范围(decimal scale)可用,在此设置,默认值0

从数据库查询出来的数据,我都保存在这里
    DTO : 叫Date Traction Object
    VO : 值对象 Value Object


    @SequenceGenerator :
        序列生成器
            @SequenceGenerator(name="sequenceGenerator",sequenceName="Msg_SEQ",initialValue=0,allocationSize=1)//生成器名字,序列的名字,起始值为0,步长为1

    @TableGenerator   生成器 写在类上面
    //用来存放实体类对应的表,下一次要用的id(存放id的表)
    //为主键单独创建一个表,可以跨数据库平台,MySQL主键自增是自己指定,不是外界指定,可能相同

    //有什么好处,能够解决数据跨平台保存的问题,因为不同的数据库平台生成数据的方式不一样,比如primary key(pk),如何还能保证呢?自己写个类库,兼容不同平台
//这里的方式是新建一张表,专门用于保存ID,表名:GENERATOR_TABLE,表里面有两列
//第一列,保存pkColumnName="key", 主键所在列的名字
//第二列,保存Id值 valueColumnName="studentId"
//第三列和第四列保存的是值:第三列是key的值,就是要保存id的表名,第四列要保存的步进值,初始值默认是一
//这就意味着,该表可以为无数的表保存Id值,只要对应的表来去一次值,id默认就会加一.有点像一个序列的集合

    @TableGenerator( //生成器
        name = "student_GEN",//生成器的名字
        table = "GENERATOR_TABLE",    //在数据库中,表的名字
        pkColumnName = "key", //主键所在列的名字
        valueColumnName = "studentId",    //保存下一次,要保存id列的数据,是去这里取得的ID的值
        pkColumnValue = "Student",    //指定要用到Id的那张表
        initialValue=1,             //起始值为1
        allocationSize = 1          //步长为1
        )

    @Id 在实体类的getId()上面强注释
        获取对应的id作为列名,并能在这个方法中,获取id的值
        相当于设置表里面的主键

    @GeneratedValue //在@id和getId()直接设置的  去生成器里面拿值,让每次要添加的数据,ID不相同,不唯一  设置该列自增

    generator="生成器的名字"  //在哪个生成器取Id
    5种格式
        1 Auto   随机
        2 table   生成一个表,存放在表里面
        3 Identity  序列一类的
        4 sequence   序列生成器,生成序列化的数字
        5 自定义   自己写的
    @GeneratedValue(strategy=GenerationType.生成的格式 , generator="生成器的名字")
    @GeneratedValue(strategy=GenerationType.TABLE , generator="student_GEN")

    @OneToOne
        
        要么都写,一个写@oneToone  一个写@ManyToOne
        要么在多的里面写@ManyToOne   多的里面必须要加 unique="true" 设置唯一  就是一对一了
            
        XML : <many-to-one name="多的指向的那个类" column="多的里面那个列指向它" unique="true"></many-to-one>
    @OneToOne(mappedBy="wife")
        //我不保留对方的引用,只让对方保存我的引用,并且,是对方的wife那条属性,保存的是我的引用,
        告诉hibernate我们是一对一关系,但是映射是在husband的wife的属性做的,以那边为标准,这边不用管,但是那边的属性指向的是wife的id
        就是在对面表中,生成一个列,这个列,专门保存本表的id的引用,当本表添加的时候,就让对面表的这个列,生成一个值,当对面表添加的时候,会参考这个列,生成一个ID,当做对面表的ID
            在本实体类中,获取另外一个类的属性的get**()上面写
            @OneToOne
                告诉hibernate我们是一对一关系,但是映射是在husband的wife的属性做的,以那边为标准,这边不用管,但是那边的属性指向的是wife

    @ManyToOne

        告诉hibernate我们是多对一的关系
        
        多对一  必须写在多的里面

    @JoinTable : //更改表的名字和列的名字

    @ManyToMany//多对多

    // 想更改表的名字和列的名字
    @JoinTable(name = "t_s",  // 表名  中间表
            joinColumns = { @JoinColumn(name = "teacher_id") },// 中间表的列名
    inverseJoinColumns = { @JoinColumn(name = "student_id") })//上面的列名指向的是谁,先通过上面指定的列名,找到这个列名,就能找到student表
            
    @JoinColumn
        
        自己指定外键列的名字,还可以指定长度,约束等
        @JoinColumn(name="wifeid") 指定外键名字为wifeid  写在外键列的get外键引用()方法上面

            //在少的表,设置多的表中,保存少的表的引用的列的列名
            //多的表,保存少的表的引用的那个列的列名

    @Embedded
        
           把两个表弄成一个表,且另一个表没有@Entity,写在get**()方法上面
        @Embedded(name="asd")指定别的表,保存当前表的引用的那个列的列名

!!!只有在一对一的时候,才有主键映射和外键映射
//主键映射

        @PrimaryKeyJoinColumn
        在对面引用的列上面加 @PrimaryKeyJoinColumn 就是主键映射
        主键映射 : 不会多生成一个列,添加的时候,会去参照另一个表的主键来生成本表的主键,本表主键和另一个表的主键有关联

//外键映射
        
        @ForeignKeyJoinColumn
         @OneToOne(mappedBy="wife") //我不保留对面的引用,让对面来保存我的引用,并且是保存在对面的wife这个属性,
         //我不保存对面的引用,让对面用wife这个属性来保存我的引用
        
        外键映射 : 多生成一个列,添加的时候,这个新的列会去参照另一个表的主键,让这个列,和另一个表有关联

mappedBy :

    只要是有双向的关系,就必须保持对方的引用,必须有mappendBy(对面)(限于双向) 少的一方必须用set集合保存多的一方的引用,且两边都注明多对以@ManyToOne(多的写) 和@OneToMany(一个的写)

    对表来说,只有多的一方保存少的一方的引用,那些设置都是给程序看的,和数据库没有任何关系

@OneToMany(mappedBy="group",//就是在对面表中,生成一个列,这个列,专门保存本表的id的引用,当本表添加的时候,就让对面表的这个列,生成一个值,当对面表添加的时候,会参考这个列,生成一个ID,当做对面表的ID
            cascade={CascadeType.ALL},//设置级联操作,在什么时候起作用
            fetch=FetchType.EAGER //级联操作的时机,这里默认是Lazy因为是少的一方
            
            )

cascade :

    cascade={CascadeType.ALL/DETACH/MERGE/PERSIST/REFRESH/REMOVE/自定义};
    //设置级联操作在什么时候起作用,就是A的增删改查,B也有改变,就相当于是绑定了事件,后面的值,就是事件,当触发这个事件的时候,就A,B两个表的属性都更新同步,级联操作
        ALL : 是所有操作都级联
        DETACH :
        MERGE : 也就是修改的时候,相当于update,级联
        REMOVE : 删除的时候,级联
        还有自定义
fetch :

    fetch=FetchType.EAGER/LAZY   //这是级联操作的时机,
        EAGER : 的时候,是比如 A里面有个列保存了B的引用,如果这里设置的是EAGER.那取出或者查看的时候,会把这个保存B的引用的那个列也拿出来,

        生成语句 :
        //生成一条查询语句

        LAZY : 的时候,是如果 A里面有个列保存了B的引用,如果这里设置的是LAZY,那取出或者查看的时候,不会把这个保存B的引用的那个列拿出来,只取出别的列,如果在关闭session对象(缓冲)之前,用到那个保存B的引用的那个列,就会再生成一个查询语句,去数据库查询,再把那个列拿出来

         生成语句 :
        //如果用到保存B引用的那个列,就会生成两个查询语句,否则就是生成一个查询语句,并且第一次查询语句中不包括保存B引用的那个列

//执行顺序
@Before/@BerforeClass -- > @Test --> @After/@AfterClass

    @Before :
        
        用于测试类中 , 用它强注释的,是第一个执行的,
        测试方法是成员方法 此方法是公共的,没有返回值的,没有参数列表的,成员方法

    @BerforeClass
        
        用于测试类中 , 用它强注释的,是第一个执行的,
        测试方法是静态方法  此方法是公共的,静态的,没有返回值的,没有参数列表的,静态方法

    @Test :
        
        测试方法 :
            1 公共的 的成员方法
            2 没有返回值
            3 没有形参列表

    @After :
        
        用于测试类中 , 用它强注释的,是最后一个执行的,
        测试方法是成员方法 此方法是公共的,没有返回值的,没有参数列表的,成员方法

    @AfterClass :
        
         用于测试类中 , 用它强注释的,是最后一个执行的,
        测试方法是静态方法  此方法是公共的,静态的,没有返回值的,没有参数列表的,静态方法

//三种状态 :

        瞬时状态(临时状态)--->持久状态(保存到数据库)--->游离状态(保存完成后关闭session对象 (session.close()))
    
    //三种状态的区分关键在于
        1 有没有ID
        2 ID在数据库中有没有
        3 内存中有没有(session缓存)
        
 Transient :

    Transient(瞬时状态) : 内存中一个实体类对象,没有ID,缓存中也没有
    //实例化实体类的时候,就是瞬时状态

 Persistent :

    Persistent(持久状态) : 内存中有,缓存中有,数据库中有(ID)
    //保存到数据库中,就是持久状态

 Detached :

    Detached(游离状态) : 内存有,缓存没有,数据库有,ID
    //关闭session对象之后(session.close()),就是游离状态

    //这三种状态需要关注的问题是在该状态下,如果进行数据库操作会发生什么结果,比如改变属性的值会不会发出update语句
        
        瞬时状态 : 不会发出update语句
        持久状态 和 游离状态 都会发出update语句
    
//联合主键

    @EmbeddedId : 嵌入的,写在实体类中,主键类的引用上面,对应的get主键类();方法上面
    @Embeddable : 可被嵌入的,该类作为另一个类的一部分,写在主键类中,
    1
    @IdClass :
    比如说是两个主键,id和name列,就在实体类中的getId()和getName()上面,加@id 声明主键,并且在类上面写 @IdClass(写的主键类名.class),    再把这两个主键写在一个实体类中,
    但是这个存有多个主键的实体类,必须实现serializable这个接口
    在主键类的类上面,不用写@Embeddable

  2
    @EmbeddedId :
    或者是本类中不写id和name,但是有主键类的引用,然后在主键类对应的get主键类();方法上面,写个@EmbeddedId,就行了
    但是在主键类的类上面,要写@Embeddable
        


//关联两个表

    new SchemaExport(new AnnotationConfiguration().configure()).create(false, true);

//面向对象的形式 :

HQL :

Query :

//-----------------简单的查询--------------

        Query q = session.createQuery("from Category ");//Category是对象,不是数据库里面的表
        简单的查询,就是select * from category;//这个是数据库里面的表名

        List<Category> topics = q.list(); //这个是获取查询之后的对象,然后遍历集合,获取每个属性
        for (Category t : topics) {//foreach遍历,只能遍历集合与数组  遍历获取的list集合中的对象的属性
            System.out.println(t.getId() + "-" + t.getTitle());
        }

//----------------------where限定查询

    Query q = session.createQuery("from Category c where c.name > 'c5'");//Category:Category那个类,c是别名,c.name是属性
    Query q = session.createQuery("from 对象 别名 where 对象里面的属性 操作 '属性值'");

//--------------------排序查询

oraer_by :

    oraer by : 排序 值有 :
                        desc 降序(从大到小)
                        asc  升序(从小到大)
    Query q = session.createQuery("from 对象 别名 oraer by 对象里面的属性 排序设置");
    Query q = session.createQuery("from Category c oraer by c.name desc");//按照Category对象里面的name属性的降序排序

//------------------去除重复

distinct :


    Query q = session.createQuery("select distinct c(别名) from 对象 别名(c) order by 对象里面的属性 排序设置");
    Query q = session.createQuery("select distinct c from Category c order by c.name desc");//按照Category对象里面的name属性的降序排序,并去除重复

//----------------预准备语句,就是SQL中带???问号的语句


    Query q = session.createQuery("from 对象 别名 where 对象里面的属性 操作 :*** and 对象里面的属性 操作 :***");


        Query q = session.createQuery("from Category c where c.id > :min and c.id < :max")//:min=?,:max=?     查询Category中 id大于 ? 且 id小于 ?

                .setInteger("min", 2)//设置对应位置的值  就是用 2 把 :min替换
                .setInteger("max", 8);

      !!!  :min 就相当于SQL语句中的 ? 问号 :冒号后面的名字,是自己指定的,用?也行  !!!

      //直接写问号
      //这里注意,他们的返回值都是一个Query对象,所以可以链式调用
      
        Query q = session.createQuery("from Category c where c.id > ? and c.id < ?")//:min=?,:max=?     查询Category中 id大于 ? 且 id小于 ?  用?也行
                q.setParameter(0, 2).setParameter(1, 8);//这里链式调用,是因为他们返回值都是一个Query对象  第一个0  是设置第一个问号  1 是设置第二个问号
                q.setParameter(0,2);//这样分开写,也行
                q.setParameter(1,8);

//--------------------------分页

        Query q = session.createQuery("from Category c order by c.name desc");//这个是对Category这个对象对应的表进行操作,别名c order by排序  以Category对象里面的name为标准 降序
        // 每页4条
        q.setMaxResults(4);
        // 从第二条开始
        q.setFirstResult(2);

setMaxResults :

        q.setMaxResults(4);//从查询的那个语句中(结果集) 每页显示多少条 int类型

setFirstResult :

        q.setFirstResult(2);//从查询的那个语句中(结果集) 从第几条开始显示 int类型

//--------------------查询特定的字段,查询指定列

取出两个字段,返回结果是个Object数组,然后封装到了List中

Query q = session.createQuery("select c.id,  c.name from Category c order by c.name desc");//查询Category对象中的 id 属性和 name 属性 别名c order by 排序 以name为准 降序
        //由于查询出来的是两列,所以肯定是数组了,以前是一个整个对象,现在是其中的属性,只能用属性装它了,所以用Object数组来装,并把这个数组弄到List数组中
        List<Object[]> categories = (List<Object[]>) q.list();

        for (Object[] o : categories) {//foreach循环  只能遍历 数组 和 集合
            //因为遍历的是Object数组 所以这里就用Object数组  : 要遍历的数组或集合
            System.out.println(o[0] + "::id---name::" + o[1]);
        }

//--------------------------多表联查

//多表联查的问题
    // 设定fetch type 为lazy后将不会有第二条sql语句
    // 多表联查,面向对象,导航式的查询语言(级联查询),topi对象的category的对象的id属性为1

    Topic中 保存了Category的引用

    Query q = session.createQuery("from Topic t where t.category.id = 1");//查询Topic 别名t 且 t中category的属性是Category的引用,通过t.cascade可以找到Category中的 id属性 为 1 的 ,然后显示全部
        List<Topic> topics = (List<Topic>) q.list();
        for (Topic t : topics) {
            System.out.println(t.getTitle());
            // lazy: 不调用就不会取
            //System.out.println(t.getCategory().getName());
        }

    
        Query q = session.createQuery("from Msg m where m.topic.category.id = 1");    //查询category的id是1的msg对象
        //msg有topic的引用
        //topic有category的引用
        //向查询msg中的属性,但是限定条件要用到category中的限定
        //就是这样 , where 先msg找到topic获得topic的引用--->在通过topic获得categroy的引用--->再去用categroy中的属性,做些限定
        
count :

        返回所有条数  返回值是long类型
        Query q = session.createQuery("select count(*) from Msg m");//返回的是一个long类型

//---------------------------使用聚合函数

    Query q = session.createQuery("select max(m.id), min(m.id), avg(m.id), sum(m.id) from Msg m");
    max(列名);//此列的最大值
    min(列名);//此列的最小值
    avg(列名);//此列的平均值
    sum(列名);//此列的值的和
    由于这里我是指定的列查询的,所以又要用到Object数组
        Object[] o = (Object[]) q.uniqueResult();
        System.out.println(o[0] + "-" + o[1] + "-" + o[2] + "-" + o[3]);//数组的第一个元素,第二个元素,第三个元素,第四个元素  因为数组的下标是从0开始的,所以0 就代表第一位

//------------------------使用条件限制

between_and :

        //值在...之间...        

        Query q = session.createQuery("from Msg m where m.id between 3 and 5");//查询msg 别名为m where限定 m的值在 3 和 5 之间

in :

    //值在(值,值,值...)里面就行
        Query q = session.createQuery("from Msg m where m.id in (3,4,5)");//msg对象中,id属性是3或4或5的,就查询出来

//-------------------------is null 与 is not null
为空和不为空
        Query q = session.createQuery("from Msg m where m.cont is not null");//查询msg中,cont属性不为空的

@NamedQuery :

    @NamedQueries( { @NamedQuery(name="名字", query="语句" ) } )
    @NamedQueries({//写在类上面
    //取特定的Topic
    @NamedQuery(name="topic.selectCertainTopic", query="from Topic t where t.id= :id")//就是用前面的名字,代表后面的那条语句,都是自己指定的
})
        Query q = session.getNamedQuery("topic.selectCertainTopic");//这里就代表from Topic t where t.id= :id
        q.setParameter("id", 5);//这就是给 :id设置值

//------------------------ is empty 为空     is not empty 不为空-

empty :  is empty 为空     is not empty 不为空

     is not empty 不为空 ----> exists 存在
     is empty 为空 ----> not exists 不存在

    Query q = session.createQuery("from Topic t where t.msgs is not empty");
        //查询topic中,msgs属性不为空的
        select * from Topic  where exists ( select msgs  from Msg msgs1_  where topic0_.ID=msgs1_.topic_ID )//就生成这样的一个语句,where限定哪里,是用的exists,存在,当HQL语句哪里用的是is empty的时候,生成代码就是 not exists  如果HQL语句是is empty的时候,代码就是 exists

//-------------------------like的使用

    % : 表示 任意多位,每位上可以为任意字符
    _ : 表示 一位上,可以是任意字符
    Query q = session.createQuery("from Topic t where t.title like '%5'");//查询topic中 title 属性 最后一位是5的

//---------------------------常用函数

    lower(列/属性);// 全部小写
    upper(列/属性);//全部大写
    trim(列/属性);//取出首位的空格
    concat(列/属性);//列后面追加,拼接字符串  SQL中,字符串拼接用 ||  如 : a||b = ab
    length(列/属性);//返回列的长度
    abs(列/属性);//该列的绝对值
    sqrt(列/属性);//该列的开平方
    mod(列/属性,值);//如 mod(列,2);//就是除2求余数  列除值 得到的余数

        Query q = session.createQuery("select lower(t.title)," +
                                             "upper(t.title)," +
                                             "trim(t.title)," +
                                             "concat(t.title, '***')," +
                                             "length(t.title)" +
                                             " from Topic t ");
        Query q = session.createQuery("select abs(t.id)," +
                                             "sqrt(t.id)," +
                                             "mod(t.id, 2)" +
                                             " from Topic t ");

//----------------------集群环境中,一台数据库服务

        Query q = session.createQuery("select current_date, sysdate, current_timestamp, t.id from Topic t");//同步时间  如果有人在外地的添加时间,在我这就不对了,对应不上,同步一下
                    //现在时间  系统时间,现在时间戳
        
//-------------------日期的比较

        Query q = session.createQuery("from Topic t where t.createDate < :date");//查询topic  where 限定 createDate(创建时间) 小于 ?   当前时间
        q.setParameter("date", new Date());//设置上面的 :date 当前时间

//-----------------group by , having
    //group by ,having, 注意这些语句的限制,group by后面出现的东西,必须出现在select里面,having,组函数进行限制
    group by  以列分组,但是这个分组列 必须在select里面,里面不能有别的列,只能有什么max(列),min(列),avg(列) 这些函数
    //group by
    Query q = session.createQuery("select t.title, count(*) from Topic t group by t.title") ;//查询topic(对象) 并以title进行分组  查询所有条数

    //having
    Query q = session.createQuery("select t.title, count(*) from Topic t group by t.title having count(*) >= 1") ;//查询topic(对象)  并以title属性进行分组,且 过滤 总条数大于等于1 查询title属性和总条数

//---------------------------------查询平均值 小于平均值

        Query q = session.createQuery("from Topic t where t.id < (select avg(t.id) from Topic t)") ;// 查询topic对象 里面的id属性 小于 (查询topic对象 里面的id属性的平均值) avg(列) : 求指定列的平均值
        //先查询出来里面的子查询  就是查出id的平均值  
        //再查出id小于平均值的所有内容

//---------------限定子查询

ANY : 任意一个.如 小于任意一个 就是小于最大的就行   值 < any (1,4,8) 小于任意一个 ,就等于是小于最大值
all : 所有 . 如 值 < all(1,4,8)  小于所有  就等于小于最小值
            Query q = session.createQuery("from Topic t where t.id < ANY (select t.id from Topic t where mod(t.id, 2)= 0) ") ;//查询topic对象 别名t where限定 id属性 小于

//-------------in , not , in , exists , not exists
//用in(not in) 可以实现exists的功能
    //但是exists执行效率高,exists(存在)反向对应empty(空)
    就是 exists == not empty    //存在 就是 不为空
        not exists == empty   //不存在 就是 为空  所以或他们反向对应

        Query q = session.createQuery("from Topic t where not exists (select m.id from Msg m where m.topic.id=t.id)") ; //查询 topic对象 别名 t  where限定 不存在(查询msg对象中的id属性,且 m里面的topic属性里面的id属性 等于 t里面的id属性) 通过m找到topic对象 再去访问topic对象里面的id属性
        //先查询msg对象中的id属性 where限定 通过m找到topic 再找到里面的id属性 等于 t里面的id属性
        //再查询topic对象 别名 t where限定 不存在的 m里面的id属性(就是除了这个查询到的id,别的都显示)

        Query q = session.createQuery("from Topic t where exists (select m.id from Msg m where m.topic.id=t.id)") ;//查询 topic对象 别名 t  where限定 存在(查询msg对象中的id属性,且 m里面的topic属性里面的id属性 等于 t里面的id属性) 通过m找到topic对象 再去访问topic对象里面的id属性

        //先查询msg对象中的id属性 where限定 通过m找到topic 再找到里面的id属性 等于 t里面的id属性
        //再查询topic对象 别名 t where限定 存在 m里面的id属性(就是除了这个查询到的id,别的都不显示)

//----------------------update  and  delete
//update and delete
    //规范并没有说明是不是要更新persistent object,所以如果要使用,建议在单独的trasaction中执行
    Query q = session.createQuery("update 对象 别名(t) set t.对象中的属性 = upper(t.属性)") ;

    两种写法 :

    1 Query q = session.createQuery("update Topic t set t.title = upper(t.title)") ;//修改topic对象 别名t 设置里面的title属性  值为 upper(title)对应列名转为大写;
    2 session.createQuery("update Topic t set t.title = lower(t.title)").executeUpdate();//修改topic对象 别名t 设置里面的title属性  值为 upper(title)对应列名转为小写;

//-----------------Native 原生  原生语言

Native :

    limit : 分页 (MySQL数据库用的)
    limit 值1,值2; //从第值1个开始,每页显示值2个
        select * from category limit 2,4; //查询category表 limit 从第二个开始,每页显示4个

        SQLQuery q = session.createSQLQuery("select * from category limit 2,4").addEntity(Category.class);

QBC :

criterion :

    Restrictions :
    设置约束  给对象添加约束,然后根据约束去生成对应的语句  真正的约束是由Restrictions来生成
        //有两种,一种是和session绑定到一起,一种是游离的,以后可以和任何session绑定到一起


    createCriteria :
        createCriteria(Topic.class);//为Topic这个类,添加约束  这句话,就是from topic


    gt :   
        greater than  大于的意思
        add(Restrictions.gt("id", 2));//id哪个列(属性),大于2的

    lt :
        little than  小于的意思
        add(Restrictions.lt("id", 8));//id哪个列(属性),小于8的

    like :
        模糊查询 :  _ 一位上任意字符
                    % 任意位上任意字符
        add(Restrictions.like("title", "t%"));//title这个列(属性) 以 t 开头的

    createCriteria :
        createCriteria("category");//表关联,另外一张表做的约束,相当于topic的属性category,然后从category那个类里面的属性找出来

    between :
        在...之间
        add(Restrictions.between("id", 3, 5))// id 列(属性) 在3到5之间

        Criteria c = session
                .createCriteria(Topic.class)    //为topic这个类创建了一系列的约束,from topic
                .add(Restrictions.gt("id", 2))    //greater than = id>2//or
                // greater than = id > 2
                .add(Restrictions.lt("id", 8))
//                // little than = id < 8
                .add(Restrictions.like("title", "t%"))
                .createCriteria("category")    //表关联,另外一张表做的约束,相当于topic的属性category,然后从category那个类里面的属性找出来
//                //注意导航
                .add(Restrictions.between("id", 3, 5)); // category.id >= 3 and
                                                        // category.id <=5
                
@Inheritance :

        前提条件是有继承关系的类中
        继承 : 这个强注解写在父类的类名之上

        父类  : @Inheritance(strategy = InheritanceType.格式) //一个实体类对应一个表,有继承关系的类,生成表的格式,在这能设置,有三种 : (生成表的格式)
            格式 :
                    SINGLE_TABLE : 父类和子类(就是多个类),生成在一张表中
                    JOINED : 把子类共有的属性,保存到一个表,其余都保存在各自的表中
                    TABLE_PER_CLASS : 有多少个类,就创建多少个表

@DiscriminatorColumn :

        辨别器 :
            前提,是在继承关系的类中,并且,父类中设置生成表的格式,是SINGLE_TABLE,(都生成再同一个表中),才有效
            这个强注解写在父类的类名之上

        @DiscriminatorColumn(name = "列名", discriminatorType = DiscriminatorType.列的值的数据类型)//这是一个辨别器  , 就是在同一张表中,多生成一个列,这个列的列名,可以自己任意指定,后面是这个列中的属性(是integer(数字)还是string(字符串)还是char(字符))
        
       列的值的 数据类型 :
                Integer : 数值型
                String : 字符串型
                Char : 字符型

@DiscriminatorValue :

        前提 : 是在继承关系的类中,并且,父类中设置生成表的格式,是SINGLE_TABLE,(都生成再同一个表中),才有效
        这个强注解写在每个有继承关系的类名之上
        @DiscriminatorValue("标签,告诉客户端,这行数据是谁的")//(列的值)相当于标签

        这个意思是 : 当多个类生成同一个表的时候,会创建一个新的列,用于区分表中的每行数据是谁的,通过 @DiscriminatorColumn()辨别器,能设置此列的列名,和此列值的数据类型 , 然后再把每次存入的每行数据(就是对象),用辨别器来区分这个对象(这行数据)是谁的,然后再去类中找到这个标签 @DiscriminatorValue,把里面自己指定的名字,显示再创建的那个新的列上面(一般名字都用作本类的类名,容易区分)
    需要在有继承关系的多个类中,都加上这个标签

//---------------------------模糊查询
        
QBE :
        Topic tExample = new Topic();//自己写的类
        //创建类对象,就是一个表中的一个行的属性
        tExample.setTitle("T_");//往对象里面设置属性(set***()方法) , 像T_的,一个典型,只能是一个确定值的对象,用于搜索,

        Example e = Example.create(tExample).ignoreCase().enableLike();// 静态方法 添加模糊查询的方法
        Criteria c = session.createCriteria(Topic.class)//给指定类(表)添加约束
                .add(Restrictions.gt("id", 2))//id属性大于2的
                .add(Restrictions.lt("id", 8))//id属性小于8的
                .add(e);//上面写好的模糊查询  "T_"

//-----------------1+N

    //1+N:只要查询当前对象,他就会查询别的
    //可以多表查询,可以解决1+N问题
    //设置为Lazy
@BatchSize :

        @BatchSize(size = 5);////@BathSize: 默认是一个一个抓取,这里可以指定每次抓取的个数
        写在类上面

left_outer_join_fetch  :

    (用iterator(迭代器)就不能使用join)

     Query q = session.createQuery("from Topic t left outer join fetch t.category c ");//Topic是对象,对象里面有个属性是另外一个表的引用,t.category就能获得另外一个类对应的表和其中的属性

        List<Category> topics = q.list();//把查询出来的值,封装到对应的对象中,再封装到list集合中
        简写 :
            List<Category> topics = session.createQuery("from Topic t left outer join fetch t.category c");

前提 : 必须有一个对象(表)中的属性(列),保存的是另一个表的引用
    如 : Topic对象中 有个属性 保存了Category的引用

    如 :  List<Category> topics = session.createQuery("from 表1 别名(t) left outer join fetch t.表名2 别名(c)");

    inner_join_fetch :

         List<Category> topics = session.createQuery("from Topic t inner join fetch t.category c");

    left_outer_join_fetch :  

    结果集 :
        表2在表1的左边
         //先查询Topic对象对应的表,再通过topic找到category对应的表,都查询出来,并且,category对应的表,查询出来并显示在Topic的左面 (相当于把两个表的结果集,合并成一个表,一个在左面,一个在右面)
        List<Category> topics = session.createQuery("from Topic t left outer join fetch t.category c");

    right_outer_join_fetch :

    结果集 :
        表2在表1的右边
         //先查询Topic对象对应的表,再通过topic找到category对应的表,都查询出来,并且,category对应的表,查询出来并显示在Topic的右面 (相当于把两个表的结果集,合并成一个表,一个在左面,一个在右面)
         List<Category> topics = session.createQuery("from Topic t right outer join fetch t.category c");

iterator :

        // iterator: 如果使用不允许使用join
        //迭代器,把查询的数据直接用迭代器遍历
        Iterator<泛型,一般用于对象名> categories = session.createQuery("from 对象 别名").iterate();//
        Iterator<Category> categories = session.createQuery("from Category c").iterate();//

        while (categories.hasNext()) {//hasNext(),是问下一位还有没有元素,返回值为boolean型,true/false
            Category c = categories.next();//next()是取得下一位元素的值,
            System.out.println(c.getName());//因为里面都是对象,所以可以通过上面获取的对象的引用,去访问对象里面的属性
        }

Cacheable :

        开启缓存,要和ehcache.xml一起使用
        List<Category> categories = session.createQuery("from Category").setCacheable(true).list();//查询Category对象对应的表,然后放入缓存中,封装到list集合中
        setCacheable(true);//开启缓存