Hibernate学习

Hibernate与JDBC的对比

jdbc缺点
1. 编程的时候很繁琐
2. jdbc没有做数据的缓存,与数据库连接频繁,消耗大
3. 没有做到面向对象编程
4. sql语句的跨平台性很差
jdbc的优点
效率比较高
hibernate的优点
1. 完全的面向对象编程
2. 有一级二级和查询缓存,能提高性能
3. 编写代码的时候简单
4. 跨平台性很强
hibernate的缺点
1. 效率比较低
2. 由于对JDBC封装得过于厉害,所以不够灵活

Hibernate增删改查操作数据库

hibernate.cfg.xml配置文件

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>

    <session-factory>
        <!-- 链接数据库的用户名 -->
        <property name="connection.username">root</property>
        <!-- 链接数据库的密码 -->
        <property name="connection.password">ying1995520***</property>
        <!-- 链接数据库的驱动 -->
        <property name="connection.driver_class">
            com.mysql.jdbc.Driver
        </property>
        <!-- 链接数据库的url -->
        <property name="connection.url">
            jdbc:mysql://localhost:3306/db3
        </property>

        <!-- 
            方言
            告诉hibernate使用什么样的数据库,hibernate就会在底层拼接什么样的sql语句
        -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

        <!-- 
            使用getCurrentSession()需要配置,指定当前session的获取范围,thread表示在当前线程获取
            当前线程有session则获取,没有则新建
        -->
        <property name="current_session_context_class">thread</property>
        <!-- 
            根据持久化类生成表的策略
            validate   通过映射文件检查持久化类与表的匹配
            update   每次hibernate启动的时候,检查表是否存在,如果不存在,则创建,如果存在,则什么都不做了
            create   每一次hibernate启动的时候,根据持久化类和映射文件生成表
            create-drop
        -->
        <property name="hbm2ddl.auto">update</property>
        <!-- 显示sql语句 -->
        <property name="show_sql">true</property>
        <!-- 格式化的显示sql语句 -->
        <property name="format_sql">true</property>

        <!-- 二级缓存驱动 -->
        <!-- 新版 -->
        <property name="hibernate.cache.provider_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
        <!-- 旧版 -->
        <!-- <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property> -->

        <!-- 开启二级缓存 -->
        <property name="hibernate.cache.use_second_level_cache">true</property>

        <!-- 开启查询缓存 -->
        <property name="hibernate.cache.use_query_cache">true</property>

        <!-- 开启统计机制 -->
        <property name="hibernate.generate_statistics">true</property>

        <!-- 指向注解的对象 -->
        <!-- 
        <mapping class="com.jyh.domain.Person"/>
         -->
        <!-- 指向xml配置的映射文件 -->
        <mapping resource="com/jyh/domain/Person.hbm.xml" />

        <!-- 
              指定哪个类开启二级缓存,放在mapping之后,usage各参数的含义:
             read-only:对于从来不会修改的数据,如参考数据,可以使用这种并发访问策略。
             nonstrict-read-write:非严格读写型:不保证缓存与数据库中数据的一致性。如果存在两个事务同时访问缓存中相同数据的可能,
                    必须为该数据配置一个很短的数据过期时间,从而尽量避免脏读。对于极少被修改,并且允许偶尔脏读的数据,
                    可以采用这种并发访问策略。
             read-write:提供了Read Committed事务隔离级别。仅仅在非集群的环境中适用。对于经常被读但很少修改的数据,
                    可以采用这种隔离类型,因为它可以防止脏读这类的并发问题。
             transactional:仅仅在受管理环境中适用。它提供了Repeatable Read事务隔离级别。对于经常被读但很少修改的数据,
                    可以采用这种隔离类型,因为它可以防止脏读和不可重复读这类的并发问题。
             事务型并发访问策略是事务隔离级别最高,只读型的隔离级别最低。事务隔离级别越高,并发性能就越低。
        -->
        <class-cache usage="read-only" class="com.jyh.domain.Person" />
    </session-factory>
