目录

​day03​

​工具类HibernateUtils(Main方法就可以帮助生成表结构)​

​简单配置和一对多​

​customer.java​

​Linkman.java​

​hibernate.cfg.xml​

​Customer.hbm.xml​

​Linkman.hbm.xml​

​★Demo1.java​

​多对多​

​User.java​

​Role.java​

​User.hbm.xml​

​Role.hbm.xml​

​★Demo2.java​

​day04(查询专题)​

​环境搭建​

​hibernate.cfg.xml​

​开始查询​

​Demo1.java(对象导航查询)​

​Demo2.java(HQL的基本查询)​

​Demo3.java​

​Demo4.java​

​Demo5.java​

​案例一:查询所有联系人​

​ListLinkmanServlet.java​

​LinkmanService.java​

​LinkmanDao.java​

​案例二:对查询功能优化​

​Demo6.java​

​Customer.hbm.xml​

​Demo7.java​

​Demo8.java​


day03

工具类HibernateUtils(Main方法就可以帮助生成表结构)

package com.itheima.utils;

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

/**
* hibernate框架的工具类
* 由于是重量级的不能轻易销毁创建 于是封装工具类
* @author Administrator
*
*/
public class HibernateUtils {
//ctrl+shift+x 转大写
private static final Configuration CONFIG;
private static final SessionFactory FACTORY;

//静态代码块赋值常量
static{
//加载xml配置文件
CONFIG=new Configuration().configure();
//构造工厂
FACTORY=CONFIG.buildSessionFactory();
}

/**
* 从工厂中获取session对象
*/
public static Session getSession(){
return FACTORY.openSession();
}


/**
* 从ThreadLocal类中获取到session的对象
* 就是获取当前线程里的那个session对象 以保证service层和dao层的session相同 (不用传引用了)
* (说明hibernate框架下,三层之间调用时,当前线程里有一个session 难怪factory获取session方法名为open而不是创建)
*/
public static Session getCurrentSession(){
return FACTORY.getCurrentSession();
}

public static void main(String[] args) {
getSession();//调用getsession 会创建重量级的SessionFactory 一旦创建 所有的配置文件被加载 (缓存很多数据) 表结构也就有了
}
}

 

简单配置和一对多

customer.java

package com.itheima.domain;

import java.util.HashSet;
import java.util.Set;

/**
* 客户
* 一方 (一个客户有可以有多个联系人)
* @author Administrator
*
*/
public class Customer {
//以后都使用包装类 默认值null
private Long cust_id;
private String cust_name;
private Long cust_user_id;
private Long cust_create_id;

private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_linkman;
private String cust_phone;
private String cust_mobile;

/*以上名称可以瞎写了,框架都可以做到连接*/

//hibernate框架默认的集合是set 集合必须手动初始化 即new一段内存
//一个客户可以有多个联系人 则在一方写一个map存下所有的联系人对象
private Set<Linkman> linkmans=new HashSet<Linkman>();


public Long getCust_id() {
return cust_id;
}
public void setCust_id(Long cust_id) {
this.cust_id = cust_id;
}

......

public Set<Linkman> getLinkmans() {
return linkmans;
}
public void setLinkmans(Set<Linkman> linkmans) {
this.linkmans = linkmans;
}

}

Linkman.java

package com.itheima.domain;

/**
* 客户的联系人 (客户家的一个负责联系的人)
* 多方: 一个联系人只能属于一个客户
* @author Administrator
*
*/
public class Linkman {
/*
* `lkm_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)',
`lkm_name` varchar(16) DEFAULT NULL COMMENT '联系人姓名',
`lkm_cust_id` bigint(32) NOT NULL COMMENT '客户id',
`lkm_gender` char(1) DEFAULT NULL COMMENT '联系人性别',
`lkm_phone` varchar(16) DEFAULT NULL COMMENT '联系人办公电话',
`lkm_mobile` varchar(16) DEFAULT NULL COMMENT '联系人手机',
`lkm_email` varchar(64) DEFAULT NULL COMMENT '联系人邮箱',
`lkm_qq` varchar(16) DEFAULT NULL COMMENT '联系人qq',
`lkm_position` varchar(16) DEFAULT NULL COMMENT '联系人职位',
`lkm_memo` varchar(512) DEFAULT NULL COMMENT '联系人备注',
*/

//注意主键怎么写
private Long lkm_id;//主键
private String lkm_name;
private String lkm_gender;
private String lkm_phone;
private String lkm_mobile;
private String lkm_email;
private String lkm_qq;
private String lkm_position;
private String lkm_memo;

//多方 一个联系人属于一个客户
//就是有外键的那一方 不写外键 写一个一方的对象即可
//此对象千万不要自己new 此对象的内存是hibernate框架帮你new的
private Customer customer;


public Long getLkm_id() {
return lkm_id;
}
public void setLkm_id(Long lkm_id) {
this.lkm_id = lkm_id;
}

.....

public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}

}

hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<!-- 记住:先配置SessionFactory标签,一个数据库对应一个SessionFactory标签 -->
<session-factory>
<!-- 必须配置的参数有5个:4大参数+数据库的方言 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 表能帮你创建 但数据库得自己创建 -->
<property name="hibernate.connection.url">jdbc:mysql:///hibernate_day03</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">1111</property>
<!-- 数据库的方言 mysql独有的语法 告诉hibernate 它会帮你实现底层代码-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

<!-- 可选配置 -->
<!-- 在控制台打印sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化sql语句 控制台打印时好看一点 -->
<property name="hibernate.format_sql">true</property>
<!-- 生成数据库的表结构 之前数据库没有建表 帮你自动生成 (把表删了再测试,确实有create语句打印在控制台)-->
<!-- update最好 有添加,没有创建 -->
<property name="hibernate.hbm2ddl.auto">update</property>

<!-- 可以手动设置数据库的隔离级别,就使用默认值就OK 4可重复读就是mysql默认的 -->
<property name="hibernate.connection.isolation">4</property>

<!-- 开启绑定本地session 注意:name值的中间的thread都是固定的-->
<property name="hibernate.current_session_context_class">thread</property>

<!-- 映射配置文件,需要引入映射的配置文件 -->
<!-- 注意 1.不是代码内右键复制,而是文件上右键复制 2:中间是/不是. 3.复制全限定名后要删去前面的,从包名com开始 -->

<!-- <mapping resource="com/itheima/domain/Customer.hbm.xml"/>
<mapping resource="com/itheima/domain/Linkman.hbm.xml"/> -->
<!-- 映射一旦被删了 表是不会被自动生成的 从演示多对对开始,注释了上面两行-->


<!-- 多对多 -->
<mapping resource="com/itheima/domain/User.hbm.xml"/>
<mapping resource="com/itheima/domain/Role.hbm.xml"/>

</session-factory>

</hibernate-configuration>

Customer.hbm.xml

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

<hibernate-mapping>

