hibernate

一对一映射

设计实体类
idCard.java
public class User{
    private Integer userId;
    private String userName;
    //维护与身份证一对一的关系
    private IdCard idCard;
    // 省略 get set
}
复制代码
idCard.java
public class IdCard{
    private Integer idCardId;
    private String idCardName;
    //维护与用户之间的关系
    private User user;
    // 省略 get set
}
复制代码
  • 第一种方式:基于外键的方式映射
User.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
        
<hibernate-mapping>

    <class name="com.bjlemon.hibernate.entity.User" table="USER">
    
        <!-- 映射主键 -->
        <id name="userId" type="java.lang.Integer">
            <column name="USER_ID" />
            <generator class="identity" />
        </id>
        
        <!--映射普通字段-->
        <property name="userName" type="java.lang.String">
            <column name="USER_NAME" />
        </property>
        
        <!-- 没有外键的一端需要使用one-to-one元素 -->
        <!-- property-ref指定关联类的属性名(定义在java中的属性名),这个属性将会和本类的主键相对应  -->
        <one-to-one name="idCard" class="com.bjlemon.hibernate.entity.IdCard" property-ref="user"></one-to-one>
    
    </class>
    
</hibernate-mapping>
复制代码
IdCard.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
        
<hibernate-mapping>

	<class name="com.bjlemon.hibernate.entity.IdCard" table="IDCARD">
	
		<!-- 映射主键 -->
		<id name="idCardId" type="java.lang.Integer">
			<column name="IDCARD_ID" />
			<generator class="identity" />
		</id>
		
		<!--映射普通字段-->
		<property name="idCardName" type="java.lang.String">
			<column name="IDCARD_NAME" />
		</property>
		
		<!-- 有外键的一端需要使用many-to-one元素 -->
		<many-to-one name="user"
			class="com.bjlemon.hibernate.entity.User" column="user_id" unique="true"></many-to-one>
	
	</class>
	
</hibernate-mapping>
复制代码
  • 第二种方式:基于主键的方式映射
User.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
        
<hibernate-mapping>

    <class name="com.bjlemon.hibernate.entity.User" table="USER">
    
        <!-- 映射主键 -->
        <id name="userId" type="java.lang.Integer">
            <column name="USER_ID" />
            <generator class="identity" />
        </id>
        
        <!--映射普通字段-->
        <property name="userName" type="java.lang.String">
            <column name="USER_NAME" />
        </property>
        
        <!-- 没有外键的一端需要使用one-to-one元素 -->
        <one-to-one name="idCard" class="com.bjlemon.hibernate.entity.IdCard"></one-to-one>
    
    </class>
    
</hibernate-mapping>
复制代码
IdCard.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
        
<hibernate-mapping>

	<class name="com.bjlemon.hibernate.entity.IdCard" table="IDCARD">
	
		<!-- 映射主键 -->
		<id name="idCardId" type="java.lang.Integer">
			<column name="IDCARD_ID" />
			<!--做主键的同时也做外键,外键的类型名称为user-->
			<generator class="foreign">
				<param name="property">user</param>
			</generator>
		</id>
		
		<!--映射普通字段-->
		<property name="idCardName" type="java.lang.String">
			<column name="IDCARD_NAME" />
		</property>
		
		<!-- 有外键的一端基于主键映射,使用oneToOne -->
		<!-- constrained="true"  指定在主键上添加外键约束 -->
		<one-to-one name="user"
			class="com.bjlemon.hibernate.entity.User" constrained="true"></one-to-one>
	
	</class>
	
</hibernate-mapping>
复制代码

一对多和多对一映射

一个部门有多个员工:一对多
多个员工属于一个部门:多对一
Dept.java
public class Department {
    private Integer deptId;
    private String deptName;
    private Set<Employee> employees = new HashSet<>();
    // 省略 get set
}
复制代码
Employee.java
public class Employee {
    private Integer empId;
    private String empName;
    private Double empSalary;
    private Department department;
    // 省略 get set
}
复制代码
Department.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
        