</hibernate-configuration>

JavaBean类与映射文件的编写

JavaBean类:
文件名为:hibernate.cfg.xml
路径:默认放在构建路径目录下(src下)

package com.jyh.domain;

import java.io.Serializable;

public class Person implements Serializable{

    private static final long serialVersionUID = 1L;

    private Long id;
    private String name;
    private String password;
    private Human human;

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public Human getHuman() {
        return human;
    }
    public void setHuman(Human human) {
        this.human = human;
    }


}

映射文件:
文件名为:类名.hbm.xml
路径:对应的JavaBean类所在的包

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <!-- 
        class用来描述一个类
           name 类的全名
           table 该持久化类对应的表名   可以不写,默认值为类名
           catalog  数据库的名称
           dynamic-update  动态更新,有改变就更新,没改变就不更新(针对单个属性字段,比如说只有name有改变就只更新name)
     -->
    <class name="com.jyh.domain.Person" table="person" dynamic-update="false">
        <!-- 
            用来描述主键
              name 属性的名称
              column 属性的名称对应的表的字段   可以不写  默认值就是属性的名称
              length  属性的名称对应的表的字段的长度  如果不写,默认是最大的长度
         -->
        <id name="id" column="id" length="5">
            <!-- 
                主键的产生器
                increment:最大id的基础上加1
                assigned:手动赋值
                identity:自动增长
                uuid:一串唯一的字符串
                sequence:序列(oracle)
             -->
            <generator class="increment"></generator>
        </id>
        <!-- 用来描述类中的属性type可以是hibernate中的类型,也可以是java语言中的类型,对照表可以搜索,建议用java类型 -->
        <property name="name" length="20" type="string"></property>
        <property name="password" length="50" type="java.lang.String"></property>


    </class>
</hibernate-mapping>

增删改查操作的方法测试

hibernate.cfg.xml中SessionFactory配置的获取

package com.jyh.utils;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

/**
 * 新版SessionFactory创建方式,不同版本的创建方式百度Google一下就有
 * @author OverrideRe
 *
 */
public class HibernateUtils {
    static Configuration cfg;
    static ServiceRegistry serviceRegistry;
    static SessionFactory sessionFactory;

    static {
        /**
         * 创建Configuration对象 调用.configure()方法 ,获取hibernate.cfg.xml配置文件
         * 默认路径在构建路径目录下(src/hibernate.cfg.xml),也可以调用configure(path)传入指定的配置文件路径;
         */
        cfg = new Configuration().configure();
        // 创建服务对象
        serviceRegistry = new StandardServiceRegistryBuilder()
                            .applySettings(cfg.getProperties()).build();
        // 创建sessionFactory工厂
        sessionFactory = cfg.buildSessionFactory(serviceRegistry);
    }

    /**
     * 使用openSession()方法获取session后。用完session后要session.close()
     */
    public static Session openSession() {
        return sessionFactory.openSession();
    }

    /**
     * 获取当前存在的session,不存在就创建一个,当前的范围在配置文件中设置,使用getCurrentSession()方法获取session后。用完session后session自动关闭
     */
    public static Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }
}

编写怎删改查测试方法

@Test
public void testPerson(){
    Session session = HibernateUtils.openSession();         //打开新session
    Transaction transaction = session.beginTransaction();           //开启事务
    Person person = new Person();
    person.setName("大狗");
    person.setPassword("123");

    //保存
    session.save(person);

    //获取
    Person p = (Person)session.get(Person.class, 1L);
    System.out.println(p.getName() + ":" + p.getClass().getName());

    //修改,修改持久化对象,提交之后同步到数据库
    person.setName("小狗");
    person.setPassword("321");

    //更新
    /**
     * update方法就是把一个对象的状态变成持久化状态,所以如果对象已经是持久化状态了,这个就不用写
     * 比如说上面的get获取的就是持久化状态,直接set修改提交事务之后就自动同步到数据库中去了
     * 如果不是持久化状态,比如说新new的一个对象,里面设置好id,就需要用update
     */
    session.update(person);

    //删除
    session.delete(person);

    transaction.commit();                                           //提交事务
    session.close();
}