<!-- 配置类和表结构的映射 -->
<!-- name:类的全限定名 table:数据库中定义的表名 catalog:数据库名 可写可不写 核心配置文件配过了已经-->
<class name="com.itheima.domain.Customer" table="cst_customer">
<!-- 配置id
见到name属性,JavaBean属性
见到column属性,是表的结构字段
-->
<!-- 下面一行便将Customer类的cust_id属性和表cst_customer的字段建立关联了,
于是对框架来说,类属性名和表字段名不必完全一样,这里配置对应了就行了 但基础部分的DButils就失效了-->
<id name="cust_id" column="cust_id"> <!-- 配置了主键,则这个属性就是当前类的唯一标识oid -->
<!-- 主键生成策略 native表示自动递增 uuid随机值-->
<generator class="native"/>
</id>
<!-- 上面配置的是主键 主键很重要 单独配置 其他属性也要一个个单独配置 以后有表结构就能自动生成配置文件,不用这么麻烦了 (以后甚至增删改查代码都能自动生成了) -->

<!-- 配置其他属性 length属性可以省略 若没有创建数据库表-->
<property name="cust_name" column="cust_name"/>
<property name="cust_user_id" column="cust_user_id"/>
<property name="cust_create_id" column="cust_create_id"/>
<property name="cust_source" column="cust_source"/>
<property name="cust_industry" column="cust_industry"/>
<property name="cust_level" column="cust_level"/>
<property name="cust_linkman" column="cust_linkman"/>
<property name="cust_phone" column="cust_phone"/>
<property name="cust_mobile" column="cust_mobile"/>

<!-- 配置一方 -->
<!-- hibernate的set属性配置也是set标签
set标签name属性:表示集合的名称
--> <!-- 单向级联 保存customer一方时在此配 -->
<!-- save-update 无保存 有更新 -->
<!-- delete 删除客户时会级联删除客户下的联系人 -->
<!-- all等价于 save-update,delete -->
<!-- delete-orphan 孤儿删除 -->
<!-- inverse="true"放弃外键约束 -->
<set name="linkmans" inverse="true">
<!-- 需要出现子标签 -->
<!-- 数据库表外键的字段 多方表的外键字段名称-->
<key column="lkm_cust_id" />
<one-to-many class="com.itheima.domain.Linkman"/> <!-- 多方类为value 正好符合set集合的key-value对应关系 -->
</set>

<!-- 映射配置好后 就不用处理外键了 映射自动帮你创建了 -->

</class>

</hibernate-mapping>

Linkman.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!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.itheima.domain.Linkman" table="cst_linkman">
<id name="lkm_id" column="lkm_id">
<generator class="native"/>
</id>

<property name="lkm_name" column="lkm_name"/>
<property name="lkm_gender" column="lkm_gender"/>
<property name="lkm_phone" column="lkm_phone"/>
<property name="lkm_mobile" column="lkm_mobile"/>
<property name="lkm_email" column="lkm_email"/>
<property name="lkm_qq" column="lkm_qq"/>
<property name="lkm_position" column="lkm_position"/>
<property name="lkm_memo" column="lkm_memo"/>
<!-- 没有结束的标签 单标签 -->

<!-- 先配置多方 (一个对象) 多对一
name 当前javabean中的属性(一方对象的那个属性)
class 属性全路径
column 数据库表中的外键字段
--> <!-- 前面不能new 此处根据实际javabean全限定名和反射帮你创建 -->
<!-- 多对一 配置多方外键字段对应的对象-->
<many-to-one name="customer" class="com.itheima.domain.Customer"
column="lkm_cust_id" cascade="save-update" /> <!--注释掉以免影响孤儿删除 cascade="save-update,delete" -->
</class>

</hibernate-mapping>

★Demo1.java

package com.itheima.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.itheima.domain.Customer;
import com.itheima.domain.Linkman;
import com.itheima.utils.HibernateUtils;

/**
* 测试一对多
* @author Administrator
*/
public class Demo1 {

/**
* 最麻烦的双向关联的方式,保存数据
*/
@Test
public void run1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();

//保存客户和联系人的数据
//创建一个客户
Customer c1 = new Customer();
c1.setCust_name("美美");

//创建2个联系人
Linkman l1=new Linkman();
l1.setLkm_name("熊大");
Linkman l2=new Linkman();
l2.setLkm_name("熊二");

//双向关联
//一方添加多方
c1.getLinkmans().add(l1);
c1.getLinkmans().add(l2);
//多方分别添加一方
l1.setCustomer(c1);
l2.setCustomer(c1);

//保存数据
session.save(c1);
session.save(l1);//竟然写成了11 报java.lang.Integer
session.save(l2);

tr.commit();
//getCurrentSession 不需要手动关闭 线程结束自动关闭了... 冗余的代码几乎都没了..
}


/**
* 改进 单向关联 不配置建联保存 会出现异常
*/
@Test
public void run2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();

//保存客户和联系人的数据
//创建一个客户
Customer c1 = new Customer();
c1.setCust_name("美美");

//创建2个联系人
Linkman l1=new Linkman();
l1.setLkm_name("熊大");
Linkman l2=new Linkman();
l2.setLkm_name("熊二");

//单向关联 操作一方即可
//一方添加多方
c1.getLinkmans().add(l1);
c1.getLinkmans().add(l2);

//保存数据
session.save(c1);

//不配置文件 此时直接运行 报瞬时态对象异常 l1、l2瞬时态(没有save就没有主键 更没有进缓存)

//配置文件里配置一下 级联保存即可 customer.hbm.xml cascade="save-update"

tr.commit();
//getCurrentSession 不需要手动关闭 线程结束自动关闭了... 冗余的代码几乎都没了..
}


/**
* 改进 单向关联 级联保存 有配置
* 保存客户 配置客户的xml 级联联系人 cascade="save"
*/
@Test
public void run3(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();

//保存客户和联系人的数据
//创建一个客户
Customer c1 = new Customer();
c1.setCust_name("美美");

//创建2个联系人
Linkman l1=new Linkman();
l1.setLkm_name("熊大");
Linkman l2=new Linkman();
l2.setLkm_name("熊二");

//单向关联 操作一方即可
//一方添加多方
c1.getLinkmans().add(l1);
c1.getLinkmans().add(l2);

//保存数据
session.save(c1);

tr.commit();
}


/**
* 改进 单向关联 级联保存 有配置
* 保存联系人 配置联系人的xml 级联客户 Linkman.hbm.xml cascade="save-update"
* (此用例时 customer.hbm.xml没有配置cascade)
*/
@Test
public void run4(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();

//保存客户和联系人的数据
//创建一个客户
Customer c1 = new Customer();
c1.setCust_name("美美");

//创建2个联系人
Linkman l1=new Linkman();
l1.setLkm_name("熊大");
Linkman l2=new Linkman();
l2.setLkm_name("熊二");

//单向关联 操作一方即可
//多方添加一方 联系人添加客户
l1.setCustomer(c1);
l2.setCustomer(c1);

//保存数据
session.save(l1);
session.save(l2);//第二次级联保存c1时发现c1已经存在了,此时就是执行save-uodate中的update了

tr.commit();
}