<hibernate-mapping>

    <class name="com.bjlemon.hibernate.entity.Department" table="DEPARTMENT">
        
        <id name="deptId" type="java.lang.Integer">
            <column name="DEPT_ID" />
            <generator class="native" />
        </id>
        
        <property name="deptName" type="java.lang.String">
            <column name="DEPT_NAME" />
        </property>
        
        <!-- set:代表集合 -->
        <!-- name:代表的是当前对象中代表多的属性的集合名称 -->
        <!-- table: set中的元素对应的记录放在哪一个数据表中 -->
        <!-- inverse: 指定由哪一方来维护关联关系,通常设置为true,由对方维护关联关系 -->
        <!-- key:外键的名称,必须和多对一中的外键名称一致-->
        <!-- class: 代表set集合中对象的全路径-->
        <set name="employees" table="EMPLOYEE" inverse="true">
            <key>
                <column name="DEPT_ID" />
            </key>
            <one-to-many class="com.bjlemon.hibernate.entity.Employee" />
        </set>
        
    </class>
    
</hibernate-mapping>
复制代码
Employee.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>

    <class name="com.bjlemon.hibernate.entity.Employee" table="EMPLOYEE">
        
        <id name="empId" type="java.lang.Integer">
            <column name="EMP_ID" />
            <generator class="native" />
        </id>
        
        <property name="empName" type="java.lang.String">
            <column name="EMP_NAME" />
        </property>
        
        <property name="empSalary" type="java.lang.Double">
            <column name="EMP_SALARY" />
        </property>
        
        <!-- name: 代表的是当前的对象中的代表外键的属性 -->
        <!-- class: 代表外键对象的全路径 -->
        <!-- column: 代表外键的名称 -->
        <many-to-one name="department" class="com.bjlemon.hibernate.entity.Department">
            <column name="DEPT_ID" />
        </many-to-one>
        
    </class>
    
</hibernate-mapping>
复制代码

多对多映射

project.java
public class Project {
    private Integer proId;
    private String proName;
    //使用Set集合与developer实体维护关系
    private Set<Developer> developers = new HashSet<>();
    // 省略 get set
}
复制代码
developer.java
public class Developer {
    private Integer devId;
    private String devName;
    //使用Set集合来维护与Project关系
    private Set<Project> projects = new HashSet<>();
    // 省略 get set
}
复制代码
Project.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

    <class name="com.bjlemon.hibernate.entity.Project" table="PROJECT">
        
        <id name="proId" type="java.lang.Integer">
            <column name="PRO_ID" />
            <generator class="identity" />
        </id>
        
        <property name="proName" type="java.lang.String">
            <column name="PRO_NAME" />
        </property>
        
        <!-- set:代表集合 -->
        <!-- name:代表的是当前对象中代表多的属性的集合名称 -->
        <!-- table:中间表的名称 -->
        <!-- key:当前对象在中间表的外键名称 -->
        <!-- column:当前对象在中间表的外键名称 -->
        <!-- class:代表set集合中对象的全路径 -->
        <!-- column:代表的是集合中对象在中间表的外键名称 -->
        <set name="developers" table="DEV_PRO" inverse="false">
            <key>
                <column name="PRO_ID" />
            </key>
            <many-to-many class="com.bjlemon.hibernate.entity.Developer" column="DEV_ID"/>
        </set>
        
    </class>
    
</hibernate-mapping>

复制代码
Developer.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
        
<hibernate-mapping>

    <class name="com.bjlemon.hibernate.entity.Developer" table="DEVELOPER">
        
        <id name="devId" type="java.lang.Integer">
            <column name="DEV_ID" />
            <generator class="native" />
        </id>
        
        <property name="devName" type="java.lang.String">
            <column name="DEV_NAME" />
        </property>
        
        <set name="projects" table="DEV_PRO" inverse="true">
            <key>
                <column name="DEV_ID" />
            </key>
            <many-to-many class="com.bjlemon.hibernate.entity.Project" column="PRO_ID"/>
        </set>
    </class>
</hibernate-mapping>
复制代码