Hibernate缓存

缓存顾名思义就是用来缓冲的内存存储,存在于内存中的对象与数据库交互之间,对象<—>缓存<—>数据库,JDBC由于每次获取数据都要建立连接发送sql语句,效率比较低,所以就弄了一个缓存,用来临时存储从数据库中获取的数据,以便在相近的时间内再次获取数据的时候可以直接从缓存中取数据而不需要从数据库中取数据.

对象的三种状态

  1. 临时状态(Transient)
    在内存中的数据,没有保存在缓存中,在hibernate缓存中没有,在数据库中也没有
  2. 持久化状态(Persistent)
    存在hibernate缓存中并且在数据库中也有对应的数据,修改该数据之后提交会影响数据库数据.
  3. 脱管状态(Detached)
    存在于数据库中,读取到缓存中之后被踢出了,所以不在缓存中,对该数据进行修改提交之后不会影响数据库.

这里写图片描述

一级缓存

为session级别的缓存,一级缓存的生命周期和session的生命周期保持一致
session方法有:
session.get:从数据库中获取数据添加进本缓存中,从本缓存中获取数据给对象
session.save:可以将临时对象存入本缓存中去,提交进数据库之后就是持久化对象了
session.update:与save一样,不过更新先与缓存中的数据进行比较,如果一致则什么都不做,不一致则更新
session.delete:将数据从缓存和数据库中删除,不是三种状态的任何一种,将会被垃圾回收期回收
session.saveOrUpdate:看名字就知道了,不过调用的时候会先与缓存中的数据进行比对,缓存中没有则插入进去,缓存中有但是数据不一致则更新,数据一致则什么都不做
session.evict:将传入的对象从缓存中踢出,但是不操作数据库
session.clear:将缓存中的所有数据清空,但是不操作数据库
session.load:与get作用差不多,不同之处在于,load是懒加载,方法产生的是代理对象,该代理类是持久化类的子类,比如说获取一个对象的时候是个假对象,里面属性没有值,只有当调用该属性值的时候才会去获取
session.close:关闭本缓存

二级缓存

二级缓存是SessionFactory级别的缓存
适用情况:
1. 经常被访间
2. 改动不大不会经常改动
3. 数重有限
生命周期:
生命周期和sessionFactory是一致的
设置二级缓存:
1.在hibernate.cfg.xml配置文件中

<!-- 二级缓存驱动 -->
<!-- 新版 -->
<property name="hibernate.cache.provider_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<!-- 旧版 -->
<!-- <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property> -->

<!-- 开启二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>

2.指定哪个类开启二级缓存

<!-- 
指定哪个类开启二级缓存,放在mapping之后,usage各参数的含义:
read-only:对于从来不会修改的数据,如参考数据,可以使用这种并发访问策略。
nonstrict-read-write:非严格读写型:不保证缓存与数据库中数据的一致性。如果存在           两个事务同时访问缓存中相同数据的可能,
必须为该数据配置一个很短的数据过期时间,从而尽量避免脏读。对于极少被修改,并且允许偶尔脏读的数据,
可以采用这种并发访问策略。
read-write:提供了Read Committed事务隔离级别。仅仅在非集群的环境中适用。对于经常被读但很少修改的数据,
可以采用这种隔离类型,因为它可以防止脏读这类的并发问题。
transactional:仅仅在受管理环境中适用。它提供了Repeatable Read事务隔离级别。对于经常被读但很少修改的数据,
可以采用这种隔离类型,因为它可以防止脏读和不可重复读这类的并发问题。
事务型并发访问策略是事务隔离级别最高,只读型的隔离级别最低。事务隔离级别越高,并发性能就越低。
-->
<class-cache usage="read-only" class="com.jyh.domain.Person" />