/**
* 两边都配置了级联 此时巧妙节省代码
* 两个xml cascade="save-update"
*/
@Test
public void run5(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();

//保存客户和联系人的数据
//创建一个客户
Customer c1 = new Customer();
c1.setCust_name("美美");

//创建2个联系人
Linkman l1=new Linkman();
l1.setLkm_name("熊大");
Linkman l2=new Linkman();
l2.setLkm_name("熊二");

l1.setCustomer(c1);
c1.getLinkmans().add(l2);

//保存数据
session.save(l1);

tr.commit();
}

/**
* 测试删除客户:注意客户下有两个联系人(联系人外键关联了客户)
* 本来由于外键约束是删不了的,但是Hibernate可以删,具体做法是先将外键字段置为null,然后再删
*/
@Test
public void run6(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//先查询1号客户
Customer c1 = session.get(Customer.class, 1L);
session.delete(c1);
//一号客户下还有两个联系人,但是Hibernate照样删

tr.commit();
}

/**
* 但是其实客户删除了,联系人也就没有存在的价值了
* 级联删除更合适
* 仅customer.hbm.xml: cascade="delete"
*/
@Test
public void run7(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//先查询1号客户
Customer c1 = session.get(Customer.class, 1L);
session.delete(c1);
//一样的代码 只是此时在customer配置文件里配置下级联删除即可

tr.commit();
}

/**
* 能否删除联系人时也删除客户呢?(删除引用的外键的主表的记录 显然不合理 但是只要你配置好了,还是能删的)
* 两个配置文件里都加上:cascade="delete"
*/
@Test
public void run8(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//先查询1号联系人
Linkman man = session.get(Linkman.class, 1L);
//删除man 由于man配置了cascade="delete" 会删除它引用的Customer
//而Customer也设置了级联删除 那么其下面的所有联系人也都删了 一行代码全部就删完了
session.delete(man);
tr.commit();
}

/**
* 解除关系:从集合中删除联系人
* 删除所有配置
*/
@Test
public void run10(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//获取一个客户和对应联系人
Customer c1 = session.get(Customer.class, 1L);
Linkman l1 = session.get(Linkman.class, 1L);
//解除两者之间的关系
c1.getLinkmans().remove(l1);
//此时不配置孤儿删除 数据库不会少数据

tr.commit();
}


/**
* 孤儿删除
* customer.hbm.xml: cascade="delete-orphan"
*/
@Test
public void run10_1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//获取一个客户和对应联系人
Customer c1 = session.get(Customer.class, 1L);
Linkman l1 = session.get(Linkman.class, 1L);
//解除两者之间的关系
c1.getLinkmans().remove(l1);
//配置孤儿删除 是删除c1的map中的成员 配置的是c1的xml 也很正常 肯定是父亲杀死儿子 不是儿子傻傻自杀

tr.commit();
}

/**
* 放弃外键约束
* 需求:让熊大联系人属于小风客户(本来属于美美客户的)
* 第一次执行没有任何配置
* 第二次执行customer.hbm.xml里:
*/
@Test
public void run11(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//获取小风客户 和 熊大联系人
Customer c2 = session.get(Customer.class,2L);
Linkman l1 = session.get(Linkman.class, 1L);

//做双向关联
c2.getLinkmans().add(l1);
l1.setCustomer(c2);
//做完后不用修改数据库 持久态对象自动保持与数据库一致 持久态对象具有自动更新能力
//不用配置 能直接执行成功 Hibernate可以先置外键为null然后修改 以绕过外键冲突
//然而此例子是为了演示双向关联会产生冗余的sql语句
//解决方法:让一方放弃外键约束,即customer里inverse="true" 一方维护外键要维护下面所有的set子元素的外键,麻烦 所以规定设置一方能放弃
tr.commit();
}

/**
* cascade和inverse的区别
* 1. cascade用来级联操作(保存、修改和删除) 保存和删除数据的
* 2. inverse用来维护外键的 维护外键的
* 第一次执行:customer.hbm.xml:cascade="save-update" 插入成功,且有外键约束
* 第二次执行:customer.hbm.xml:cascade="save-update" inverse="true"
* 插入成功,但是linkman外键都为null 因为操作的是customer,而customer放弃了外键维护(l1,l2虽然没有放弃,但是却也没有主动去关联c1 也即是setCustomer(c1))
*
* 注意:只有一方能放弃 也就是只能在一方放弃了 那么cascade="save-update"就只能在多方配置了 单向关联和保存也只能是多方这边操作了 见下例
*/
@Test
public void run12(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();

//保存客户和联系人的数据
//创建一个客户
Customer c1 = new Customer();
c1.setCust_name("美美");

//创建2个联系人
Linkman l1=new Linkman();
l1.setLkm_name("熊大");
Linkman l2=new Linkman();
l2.setLkm_name("熊二");

//单向关联 操作一方即可
//一方添加多方
c1.getLinkmans().add(l1);
c1.getLinkmans().add(l2);

//保存数据
session.save(c1);

tr.commit();
}

/**
* 注意:只有一方能放弃 也就是只能在一方放弃了 那么cascade="save-update"就只能在多方配置了(否则放弃后外键关联关系写不进数据库) 单向关联和保存也只能是多方这边操作了
* customer.hbm.xml: inverse="true"
* linkman.hbm.xml: cascade="save-update" (因为必须多方去单向关联一方了,否则没有外键关联关系的数据了)
*/
@Test
public void run13(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();

//保存客户和联系人的数据
//创建一个客户
Customer c1 = new Customer();
c1.setCust_name("美美");

//创建2个联系人
Linkman l1=new Linkman();
l1.setLkm_name("熊大");
Linkman l2=new Linkman();
l2.setLkm_name("熊二");

//单向关联 操作一方即可
//多方添加一方
l1.setCustomer(c1);
l2.setCustomer(c1);

//保存数据
session.save(l1);
session.save(l2);

tr.commit();
}



}

 

 

多对多

User.java

package com.itheima.domain;

import java.util.HashSet;
import java.util.Set;

/**
* 系统用户
* @author Administrator
*/
public class User {
private Long uid;
private String username;
private String password;

//对对多 此处一个用户(可以是经理,也可以是演员,可以有多重身份,以此来演示多对多)
//在用户这方,编写的是集合 注意集合必须自己手动分配内存 (角色那方也是集合)

private Set<Role> roles=new HashSet<Role>();

public Long getUid() {
return uid;
}
public void setUid(Long uid) {
this.uid = uid;
}

......

public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}

}

Role.java

package com.itheima.domain;

import java.util.HashSet;
import java.util.Set;