持久化对象的三种状态

  • 持久化对象的三个状态:看唯一标识OID是否有值,对象是否被Session对象管理
  • 瞬时态:也称临时状态,未被持久化,不处于session的缓存中
    获得瞬时态的对象:User user = new User()
    瞬时态对象转换持久态:save()/saveOrUpdate();
    瞬时态对象转换成脱管态:user.setId(1)
  • 持久态:已经被持久化,处于session的缓存中
    获得持久态的对象:get()/load();
    持久态转换成瞬时态对象:delete();
    持久态对象转成脱管态对象:session的close()/evict()/clear();
  • 脱管态:已经被持久化,但不处于session的缓存中
    获得托管态对象:User user = new User();user.setId(1);
    脱管态对象转换成持久态对象:update();/saveOrUpdate()/lock();
    脱管态对象转换成瞬时态对象:user.setId(null);

hibernate的抓取策略

  • 抓取策略:使用Hibernate查询一个对象的时候,查询其关联对象.应该如何查询.是Hibernate的一种优化手段
  • Hibernate框架的检索策略解决的问题
    查询的时机:lazy属性解决查询的时机的问题,需要配置是否采用延迟加载!!
    查询的语句形式:fetch属性就可以解决查询语句的形式的问题

立即检索和延迟检索

  • 立即检索:当执行到某条语句的时候,就会马上发送SQL.(get方法)
  • 延迟检索:当执行到某条语句的时候,不会马上发送SQL.当真正使用对象的属性的时候,才会发送SQL语句(load方法)
    延迟检索分成类级别延迟和关联级别的延迟:
    1.类级别的延迟:查询对象的本身的时候是否采用延迟,默认情况下是采用延迟。使延迟加载失效的办法:上配置lazy="false"  如果是true,采用延迟加载,如果是false,不采用
    2.关联级别的延迟:类中所关联的类对象是否采用延迟。可以在,等标签上设置lazy属性

抓取策略相关的属性和取值

  • 主要是:lazy、fetch:在,这些标签上,使用fetch属性和lazy属性就可以完成抓取策略的配置
  • fetch作用在set标签上
    fetch的取值    控制SQL语句生成的格式
    select         默认值,发送查询语句
    join           连接查询,发送的是一条迫切左外连接,配置了join.lazy就失效了
    subselect      子查询,发送一条子查询查询其关联对象

    lazy的取值     查找关联对象的时候是否采用延迟!
    true           默认.延迟
    false          不延迟
    extra          及其懒惰
  • fetch属性作用在many-to-one标签上
    fetch的取值    控制SQL语句生成的格式
    select         默认值,发送查询语句
    join           连接查询,发送的是一条迫切左外连接,配置了join.lazy就失效了

    lazy的取值     查找关联对象的时候是否采用延迟!
    false          不采用延迟加载
    proxy          默认值代理,现在是否采用延迟,由另一端的上的lazy确定。         如果这端的class上的lazy=true,proxy的值就是true(延迟加载),
            如果class上lazy=false,proxy的值就是false(不采用延迟)
    no-proxy      

批量抓取:batch-size

  • set元素有一个batch-size属性,用来为延迟检索策略或立即检索策略设定批量检索的数量,批量检索能减少SELECT语句的数目,提高延迟检索或立即检索的运行性能。默认值是1
  • class标签上也可以配置批量抓取

Hibernate中的事务与并发

  • 什么是事务
    事务就是逻辑上的一组操作,组成事务的各个执行单元,操作要么全都成功,要么全都失败
  • 事务的特性
    原子性   事务不可分割.
    一致性   事务执行的前后数据的完整性保持一致.
    隔离性   一个事务执行的过程中,不应该受到其他的事务的干扰.
    持久性   事务一旦提交,数据就永久保持到数据库中.
  • 如果不考虑隔离性:引发一些读的问题
    脏读:一个事务读到了另一个事务未提交的数据.
    不可重复读:一个事务读到了另一个事务已经提交的update数据,导致多次查询结果不一致.
    幻读:一个事务读到了另一个事务已经提交的insert数据,导致多次查询结构不一致.
  • 通过设置数据库的隔离级别来解决上述读的问题
    未提交读:以上的读的问题都有可能发生.
    已提交读:避免脏读,但是不可重复读,幻读都有可能发生.
    可重复读:避免脏读,不可重复读,但是幻读是有可能发生.
    串行化:以上读的情况都可以避免.
  • 如果想在Hibernate的框架中来设置隔离级别,需要在hibernate.cfg.xml的配置文件中通过标签来配置
    通过:hibernate.connection.isolation = 4 来配置
    取值:
    1—Read uncommitted isolation
    2—Read committed isolation
    4—Repeatable read isolation
    8—Serializable isolation