操作二级缓存的方法:
session.get方法和session.load方法
另外的方法:
list:不从2级缓存中查找数据,直接从数据库查找全部数据添加进2级缓存
iterate:先从2级缓存中查找数据,没有就从数据库中查找数据,并将数据添加进2级缓存
iterate是先查找id,然后根据id查找关联对象,list是直接查找出所有对象
如果查找所有班级的所有学生,就需要先查找所有班级的id(第一次查询),然后根据id查找每个班级的学生(产生n个班级次数的查询),所以这里就产生了一个sql滥用的问题,俗称N+1问题,如果使用普通的sql语句一次就可以全部查询出来

@Test
public void testSecond2(){
    Session session = HibernateUtils.openSession();
    session.beginTransaction();
    //list从数据库中加载到二级缓存
    @SuppressWarnings("unchecked")
    List<Second> list = session.createQuery("from Second").list();
    for(Second s : list){
        System.out.println(s.getName());
    }
    session.close();
    System.out.println("------------------------------");

    session = HibernateUtils.openSession();
    @SuppressWarnings("unchecked")
    //list直接从数据库中查找,不从二级缓存中查找
    List<Second> list2 = session.createQuery("from Second").list();
    for(Second s : list2){
        System.out.println(s.getName());
    }
    session.close();
    System.out.println("------------------------------");

    //Iterate先从数据库中查找出id,等到需要用其中某一个对象的时候,
    //再根据该对象所对应的id从二级缓存中查找,二级缓存中没有就从数据库中查找
    session = HibernateUtils.openSession();
    @SuppressWarnings("unchecked")
    Iterator<Second> iterator = session.createQuery("from Second").iterate();
    while(iterator.hasNext()){
        System.out.println(iterator.next().getName());
    }
    session.close();
}

查询缓存

一级缓存和二级缓存都是对象的缓存,即将数据以对象的形式保存,查询缓存则是保存数据集,不以对象的形式保存
生命周期:
只要一些数据放入到查询缓存中,该缓存会一直存在,直到缓存中的数据被修改了,该 缓存的生命周期就结束了。
操作查询缓存:
1.在hibernate的配置文件中,开启查询缓存

<!-- 开启查询缓存 -->
<property name="hibernate.cache.use_query_cache">true</property>

2.使用查询缓存

//查询缓存
@Test
public void testQuery1(){
    Configuration configuration = new Configuration();
    configuration.configure();
    SessionFactory sessionFactory = configuration.buildSessionFactory();
    Session session = sessionFactory.openSession();
    Query query = session.createQuery("select id,name from Second");
    query.setCacheable(true);//开启查询缓存
    System.out.println(query.list().size());
    session.close();

    session = sessionFactory.openSession();
    query = session.createQuery("from Second");
    query.setCacheable(true);//开启查询缓存
    System.out.println(query.list().size());
    session.close();
}

对象关系

xml配置

OneToOne(一对一)

OneToMany(一对多)

一:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>

    <class name="com.jyh.domain.Classes" table="classes" dynamic-update="false">

        <id name="id" column="id" length="5">
            <generator class="increment"></generator>
        </id>

        <property name="name" length="20" type="string"></property>
        <!-- 
            list集合属性 
            cascade:表示对象与对象之间的关系,比如说一个班级有10个老师,每次保存一个班级的时候
            看cascade的值是什么,如果是save-update,则班级里面的老师也会被保存,更新也会随着班级的更新而更新
            但是老师的类里面没有外键这个属性,所以保存的时候是不会有外键的,也就无法与班级表产生联系

            inverse:表示表中记录的关系,也就是外键之类的,像上面的例子中,班级对象添加进表
            顺带老师对象添加进表,设置inverse为false,则表示本对象不主导关系,由另一个类主导关系,(在另一个类中加外键)现在班级设置成false,则班级添加的时候
            会将id作为外键保存在该班级下对应老师的数据中
            inverse只存在于一对多中的一种和多对多中
            fetch:
                join:左外链接
                select:普通模式
                subselect:子查询
            设置这个属性表示本类与关联类以什么样的方式查询
        -->
        <list name="teachers" cascade="save-update" inverse="false" fetch="join">
            <!-- column表示在另一张表生成的外键-->
            <key column="c_id" />
            <!-- list集合序号必须设置,不然报错,set集合不需要 -->
            <list-index column="idx"/>
            <!-- 集合中的类 -->
            <one-to-many class="com.jyh.domain.Teacher"/>
        </list>
    </class>