/**
* 系统角色
* @author Administrator
*/
public class Role {
private Long rid;
private String rname;

//多对多两方编写的都是集合
private Set<User> users=new HashSet<User>();


public Long getRid() {
return rid;
}
public void setRid(Long rid) {
this.rid = rid;
}
public String getRname() {
return rname;
}
public void setRname(String rname) {
this.rname = rname;
}
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}


}

User.hbm.xml

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

<hibernate-mapping>

<!-- 配置类和表结构的映射 -->
<!-- name:类的全限定名 table:数据库中定义的表名 catalog:数据库名 可写可不写 核心配置文件配过了已经-->
<class name="com.itheima.domain.User" table="sys_user">
<!-- 配置id
见到name属性,JavaBean属性
见到column属性,是表的结构字段-->
<id name="uid" column="uid"> <!-- 配置了主键,则这个属性就是当前类的唯一标识oid -->
<!-- 主键生成策略 native表示自动递增 uuid随机值-->
<generator class="native"/>
</id>

<!-- 配置其他属性 length属性可以省略 若没有创建数据库表-->
<property name="username" column="username"/>
<property name="password" column="password"/>

<!-- 配置多对多
set的属性:
name 集合的名称
table 中间表的名称 (打算生成表时此处表名可以随便写 中间表写好了 那么就必须把表名写对了)
-->
<set name="roles" table="sys_user_role" cascade="save-update"><!-- 很明显 两个多方的table中间表 要相同 -->
<!-- 当前JavaBean在中间表的外键的名称 -->
<key column="uid"/>

<!-- 多对多
class 集合中存入对象的全路径(另一方的全路径)
column 集合中的对象在中间表的外键名称(另一方在中间表中的名称)
-->
<many-to-many class="com.itheima.domain.Role" column="rid"/>
</set>

<!-- 映射配置好后 就不用处理外键了 映射自动帮你创建了 -->

</class>

</hibernate-mapping>

Role.hbm.xml

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

<hibernate-mapping>

<!-- 配置类和表结构的映射 -->
<!-- name:类的全限定名 table:数据库中定义的表名 catalog:数据库名 可写可不写 核心配置文件配过了已经-->
<class name="com.itheima.domain.Role" table="sys_role">
<!-- 配置id
见到name属性,JavaBean属性
见到column属性,是表的结构字段
-->
<id name="rid" column="rid"> <!-- 配置了主键,则这个属性就是当前类的唯一标识oid -->
<!-- 主键生成策略 native表示自动递增 uuid随机值-->
<generator class="native"/>
</id>

<!-- 配置其他属性 length属性可以省略 若没有创建数据库表-->
<property name="rname" column="rname"/>

<!-- 配置多对多 就是配置那个集合字段 -->
<set name="users" table="sys_user_role" inverse="true"><!-- javaBean属性和中间表关联了 -->
<!-- 下面写两个多表相关的外键 -->

<!-- 当前JavaBean在中间表的外键的名称 -->
<key column="rid"/>

<!-- 多对多
class 集合中存入对象的全路径(另一方的全路径)
column 集合中的对象在中间表的外键名称(另一方在中间表中的名称)
-->
<many-to-many class="com.itheima.domain.User" column="uid"/>
</set>

<!-- 映射配置好后 就不用处理外键了 映射自动帮你创建了 -->

</class>

</hibernate-mapping>

★Demo2.java

package com.itheima.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.itheima.domain.Role;
import com.itheima.domain.User;
import com.itheima.utils.HibernateUtils;

public class Demo2 {

/**
* 不进行任何配置,手动进行双向关联
* 但是不进行任何配置,直接运行,会报错,因为双方都在维护外键,向多表重复插入相同的联合主键,冲突,整个事务回滚了
* 所以,多对多必须有一方放弃外键
* 因为操作用户比较多,下面就让角色表放弃维护外键
*
*/
@Test
public void run1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//模拟多对多 双向关联

//创建用户
User u1 = new User();
u1.setUsername("张三");
User u2 = new User();
u2.setUsername("赵四");

//创建角色
Role r1 = new Role();
r1.setRname("经理");
Role r2 = new Role();
r2.setRname("演员");

//手动双向关联
//u1即是经理又是演员
u1.getRoles().add(r1);
u1.getRoles().add(r2);
r1.getUsers().add(u1);//麻烦
r2.getUsers().add(u1);

//u2只是经理
u2.getRoles().add(r1);
r1.getUsers().add(u2);

session.save(u1);
session.save(u2);
session.save(r1);
session.save(r2);

tr.commit();
}

/**
* 级联保存
* 有方向性
* 和一对多一样,很简单
* 此处 User.hbm.xml: cascade="save-update"
*/
@Test
public void run2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();

//单向关联

//创建用户
User u1 = new User();
u1.setUsername("张三");
User u2 = new User();
u2.setUsername("赵四");

//创建角色
Role r1 = new Role();
r1.setRname("经理");
Role r2 = new Role();
r2.setRname("演员");

//手动双向关联
//u1即是经理又是演员
u1.getRoles().add(r1);
u1.getRoles().add(r2);

//u2只是经理
u2.getRoles().add(r1);

session.save(u1);
session.save(u2);

tr.commit();
}

/**
* 只操作中间表演示(就是操作集合 集合自动维护外键)
* 业务:
* 张三用户u1有演员和经理两个角色 现在要删除演员这个角色
*/
@Test
public void run3(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
User u1 = session.get(User.class, 1L);
Role r1=session.get(Role.class, 1L);
u1.getRoles().remove(r1);
//自动更新
tr.commit();
}

}

 

day04(查询专题)

环境搭建

hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<!-- 记住:先配置SessionFactory标签,一个数据库对应一个SessionFactory标签 -->
<session-factory>
<!-- 必须配置的参数有5个:4大参数+数据库的方言 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 表能帮你创建 但数据库得自己创建 -->
<property name="hibernate.connection.url">jdbc:mysql:///hibernate_day04</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">1111</property>
<!-- 数据库的方言 mysql独有的语法 告诉hibernate 它会帮你实现底层代码-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

<!-- 可选配置 -->
<!-- 在控制台打印sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化sql语句 控制台打印时好看一点 -->
<property name="hibernate.format_sql">true</property>
<!-- 生成数据库的表结构 之前数据库没有建表 帮你自动生成 (把表删了再测试,确实有create语句打印在控制台)-->
<!-- update最好 有添加,没有创建 -->
<property name="hibernate.hbm2ddl.auto">update</property>

<!-- 可以手动设置数据库的隔离级别,就使用默认值就OK 4可重复读就是mysql默认的 -->
<property name="hibernate.connection.isolation">4</property>

<!-- 开启绑定本地session 注意:name值的中间的thread都是固定的-->
<property name="hibernate.current_session_context_class">thread</property>