Hibernate的一级缓存(Session对象的一级缓存)

  • 什么是缓存 其实就是一块内存空间,将数据源中的数据存放到缓存中。再次获取的时候,直接从缓存中获取,可以提升程序的性能!
  • Hibernate框架提供了两种缓存
    一级缓存:自带的不可卸载的,一级缓存的生命周期与session一致,一级缓存称为session级别的缓存.
    二级缓存:默认没有开启,需要手动配置才可以使用的,二级缓存可以在多个session中共享数据,二级缓存称为是sessionFactory级别的缓存.
  • Session对象的缓存概述
    Session接口中,有一系列的java的集合,这些java集合构成了Session级别的缓存(一级缓存),将对象存入到一级缓存中。
    如果session没有结束生命周期,那么对象就在session中存放着
  • 证明一级缓存的存在,编写查询的代码即可证明
    在同一个Session对象中两次查询,可以证明使用了缓存  
  • Hibernate框架是如何做到数据发生变化时进行同步操作的呢?
    利用快照机制来完成的。

Hibernate的二级缓存的概述

  • 内存中存放经常操作的数据可以放入缓存中,减少与数据库的交互,提升性能
  • Hibernate一级缓存是Session级别的缓存。这一级别的缓存由 hibernate 管理的,一般情况下无需进行干预
  • Hibernate二级缓存是SessionFactory级别的缓存,它是属于进程范围的缓存,被多个Session(线程)共享

Hibernate的二级缓存的并发访问策略的问题

  • 由于二级缓存被多线程所共享,就必须要有一定的事务策略,二级缓存可以设定以下4种类型的并发访问策略,每一种访问策略对应一个事务隔离级别
    只读缓存(read-only)
    读/写缓存(read-write)
    不严格的读/写缓存(nonstrict-read-write)
    事务缓存(transactional)
  • 在上面所介绍的隔离级别中,事务型并发访问策略的隔离级别最高,然后依次是读/写型和不严格读写型,只读型的隔离级别最低。事务的隔离级别越高,并发性能就越低

Hibernate的二级缓存存放的数据

  • 适合放入的数据(默认的规范)
    很少被修改
    不是很重要的数据, 允许出现偶尔的并发问题
  • 不适合放入的数据
    经常被修改
    财务数据, 绝对不允许出现并发问题
    与其他应用数据共享的数据

解释get和load的方法的区别(面试题)

    get是立即加载,load延迟加载,真正使用对象的属性的时候才会发送SQL语句。
    get方法查询的结果就是对象的本身,load方法查询的结果是对象的代理对象.
    get方法查询一个找不到的记录的时候,返回Null,load方法查询一个找不到的对象的时候,返回ObjectNotFoundException.

Hibernate的检索方式(查询的方式)

  • 导航对象图的检索方式
    例如如下这种代码
        Customer customer = ...;
        Set orders = customer.getOrders();
        Order order = ...;
        order.getCustomer();
  • 唯一标识OID的检索方式
    get或者load的方法的方式
    session.get(Cusotmer.class,1);    
  • HQL的检索方式(重点掌握)
    session.createQuery("hql语句");
  • QBC的检索方式
    session.createCriteria(Customer.class);
    面向对象的查询的方式
  • 本地SQL的检索方式
    本地的SQL检索

Hibernate框架的SQL查询

基本语法
    // 查询所有
    SQLQuery sqlQuery = session.createSQLQuery("select * from customers");
    // JavaBean的Class类通过参数的方式传递进去
    sqlQuery.addEntity(Customer.class);
    List<Customer> list = sqlQuery.list();
    for (Customer customer : list) {
        System.out.println(customer);
    }
复制代码

