淘宝优惠券 如果做网站打开网站搜索
本博客为此篇博客的辅助博客,就是一些自己写的demo代码部分
目录
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 {//以后都使用包装类 默认值nullprivate 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 {/*** 最麻烦的双向关联的方式,保存数据*/@Testpublic 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.Integersession.save(l2);tr.commit();//getCurrentSession 不需要手动关闭 线程结束自动关闭了... 冗余的代码几乎都没了..}/*** 改进 单向关联 不配置建联保存 会出现异常*/@Testpublic 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"*/@Testpublic 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)*/@Testpublic 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"*/@Testpublic 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,然后再删*/@Testpublic 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"*/@Testpublic 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"*/@Testpublic 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();}/*** 解除关系:从集合中删除联系人* 删除所有配置*/@Testpublic 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"*/@Testpublic 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里:*/@Testpublic 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"就只能在多方配置了 单向关联和保存也只能是多方这边操作了 见下例*/@Testpublic 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" (因为必须多方去单向关联一方了,否则没有外键关联关系的数据了)*/@Testpublic 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 {/*** 不进行任何配置,手动进行双向关联* 但是不进行任何配置,直接运行,会报错,因为双方都在维护外键,向多表重复插入相同的联合主键,冲突,整个事务回滚了* 所以,多对多必须有一方放弃外键 * 因为操作用户比较多,下面就让角色表放弃维护外键* */@Testpublic 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"*/@Testpublic 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有演员和经理两个角色 现在要删除演员这个角色*/@Testpublic 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 {/*** 对象导航方式*/@Testpublic 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();}/*** 查询指定联系人属于哪个客户*/@Testpublic 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 {/*** 基本演示*/@Testpublic 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(); }/*** 支持方法链的编程风格*/@Testpublic 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 正确*/@Testpublic 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(); }/*** 使用有别名的方式* 条件查询*/@Testpublic 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 属性*/@Testpublic 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) -- 每页查询的记录条数*/@Testpublic 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=3query.setMaxResults(3);List<Linkman> list = query.list();for (Linkman man : list) {System.out.println(man);}tr.commit(); }/*** 按条件进行查询*/@Testpublic 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(); }/**********************************************************************************************//*** 投影查询:只查询几个字段*/@Testpublic 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语句需要发生变化 (调用构造方法)*/@Testpublic 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()*/@Testpublic 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()*/@Testpublic 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的基本入门查询*/@Testpublic 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语句,所以需要了解一系列的方法*/@Testpublic 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分页的方式一样的*/@Testpublic 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的条件查询* 同样得使用方法添加条件*/@Testpublic 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*/ //betweencriteria.add(Restrictions.between("lkm_id",2L,5L));List<Linkman> list = criteria.list();for (Linkman man : list) {System.out.println(man);}tr.commit();}/*** QBC的条件查询* in 查询*/@Testpublic 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方法*/@Testpublic 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();}/*** 判断值是否为空*/@Testpublic 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*/@Testpublic 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*/@Testpublic 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的时候就是执行的时候获取一下*/@Testpublic 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语句的查询*/@Testpublic 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[]肯定不妥* 下面演示把数据封装到对象中*/@Testpublic 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;*/@Testpublic 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 迫切连接*/@Testpublic 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即可去重*/@Testpublic 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即可*/@Testpublic 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();//写此行时先得检查是否开启绑定本地sessionTransaction 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() 此方法默认情况下使用延迟加载* * 演示非延迟加载*/@Testpublic 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() 此方法默认情况下使用延迟加载* * 演示延迟加载*/@Testpublic 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();}/********************************************************************************************//*** 关联级别的延迟加载* 说的是客户下的联系人的集合*/@Testpublic 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属性能解决的问题*/@Testpublic 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*/@Testpublic 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 不延迟加载*/@Testpublic 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 极其懒惰的延迟加载*/@Testpublic 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无论配啥 都不起作用*/@Testpublic 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") //忽略任何警告@Testpublic 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:是延迟加载*/@Testpublic 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*/@Testpublic 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:不延迟 */@Testpublic 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 所有表)*/@Testpublic 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();}}