<!-- 映射配置文件,需要引入映射的配置文件 -->
<!-- 注意 1.不是代码内右键复制,而是文件上右键复制 2:中间是/不是. 3.复制全限定名后要删去前面的,从包名com开始 -->

<mapping resource="com/itheima/domain/Customer.hbm.xml"/>
<mapping resource="com/itheima/domain/Linkman.hbm.xml"/>

</session-factory>

</hibernate-configuration>

开始查询

Demo1.java(对象导航查询)

package com.itheima.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.itheima.domain.Customer;
import com.itheima.domain.Linkman;
import com.itheima.utils.HibernateUtils;

/**
* 演示对象导航方式
* @author Administrator
*
*/
public class Demo1 {

/**
* 对象导航方式
*/
@Test
public void run1(){
//先查询1号客户(唯一OID方式)
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
Customer c = session.get(Customer.class, 1L);
System.out.println("==============================");
//查询该客户下的联系人的集合
System.out.println(c.getLinkmans().size());
//执行上行时才临时查数据库 linkman表的记录
//或者说查到了customer对象后就可以直接取得其下的所有联系人了,调用javabean方法时自动帮你查数据库了。
//而这就是所谓的对象导航方式查数据库(程序员似乎感觉不到)

tr.commit();
}

/**
* 查询指定联系人属于哪个客户
*/
@Test
public void run2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//先查到联系人
Linkman man = session.get(Linkman.class, 1L);
System.out.println("============================");
System.out.println(man.getCustomer().getCust_name());
//同样,上面一行也具有查询数据库的作用,这就是对象导航方式查询数据库
//(要知道开始man内存里只有表linkman里查询的一点数据,不会有customer的数据 肯定是从数据库中查到的)

tr.commit();
}

}

Demo2.java(HQL的基本查询)

package com.itheima.test;

import java.util.Arrays;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.itheima.domain.Customer;
import com.itheima.domain.Linkman;
import com.itheima.utils.HibernateUtils;

/**
* 演示HQL的基本查询
* @author Administrator
*
*/
public class Demo2 {
/**
* 基本演示
*/
@Test
public void run1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//创建HQL查询接口
Query query = session.createQuery("from Customer");//注意括号内的语句写的都是javaBean的属性
//调用list方法 默认查询
List<Customer> list = query.list();
for (Customer c : list) {
System.out.println(c);
}
tr.commit();
}

/**
* 支持方法链的编程风格
*/
@Test
public void run2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//创建HQL查询接口 直接往下点调用 支持方法链
//Query query = session.createQuery("from Customer").setString(arg0, arg1).list();
List<Customer> list = session.createQuery("from Customer").list();
for (Customer c : list) {
System.out.println(c);
}
tr.commit();
}

/**
* 使用有别名的方式
* select * from Customer错误
* select c from Customer c 正确
*/
@Test
public void run3(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//创建HQL查询接口 直接往下点调用 支持方法链 //不能select*只能select 别名 c是别名
List<Customer> list = session.createQuery("select c from Customer c").list();
for (Customer c : list) {
System.out.println(c);
}
tr.commit();
}

/**
* 使用有别名的方式
* 条件查询
*/
@Test
public void run3_1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//创建HQL查询接口 直接往下点调用 支持方法链 //不能select*只能select 别名 c是别名
List<Customer> list = session.createQuery("select c from Customer c where c.cust_id=?").setInteger(0, 1).list();
for (Customer c : list) {
System.out.println(c);
}
tr.commit();
}


/**
* 排序查询
* SQL: order by 字段 asc/desc;
* HQL: 关键字一样,都是 order by 属性
*/
@Test
public void run4(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//查询联系人 //注意lkm_id是javaBean属性
List<Linkman> list = session.createQuery("from Linkman order by lkm_id desc").list();
//List<Linkman> list = session.createQuery("from Linkman l order by l.lkm_id desc").list();
for (Linkman man : list) {
System.out.println(man);
}
tr.commit();
}


/**
* HQL分页查询两个方法(规定查询起点和查询条数 等价于查询某一页)
* setFirstResult(a) -- 从哪条记录开始,如果查询是从第一条开启,值是0
* setMaxResults(b) -- 每页查询的记录条数
*/
@Test
public void run5(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//查询联系人 //注意lkm_id是javaBean属性
Query query = session.createQuery("from Linkman");

//设置分页查询
//假定每页3条 现在查询第一页的数据
/*query.setFirstResult(0);
query.setMaxResults(3); */

//查询第二页
query.setFirstResult(3); //(当前页-1)*pageSize=(2-1)*3=3
query.setMaxResults(3);

List<Linkman> list = query.list();
for (Linkman man : list) {
System.out.println(man);
}
tr.commit();
}

/**
* 按条件进行查询
*/
@Test
public void run6(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//查询联系人 //注意lkm_id是javaBean属性
Query query = session.createQuery("from Linkman where lkm_id > ? and lkm_gender=?");

//"from Linkman where lkm_gender=?"
//query.setString(0, "男");

//"from Linkman where lkm_gender=:gender"
//query.setString("gender", "女");

//"from Linkman where lkm_id > ?" 用?的弊端 按序并且要判断字段类型
//query.setLong(0, 2L);
//好在Hibernate为我们提供了一个忽略类型的方法(Object类型参数) 用此方法较好
//query.setParameter(0, 3L);

//"from Linkman where lkm_id > ? and lkm_gender=?"
query.setParameter(0, 3L);
query.setParameter(1, "男");


List<Linkman> list = query.list();
for (Linkman man : list) {
System.out.println(man);
}
tr.commit();
}


/**********************************************************************************************/


/**
* 投影查询:只查询几个字段
*/
@Test
public void run7(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//查询联系人
Query query = session.createQuery("select lkm_name,lkm_gender from Linkman");
//若下面任然写 <Linkman> 则类型转换异常 因为默认利用无参构造方法封装所有参数 现在就两个方法,肯定不行了
List<Object[]> list = query.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
tr.commit();
}


/**
* 投影查询:只查询几个字段 设法处理
* 第一步:需要在JavaBean类提供对应的构造方法(如下面的例子 提供包含2个参数lkm_name,lkm_gender的构造方法)
* 第二步:HQL语句需要发生变化 (调用构造方法)
*/
@Test
public void run8(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//查询联系人
Query query = session.createQuery("select new Linkman(lkm_name,lkm_gender) from Linkman");
//若下面任然写 <Linkman> 则类型转换异常 因为默认利用无参构造方法封装所有参数 现在就两个方法,肯定不行了
List<Linkman> list = query.list();
for (Linkman linkman : list) {
System.out.println(linkman);//虽然全打印了 但仔细看就name和性别有值 其他的都是null
}
tr.commit();
}


/*****************************************聚合查询*****************************************/