</hibernate-mapping>

多:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>

    <class name="com.jyh.domain.Teacher" table="teacher" dynamic-update="false" >

        <id name="id" column="id" length="5">
            <generator class="increment"></generator>
        </id>

        <property name="name" length="20" type="string"></property>
        <!-- 会在表中生成name属性字段的外键 -->
        <many-to-one name="classes" column="c_id" cascade="all"></many-to-one>
    </class>
</hibernate-mapping>

ManyToMany(多对多)

第一个类

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>

    <class name="com.jyh.domain.A2" table="a2" dynamic-update="false" >

        <id name="id" column="id" length="5">
            <generator class="identity"></generator>
        </id>

        <property name="name" length="20" type="string"></property>

        <!-- table表示生成的第三张关联表的名字 -->
        <set name="b2s" cascade="all" table="aabb">

            <!-- column表示本类在第三张表中的外键字段 -->
            <key column="a2_id"></key>

            <!-- column表示另一个类在第三张表中的外键字段 -->
            <many-to-many column="b2_id" class="com.jyh.domain.B2"></many-to-many>
        </set>
    </class>
</hibernate-mapping>

第二个类

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>

    <class name="com.jyh.domain.B2" table="b2" dynamic-update="false" >

        <id name="id" column="id" length="5">
            <generator class="identity"></generator>
        </id>

        <property name="name" length="20" type="string"></property>
        <set name="a2s" cascade="all" table="aabb">
            <key column="b2_id"></key><!-- column表示本类在第三张表中的外键字段 -->
            <!-- column表示另一个类在第三张表中的外键字段 -->
            <many-to-many column="a2_id" class="com.jyh.domain.A2"></many-to-many>
        </set>
    </class>
</hibernate-mapping>

注解(annotation)

OneToOne(一对一)

OneToMany(一对多)

一:

package com.jyh.domain;

import java.io.Serializable;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import org.hibernate.annotations.Cascade;


@SuppressWarnings("serial")
@Entity
@Table(name="people")
public class People implements Serializable{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
//  @GenericGenerator(name = "generator", strategy = "uuid")    //主键策略生成器生成主键策略
//  @GeneratedValue(generator = "generator")                    // 引用生成的主键策略,generator等于生成的id策略的name属性
    private Integer id;
    //mappedBy相当于xml映射文件中的inverse值等于本类在对面类中的属性
    //cascade等同于xml配置中的cascade,不过这里的cascade是jpa中的,除了all有效,其它都无效,所以用hibernate中的
    @OneToMany(mappedBy = "people",         
            cascade = {CascadeType.ALL})    
    //hibernate中的
    @Cascade(value = org.hibernate.annotations.CascadeType.SAVE_UPDATE)
    private List<Phone> phones;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public List<Phone> getPhones() {
        return phones;
    }

    public void setPhones(List<Phone> phones) {
        this.phones = phones;
    }
}

多:

package com.jyh.domain;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;


@SuppressWarnings("serial")
@Entity
public class Phone implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String number;
    @ManyToOne
    @JoinColumn(name = "p_id")//表示本类在另一个类中的外籍
    private People people;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getNumber() {
        return number;
    }
    public void setNumber(String number) {
        this.number = number;
    }
    public People getPeople() {
        return people;
    }
    public void setPeople(People people) {
        this.people = people;
    }

}