HQL的检索(使用Hibernate框架,就尽量使用HQL语句查询)

  • HQL(Hibernate Query Language) 是面向对象的查询语言,它和SQL查询语言有些相似
  • HQL与SQL的关系
    HQL查询语句是面向对象的,Hibernate负责解析HQL查询语句,然后根据对象-关系映射文件中的映射信息,把HQL查询语句翻译成相应的SQL语句
    HQL查询语句中的主体是域模型中的类及类的属性  
    SQL查询语句是与关系数据库绑定在一起的,SQL查询语句中的主体是数据库表及表的字段

HQL查询的演示

  • 简单查询
    List<Customer> list = session.createQuery("from Customer").list();
复制代码
  • 使用别名的方式
    List<Customer> list = session.createQuery("select c from Customer c").list();
复制代码
  • 排序查询
    升序(默认也是是升序)
    List<Customer> list = session.createQuery("from Customer order by age").list();
复制代码
    降序
    List<Customer> list = session.createQuery("from Customer order by age desc").list();
复制代码
  • 分页查询
    Hibernate框架提供了分页的方法,咱们可以调用方法来完成分页。推荐大家使用它的方法。框架会根据不同的数据库,完成不同的分页方式。
    两个方法如下:
        setFirstResult()    从哪条记录开始(默认是0代表第一条记录)
        setMaxResults()     每页查询的记录条数(一般都是固定值)
    测试代码如下:
    List<Order> list = session.createQuery("from Order").setFirstResult(0).setMaxResults(4).list();
复制代码
  • 唯一对象查询
    查询某一个对象,用get()或者load()的方法
    检索某一个对象,使用uniqueResult()该方法
    Department department=(Department)session.createQuery("from Department d where d.deptId = ?").setParameter(0, 1).uniqueResult();
复制代码
  • 带条件的查询
    setParameter("?号的位置,默认从0开始","参数的值"); 不用考虑参数的具体类型
    按位置绑定参数的条件查询(指定下标值,默认从0开始)
    session.createQuery("from Customer where cname like ?").setParameter(0, "张%").list();
    session.createQuery("from Customer where cname = ? and age > ?").setParameter(0, "李四").setParameter(1, 25).list();
复制代码
    按名称绑定参数的条件查询(HQL语句中的 ? 号换成 :名称 的方式)
    session.createQuery("from Customer where cname like :name").setParameter("name", "张%").list();
    session.createQuery("from Customer where cname = :name and age > :age").setParameter("name", "李四").setParameter("age", 25).list();
复制代码

HQL的投影查询

  • 投影查询就是想查询某一字段的值或者某几个字段的值
  • 投影查询的案例
    如果只查询一个字段
    List<String> list = session.createQuery("select cname from Customer").list();
    for (String string : list) {
        System.out.println(string);
    }
复制代码
    如果查询两个字段
    List<Object[]> list = session.createQuery("select cname,age from Customer").list();
    for (Object[] objects : list) {
        System.out.println(Arrays.toString(objects));
    }
复制代码
    如果查询两个字段,也可以把这两个字段封装到对象中
    先在持久化类中提供对应字段的构造方法
    List<Customer> list = session.createQuery("select new Customer(cname,age) from Customer").list();
    for (Customer customer : list) {
        System.out.println(customer);
    }
复制代码

聚集函数

  • 聚集函数(一般和分组在一起使用的时候,才会有效果)
    count()       计数
    sum()         求和
    avg()         平均值
    max()         最大值
    min()         最小值
  • 使用聚集函数的查询
    Query query = session.createQuery("select count(*) from Customer c");
    Integer count=(Integer)query.uniqueResult();
    System.out.println("count "+count);

    Query query = session.createQuery("select avg(c.age) from Customer c");
    Double avg=(Double)query.uniqueResult();
    System.out.println("avg "+avg);

    Query query = session.createQuery("select max(c.age),min(c.age) from  Customer c");
    Object[] maxmin=(Object[])query.uniqueResult();
    System.out.println("max "+(Long)maxmin[0]);
    System.out.println("min "+(Long)maxmin[1]);

    Query query = session.createQuery("select sum(c.age) from Customer c");
    Long sum=(Long)query.uniqueResult();
    System.out.println("sum "+sum);