/**
* 聚合函数: count() sum() avg() max() min()
*/
@Test
public void run9(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//查询共有多少个联系人(对象导航不行,只能查指定用户有几个联系人)
//查询所有联系人的数量 //Number是Long Integer的父类
List<Number> list = session.createQuery("select count(*) from Linkman").list();
//List<Number> list = session.createQuery("select count(l) from Linkman l").list();
//list下标法 用Number可以调用对象api方法 转成任意数字类型
Long count = list.get(0).longValue();
System.out.println("数量:"+count);
tr.commit();
}


/**
* 聚合函数: 求和 sum()
*/
@Test
public void run10(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//查询共有多少个联系人(对象导航不行,只能查指定用户有几个联系人)
//查询所有联系人的数量 //Number是Long Integer的父类
List<Number> list = session.createQuery("select sum(lkm_id) from Linkman").list();
//list下标法 用Number可以调用对象api方法 转成任意数字类型
Long count = list.get(0).longValue();
System.out.println("数量:"+count);
tr.commit();
}
}

Demo3.java

(QBC查询:Query By Criteria  按条件进行查询)

package com.itheima.test;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.junit.Test;

import com.itheima.domain.Customer;
import com.itheima.domain.Linkman;
import com.itheima.utils.HibernateUtils;


/**
* QBC查询
* : Query By Criteria 按条件进行查询
* @author Administrator
*/
public class Demo3 {

/**
* QBC的基本入门查询
*/
@Test
public void run1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//创建QBC查询接口
Criteria criteria = session.createCriteria(Customer.class);
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}


tr.commit();
}


/**
* QBC的基本入门查询
* 都是面向对象的查询,没有sql语句,所以需要了解一系列的方法
*/
@Test
public void run2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//创建QBC查询接口
Criteria criteria = session.createCriteria(Linkman.class);

//调用排序的方法 按字段lkm_id降序排序
criteria.addOrder(Order.desc("lkm_id"));

List<Linkman> list = criteria.list();
for (Linkman man : list) {
System.out.println(man);
}

tr.commit();
}

/**
* QBC分页的方法和HQL分页的方式一样的
*/
@Test
public void run3(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//创建QBC查询接口
Criteria criteria = session.createCriteria(Linkman.class);

//调用排序的方法 按字段lkm_id降序排序
criteria.addOrder(Order.desc("lkm_id"));

//设置分页方法 假设每页3行记录 下面查询第一页
criteria.setFirstResult(0);
criteria.setMaxResults(3);

List<Linkman> list = criteria.list();
for (Linkman man : list) {
System.out.println(man);
}

tr.commit();
}

/**
* QBC的条件查询
* 同样得使用方法添加条件
*/
@Test
public void run4(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//创建QBC查询接口
Criteria criteria = session.createCriteria(Linkman.class);

//使用方法添加条件 //性别等于男
/*criteria.add(Restrictions.eq("lkm_gender","男"));
criteria.add(Restrictions.ge("lkm_id", 4L));//id号大于等于4*/

//between
criteria.add(Restrictions.between("lkm_id",2L,5L));

List<Linkman> list = criteria.list();
for (Linkman man : list) {
System.out.println(man);
}

tr.commit();
}
/**
* QBC的条件查询
* in 查询
*/
@Test
public void run5(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//创建QBC查询接口
Criteria criteria = session.createCriteria(Linkman.class);

//SQL: select * from cst_linkman where lkm_id in (1,2,7)
List<Long> params=new ArrayList<Long>();
params.add(1L);
params.add(2L);
params.add(7L);

criteria.add(Restrictions.in("lkm_id", params));

List<Linkman> list = criteria.list();
for (Linkman man : list) {
System.out.println(man);
}

tr.commit();
}

/**
* 演示QBC的or方法
*/
@Test
public void run6(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//创建QBC查询接口
Criteria criteria = session.createCriteria(Linkman.class);

//SQL: select * from cst_linkman where lkm_gender='女' or lkm_id>3L;

criteria.add(Restrictions.or(
Restrictions.eq("lkm_gender", "男"),Restrictions.gt("lkm_id",3L)
));

List<Linkman> list = criteria.list();
for (Linkman man : list) {
System.out.println(man);
}

tr.commit();
}


/**
* 判断值是否为空
*/
@Test
public void run7(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//创建QBC查询接口
Criteria criteria = session.createCriteria(Linkman.class);

//查找所有email是空的记录
criteria.add(Restrictions.isNull("lkm_email"));

List<Linkman> list = criteria.list();
for (Linkman man : list) {
System.out.println(man);
}

tr.commit();
}


/**
* 聚合函数的查询
* 前面加条件是add
* 现在加聚合函数是setProjection
*/
@Test
public void run8(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//创建QBC查询接口
Criteria criteria = session.createCriteria(Linkman.class);

//设置聚合函数的方式 //当然除了count还有sum等其他一些聚合函数的方法
List<Number> list = criteria.setProjection(Projections.count("lkm_id")).list();
long count = list.get(0).longValue();
System.out.println(count);

tr.commit();
}


/**
* 强调一个问题:select count(*) from 表,接着又想查 select * from 表,存在问题
* 必须再设置一次setProjection
*/
@Test
public void run9(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//创建QBC查询接口
Criteria criteria = session.createCriteria(Linkman.class);
//设置聚合函数的方式: select count(lkm_id) from 表;=>5
criteria.setProjection(Projections.count("lkm_id"));
List<Number> list = criteria.list();
long count = list.get(0).longValue();
System.out.println(count);

//继续查询所有联系人

//必须再设置一次setProjection 此处直接清空为原始情况即可
criteria.setProjection(null);

List<Linkman> mans=criteria.list();//若不清空Projection 此时执行list count(lkm_id)还有效
for (Linkman linkman : mans) {
System.out.println(linkman);
}

tr.commit();
}

/**
* 演示离线条件对象
* 仔细分析下面代码 大体上和前面的查询差不多
* 离线查询的好处,不需要session就可以创建查询接口,就可以设置查询参数了
* 唯一需要session的时候就是执行的时候获取一下
*/
@Test
public void run10(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();

//创建离线条件的查询对象
DetachedCriteria dcriteria = DetachedCriteria.forClass(Linkman.class);
//添加查询的条件了
dcriteria.add(Restrictions.eq("lkm_gender", "男"));
//开始查询了 查询的时候仍然需要session 那么就要自己获取session了
List<Linkman> list = dcriteria.getExecutableCriteria(session).list();
for (Linkman linkman : list) {
System.out.println(linkman);
}

tr.commit();
}

/*仔细分析发现上面执行都是同一个list方法*/


}

Demo4.java

(原始sql查询方式)

package com.itheima.test;

import java.util.Arrays;
import java.util.List;

import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.itheima.domain.Linkman;
import com.itheima.utils.HibernateUtils;