ManyToMany(多对多)

第一个类:

package com.jyh.domain;

import java.io.Serializable;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;

@SuppressWarnings("serial")
@Entity
@Table(name = "aa")
public class A1 implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    @ManyToMany()
    @Cascade(value = CascadeType.SAVE_UPDATE)
    @JoinTable(name = "a_b",                                        //中间表的名字
    joinColumns = {@JoinColumn(name = "a_id")},                     //JoinColumn定义本类在中间表的主键映射
    inverseJoinColumns = {@JoinColumn(name = "b_id")})              //inverseJoinColumns定义另一个类在中间表的主键映射
    private Set<B1> b1s;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Set<B1> getB1s() {
        return b1s;
    }
    public void setB1s(Set<B1> b1s) {
        this.b1s = b1s;
    }

}

另一个类:

package com.jyh.domain;

import java.io.Serializable;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;

import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;

@SuppressWarnings("serial")
@Entity
@Table(name = "bb")
public class B1 implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @JoinColumn(name = "b_id")
    private Integer id;
    private String name;
    @ManyToMany()
    @Cascade(value = CascadeType.SAVE_UPDATE)                       //用hibernate自带的
    @JoinTable(name = "a_b",
    joinColumns = {@JoinColumn(name = "b_id")},                     //JoinColumn定义本类在中间表的主键映射
    inverseJoinColumns = {@JoinColumn(name = "a_id")})              //inverseJoinColumns定义另一个类在中间表的主键映射
    private Set<A1> a1s;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Set<A1> getA1s() {
        return a1s;
    }
    public void setA1s(Set<A1> a1s) {
        this.a1s = a1s;
    }

}

由于关系复杂繁多,所以想了解清楚最好是各种情况都写代码运行查看效果

查询

本地sql语句

session.createSQLQuery(“sql语句”);

hql语句

//HQL
@Test
public void testQueryAllClasses(){
    Session session = HibernateUtils.openSession();
    @SuppressWarnings("unchecked")
    List<Classes> classes = session.createQuery("from Classes").list();
    for (Classes classes2 : classes) {
        System.out.println(classes2.getName());
    }
    session.close();
}

@Test
public void testQueryProperties(){
    Session session = HibernateUtils.openSession();
    @SuppressWarnings("unchecked")
    List<Classes> list 
    //这种需要一个与获取字段相匹配的构造函数
    = session.createQuery("select new com.jyh.domain.Classes(id,name) from Classes").list();
    for (Classes c : list) {
        System.out.println(c.getName());
    }
    session.close();
}

@Test
public void testQueryCount(){
    Session session = HibernateUtils.openSession();
    //获取一条数据用uniqueResult();
    Long count = (Long)session.createQuery("select count(id) from Classes").uniqueResult();

    System.out.println(count);
    session.close();
}

//序号填充参数
@Test
public void testQueryPrepare_1(){
    Session session = HibernateUtils.openSession();
    Query query = session.createQuery("from Classes where id=? and name=?");
    query.setParameter(0, 3);
    query.setParameter(1, "nn");
    Classes classes = (Classes)query.uniqueResult();
    System.out.println(classes.getName());
    session.close();
}

//名称填充参数
@Test
public void testQueryPrepare_2(){
    Session session = HibernateUtils.openSession();
    Query query = session.createQuery("from Classes where id=:id and name=:name");
    query.setParameter("id", 3);
    query.setParameter("name", "nn");
    Classes classes = (Classes)query.uniqueResult();
    System.out.println(classes.getName());
    session.close();
}

/**
 * 内连接:
 * 将每张表对应的对象放在一个数组里,然后将数组放进List集合中去,对象中没有关联对象
 */