复制代码
  • 分组查询
    相关代码
    List<Object[]> list=session.createQuery("select c.cname,count(c) from Customer c group by c.cname").list();
    System.out.println(list.size());
    for(int i=0;i<list.size();i++){
        Object [] o = list.get(i);
        System.out.print(o[0]+" : "+o[1]);
    }
复制代码

QBC检索方式

  • 简单查询,使用的是Criteria接口
    List<Customer> list = session.createCriteria(Customer.class).list();
    for (Customer customer : list) {
        System.out.println(customer);
    }
复制代码
  • 排序查询(要注意需要使用到Hibernate提供的Order类)
    需要使用addOrder()的方法来设置参数,参数使用org.hibernate.criterion.Order对象
    Criteria criteria = session.createCriteria(Customer.class);
    criteria.addOrder(org.hibernate.criterion.Order.asc("age"));
复制代码
  • 分页查询
    Criteria criteria = session.createCriteria(Order.class);
    criteria.setFirstResult(0);
    criteria.setMaxResults(10);
    List list = criteria.list();
  • 条件查询
    条件查询使用Criteria接口的add方法,用来传入条件。
    使用Restrictions的添加条件的方法,来添加条件,例如:
        Restrictions.eq                 =
        Restrictions.gt                 >
        Restrictions.ge                 >=
        Restrictions.lt                 <
        Restrictions.le                 <=
        Restrictions.between            between
        Restrictions.like               like
        Restrictions.in                 in
        Restrictions.and                and
        Restrictions.or                 or
        Restrictions.asc()              asc
        Restrictions.desc()             desc
    Criteria criteria = session.createCriteria(Customer.class);
    criteria.add(Restrictions.like("cname", "张%"));
    List<Customer> list = criteria.list();

    Criteria criteria = session.createCriteria(Customer.class);
    criteria.add(Restrictions.eq("cname", "李四"));
    criteria.add(Restrictions.gt("age", 25));
    List<Customer> list = criteria.list();
复制代码

多表查询

  • 多表的查询进来使用HQL语句进行查询,HQL语句和SQL语句的查询语法比较类似。
  • 先回忆多表查询相关的语法
    内连接
        显示内连接
            select * from customers c inner join orders o on c.cid = o.cno;
        隐式内连接
            select * from customers c,orders o where c.cid = o.cno;

    外连接
        左外连接
            select * from customers c left outer join orders o on c.cid = o.cno;
        右外连接
            select * from customers c right outer join orders o on c.cid = o.cno;
  • HQL的多表查询
    迫切和非迫切:
        非迫切返回结果是Object[]
        迫切连接返回的结果是对象,把客户的信息封装到客户的对象中,把订单的信息封装到客户的Set集合中。
        说明:HQL语句是支持内连接和外连接的。并且又多提供了两种方式(迫切内连接和迫切左外连接)
    内连接使用 inner join ,默认返回的是Object数组
    基本的语句:
    List<Object[]> list = session.createQuery("from Customer c inner join c.orders").list();
复制代码
    问题
        默认把查询的数据封装到Object[]的数组中。
        如果想把数据封装到Customer对象中,需要这样来编写SQL语句
    List<Customer> list = session.createQuery("select c from Customer c inner join c.orders").list();
复制代码
    想去掉重复的数据,使用distinct关键字
    迫切内连接:inner join fetch ,返回的是实体对象
    迫切内连接和普通的内连接的SQL语句都相同
    List<Customer> list = session.createQuery("select distinct c from Customer c inner join fetch c.orders").list();
复制代码

外连接:
    左外连接: 封装成List<Object[]>
    迫切左外连接:封装成List<Customer>
复制代码
    List<Customer> list = session.createQuery("select distinct c from Customer c left outer join c.orders").list();
复制代码
    或者使用set集合来去掉重复的数据
    List<Customer> list = session.createQuery("from Customer c left outer join fetch c.orders").list();
    Set<Customer> set = new HashSet<Customer>(list);
    for (Customer c : set) {
        System.out.println(c);
    }
复制代码

转载于:https://juejin.im/post/5bcb468e6fb9a05cdd2d3f62

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值