/**
* 原始sql查询方式
* @author Administrator
*
*/
public class Demo4 {
/**
* 测试sql语句的查询
*/
@Test
public void run1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//创建的是sql的查询接口
SQLQuery query = session.createSQLQuery("select * from cst_linkman");
List<Object[]> list = query.list();//只能封装成Object[]数组类型(每一个字段的值作为数组元素,不知道属性名)
for (Object[] object : list) {
System.out.println(Arrays.toString(object));
}
tr.commit();
}


/**
* Object[]肯定不妥
* 下面演示把数据封装到对象中
*/
@Test
public void run2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//创建的是sql的查询接口
SQLQuery query = session.createSQLQuery("select * from cst_linkman");
//通过方法设置
query.addEntity(Linkman.class);//把类传过去,底层就能通过反射帮你封装了
List<Linkman> list = query.list();
for (Linkman linkman : list) {
System.out.println(linkman);
}

tr.commit();
}
}

Demo5.java

(多表连接查询代码)

package com.itheima.test;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.itheima.domain.Customer;
import com.itheima.domain.Linkman;
import com.itheima.utils.HibernateUtils;

/**
* HQL的多表查询
* @author Administrator
*
*/
public class Demo5 {

/**
* 查询客户联系人信息
* select * from cst_customer c,cst_linkman l where c.id=l.id;
*/
@Test
public void run1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();

//内连接的查询 createQuery默认创建HQL接口(当然,这是Hibernate框架嘛) 创建其他接口就麻烦了createSQLQuery(原始sql语句查询)
Query query = session.createQuery("from Customer c inner join c.linkmans");
//默认的返回值还是Object数组
List<Object[]> list = query.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
tr.commit();
}

/**
* 数据默认返回的数组,但可以自己设置,从而将数据封装到对象中
* 提供关键字:fetch 迫切连接
*/
@Test
public void run2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();

//内连接的查询 createQuery默认创建HQL接口(当然,这是Hibernate框架嘛) 创建其他接口就麻烦了createSQLQuery(原始sql语句查询)
Query query = session.createQuery("from Customer c inner join fetch c.linkmans");
//默认的返回值还是Object数组
List<Customer> list = query.list();
for (Customer c : list) {
System.out.println(c);//toString方法要把linkmans给加上了
}

tr.commit();
}


/**
* 数据的重复问题
* 手动解决,存入set即可去重
*/
@Test
public void run3(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();

//内连接的查询 createQuery默认创建HQL接口(当然,这是Hibernate框架嘛) 创建其他接口就麻烦了createSQLQuery(原始sql语句查询)
Query query = session.createQuery("from Customer c inner join fetch c.linkmans");//和自己的集合连接
//默认的返回值还是Object数组
List<Customer> list = query.list();
Set<Customer> set=new HashSet<Customer>(list);
for (Customer customer : set) {
System.out.println(customer);//此时所属联系人已经封装到Set<Linkman> linkmans集合中了
}
tr.commit();
}


/**
* 左外连接
* 和内连接一样,把inner改成left即可
*/
@Test
public void run4(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();

//内连接的查询 createQuery默认创建HQL接口(当然,这是Hibernate框架嘛) 创建其他接口就麻烦了createSQLQuery(原始sql语句查询)
Query query = session.createQuery("from Customer c left join fetch c.linkmans");//和自己的集合连接
//默认的返回值还是Object数组
List<Customer> list = query.list();
Set<Customer> set=new HashSet<Customer>(list);
for (Customer customer : set) {
System.out.println(customer);//此时所属联系人已经封装到Set<Linkman> linkmans集合中了
}
tr.commit();
}

}

案例一:查询所有联系人

ListLinkmanServlet.java

package com.itheima.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;

import com.itheima.domain.Linkman;
import com.itheima.service.LinkmanService;

/**
* 查询所有的联系人
* @author Administrator
*
*/
public class ListLinkmanServlet extends HttpServlet {

public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
String lkmName = request.getParameter("lkmName");
//前端的查询条件可能变化,一个两个查询参数都有可能 ,若使用传递参数的方法传递查询参数,需要改动函数的结构,比较麻烦
//下面使用离线条件查询的方法

//先创建离线条件查询对象,脱离session对象
DetachedCriteria criteria = DetachedCriteria.forClass(Linkman.class);
//添加查询条件
if(lkmName!=null&&!lkmName.trim().isEmpty()){
//拼接查询条件
criteria.add(Restrictions.like("lkm_name", "%"+lkmName+"%"));
}
//调用业务层
List<Linkman> mans=new LinkmanService().findAll(criteria);
request.setAttribute("mans", mans);
request.getRequestDispatcher("/jsp/linkman/list.jsp").forward(request, response);

}

public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}


}

LinkmanService.java

package com.itheima.service;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.DetachedCriteria;

import com.itheima.dao.CustomerDao;
import com.itheima.dao.LinkmanDao;
import com.itheima.domain.Customer;
import com.itheima.domain.Linkman;
import com.itheima.utils.HibernateUtils;

public class LinkmanService {

/**
* 开始编写业务了(web层只负责传递所有需要的数据即可)
* 先把客户查出来,设置到联系人中,然后再保存
* @param man
* @param cust_id
*/
public void save(Linkman man, Long cust_id) {
Session session = HibernateUtils.getCurrentSession();//写此行时先得检查是否开启绑定本地session
Transaction tr = session.beginTransaction();
try {
//编写代码
//1.查客户 直接dao不需要 customerService了
Customer c=new CustomerDao().findById(cust_id);
//2.设置
man.setCustomer(c);//行了 保存数据库时 框架会会帮助你写对应的id值的
//3.保存联系人
new LinkmanDao().save(man);

tr.commit();
System.out.println("保存联系人成功!");
} catch (Exception e) {
tr.rollback();
e.printStackTrace();
}

}

/**
* 获取所有联系人
* @return
*/
public List<Linkman> findAll() {
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
List<Linkman> mans=null;
try {
//查询事务
mans=new LinkmanDao().findAll();

tr.commit();
} catch (Exception e) {
tr.rollback();
e.printStackTrace();
}
return mans;
}

/**
* 利用离线查询条件接口封装的条件来查询
* @param criteria
* @return
*/
public List<Linkman> findAll(DetachedCriteria criteria) {
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
List<Linkman> mans=null;
try {
//查询事务
mans=new LinkmanDao().findAll(criteria);
tr.commit();
} catch (Exception e) {
tr.rollback();
e.printStackTrace();
}
return mans;
}


}

LinkmanDao.java

package com.itheima.dao;

import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;

import com.itheima.domain.Linkman;
import com.itheima.utils.HibernateUtils;

public class LinkmanDao {

/**
* 保存联系人
* @param man
*/
public void save(Linkman man) {
Session session=HibernateUtils.getCurrentSession();
session.save(man);
}

/**
* 查询所有联系人
* @return
*/
public List<Linkman> findAll() {
Session session = HibernateUtils.getCurrentSession();
Query query = session.createQuery("from Linkman");
return query.list();
}

/**
* 利用离线查询条件接口封装的条件来查询
* @param criteria
* @return
*/
public List<Linkman> findAll(DetachedCriteria criteria) {
Session session = HibernateUtils.getCurrentSession();
return criteria.getExecutableCriteria(session).list();
}

}