@Test
public void testInnerJoin(){
    Session session = HibernateUtils.openSession();
    @SuppressWarnings("unchecked")
    List<Object[]> list = session.createQuery("from Classes c inner join c.teachers").list();
    for (Object[] objects : list) {
        Classes c = (Classes)objects[0];
        Teacher t = (Teacher)objects[1];
        System.out.println(c.getName() + ":" + t.getName());
    }
    session.close();
}

/**
 * 迫切内连接:
 * 返回的是封装好的语句前面的对象,比如说
 * from Classes c inner join fetch c.teachers返回的是Classes对象,里面含有Teacher对象
 */
@SuppressWarnings("unchecked")
@Test
public void testInnerJoin_fetch(){
    Session session = HibernateUtils.openSession();
    List<Classes> clist = session.createQuery("from Classes c inner join fetch c.teachers").list();
    for (Classes c : clist) {
        List<Teacher> ts = c.getTeachers();
        System.out.println(c.getName());
        for (Teacher teacher : ts) {
            System.out.println(teacher.getName());
        }
    }

    List<Teacher> tlist = session.createQuery("from Teacher t inner join fetch t.classes").list();
    for (Teacher teacher : tlist) {
        System.out.println(teacher.getName() + ":" + teacher.getClasses().getName());
    }
    session.close();
}

/**
 * 左外连接:
 * 返回的是数组,左连接与内连接的区别就是sql语句的区别
 */
@SuppressWarnings("unchecked")
@Test
public void testLeftJoin(){
    Session session = HibernateUtils.openSession();
    List<Object[]> list = session.createQuery("from Classes c left join c.teachers").list();
    for (Object[] objects : list) {
        Classes c = (Classes)objects[0];
        Teacher t = (Teacher)objects[1];
        System.out.print(c.getName() + ":");
        System.out.println(t.getName());
        System.out.println("----------");
    }
    session.close();
}

/**
 * 迫切左外连接:
 * 与普通左外连接的区别跟内连接一样
 */
@SuppressWarnings("unchecked")
@Test
public void testLeftJoin_fetch(){
    Session session = HibernateUtils.openSession();
    List<Classes> clist = session.createQuery("from Classes c left outer join fetch c.teachers").list();
    //List<Teacher> tlist = session.createQuery("from Teacher t left outer join fetch t.classes").list();

    for (Classes c : clist) {
        List<Teacher> ts = c.getTeachers();
        System.out.println(c.getName());
        for (Teacher teacher : ts) {
            System.out.println(teacher.getName());
        }
    }

//      for (Teacher teacher : tlist) {
//          System.out.print(teacher.getName() + ":");
//          System.out.println(teacher.getClasses().getName());
//      }
    session.close();
}

/**
 * 要查询的属性来自于两个持久化类
 *    带构造函数的查询和fetch的查询不能同时存在
 */
@Test
public void testQuery(){
    Session session = HibernateUtils.openSession();
    @SuppressWarnings("unchecked")
    List<ClassTeacher> cts = session.createQuery(
            "select new com.jyh.domain.ClassTeacher (c.name,t.name) from Classes c right join c.teachers t").list();
    for (ClassTeacher classTeacher : cts) {
        System.out.println(classTeacher.getCname() + ":" + classTeacher.getTname());
    }
    session.close();
}



//ManyToMany
/**
 * 迫切内连接
 *     
 */
@SuppressWarnings("unchecked")
@Test
public void testInnerJoin_Fetch(){
    Session session = HibernateUtils.openSession();
    List<A1> list = session.createQuery("from A1 a inner join fetch a.b1s b").list();
    for (A1 a1 : list) {
        System.out.println(a1.getName());
        Set<B1> bSet = a1.getB1s();
        for (B1 b1 : bSet) {
            System.out.println(b1.getName());
        }
    }
    session.close();
}

/**
 * 迫切左外连接
 */
@Test
public void testLeftOuterJoin_Fetch(){
    Session session = HibernateUtils.openSession();
    session.createQuery("from Student s left outer join fetch s.courses c").list();
    session.close();
}

criteria

略(搜索)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值