案例二:对查询功能优化

Demo6.java

(演示延迟加载,提升程序性能 )

package com.itheima.test;

import java.util.List;

import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.itheima.domain.Customer;
import com.itheima.utils.HibernateUtils;

/**
* 演示延迟加载,提升程序性能
* @author Administrator
*
*/
public class Demo6 {
/**
* 类级别的延迟加载
* 需要使用session.load() 此方法默认情况下使用延迟加载
*
* 演示非延迟加载
*/
@Test
public void run1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//使用get方法,不是延迟加载 (先演示非延迟加载 打断点会发现下行执行完,sql语句就提交了(体验为打印出来了))
Customer c1 = session.get(Customer.class, 1L);
System.out.println("============================");
System.out.println(c1.getCust_name());

tr.commit();
}


/**
* 类级别的延迟加载
* 需要使用session.load() 此方法默认情况下使用延迟加载
*
* 演示延迟加载
*/
@Test
public void run2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//load方法 默认延迟加载
Customer c1 = session.load(Customer.class, 1L);//打断点发现执行完此行,并没有打印sql语句

//若是不想延迟加载 可以在对应类的xml文件class标签里配置lazy="false"(默认为true)
//或者不用配置,而是用代码方式初始化,立即提交查询
//Hibernate.initialize(c1);//把c1对象初始化 立即提交 不延迟了

System.out.println("============================");
System.out.println(c1.getCust_name());//打断点发现执行完此行才打印sql语句,也即sql语句才提交,也即延迟提交了(鼠标放上去也会自动执行查询,充分证明之前没提交)


tr.commit();
}

/********************************************************************************************/

/**
* 关联级别的延迟加载
* 说的是客户下的联系人的集合
*/
@Test
public void run3(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
Customer c = session.get(Customer.class, 1L);
System.out.println("================================");
System.out.println(c.getLinkmans().size());//执行到此行时才从数据库中查询集合的数据,也是延迟加载
tr.commit();
}

/**
* fetch属性能解决的问题
*/
@Test
public void run4(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//Hibernate Query Language 语句内写的都是javaBean对象
List<Customer> list = session.createQuery("from Customer").list();
for (Customer customer : list) {
System.out.println(customer.getLinkmans().size());//有几个客户此行执行几次,那么就会查询几次数据库 明显不好,慢,此时需要fetch
}
tr.commit();
}
}

Customer.hbm.xml

延迟加载的xml配置

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

<hibernate-mapping>

<!-- lazy="false"关闭延迟记载 默认为true-->
<class name="com.itheima.domain.Customer" table="cst_customer" lazy="false">

......

</class>
</hibernate-mapping>

Demo7.java

查询策略set标签上的配置

package com.itheima.test;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.itheima.domain.Customer;
import com.itheima.utils.HibernateUtils;

/**
* 查询策略
* @author Administrator
*
*/
public class Demo7 {
/**
* 默认值
* fetch是:select
* lazy是:true
*/
@Test
public void run3(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//查询1号客户
Customer c = session.get(Customer.class, 1L);
//查看客户下所有联系人
System.out.println(c.getLinkmans().size());//执行到此行时才从数据库中查询集合的数据,也是延迟加载
tr.commit();
}


/**
* 主动配置
* fetch:select 默认sql形式
* lazy:false 不延迟加载
*/
@Test
public void run4(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//查询1号客户
Customer c = session.get(Customer.class, 1L);
//查看客户下所有联系人
System.out.println(c.getLinkmans().size());//执行到此行时才从数据库中查询集合的数据,也是延迟加载
tr.commit();
}

/**
* 主动配置
* fetch:select 默认sql形式
* lazy:extra 极其懒惰的延迟加载
*/
@Test
public void run5(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//查询1号客户
Customer c = session.get(Customer.class, 1L);
//查看客户下所有联系人
System.out.println(c.getLinkmans().size());//懒加载 只查数量 其他都不查(从打印的sql语句可以看出来)
tr.commit();
}

/**
* 主动配置
* fetch:join 迫切左外连接 一条左外连接语句实现了多表查询 总共只发送一条sql语句,但是一条语句所有的事就都做完了
* lazy:true,false,extra无论配啥 都不起作用
*/
@Test
public void run6(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//查询1号客户
Customer c = session.get(Customer.class, 1L);
//查看客户下所有联系人
System.out.println(c.getLinkmans().size());//懒加载 只查数量 其他都不查(从打印的sql语句可以看出来)
tr.commit();
}

/**
* fetch:subselet 使用子查询方式查询
* lazy:true 默认延迟加载
*
* 默认配置打印1+n条语句(n是客户数 也即是循环次数)
* 配置好后 只打印2条sql语句,联系人一次就全部查完了
*/
@SuppressWarnings("all") //忽略任何警告
@Test
public void run7(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
//Hibernate Query Language 语句内写的都是javaBean对象
List<Customer> list = session.createQuery("from Customer").list();
for (Customer customer : list) {
System.out.println(customer.getLinkmans().size());//有几个客户此行执行几次,那么就会查询几次数据库 明显不好,慢,此时需要fetch
}
tr.commit();
}
}

Demo8.java

在many-to-one标签上优化配置策略

package com.itheima.test;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import com.itheima.domain.Linkman;
import com.itheima.utils.HibernateUtils;


/**
* 在many-to-one标签上查询策略的优化
* @author Administrator
*
*/
public class Demo8 {

/**
* 默认值
* fetch:select
* lazy:是延迟加载
*/
@Test
public void run1(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
Linkman linkman = session.get(Linkman.class,1L);
System.out.println(linkman.getCustomer().getCust_name());
tr.commit();
}

/**
* fetch:select
* lazy:false
*/
@Test
public void run2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
Linkman linkman = session.get(Linkman.class,1L);
System.out.println(linkman.getCustomer().getCust_name());
tr.commit();
}


/**
* fetch:select
* lazy:proxy
* 配置了proxy 则是否延迟加载 又一对多的一方(也即此处要获得的Customer一方)的class标签的lazy属性决定 true延迟(默认) false:不延迟
*/
@Test
public void run3(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
Linkman linkman = session.get(Linkman.class,1L);
System.out.println(linkman.getCustomer().getCust_name());
tr.commit();
}


/**
* fetch:join 迫切左外连接 就一条sql语句
* lazy:无论啥值都失效 一条语句解决一切(select 所有要查的表的字段列表 from 所有表)
*/
@Test
public void run4(){
Session session = HibernateUtils.getCurrentSession();
Transaction tr = session.beginTransaction();
Linkman linkman = session.get(Linkman.class,1L);
System.out.println(linkman.getCustomer().getCust_name());
tr.commit();
}

}