Ø 了解什么是ORM
Ø 完成Hibernate开发环境搭建
Ø 掌握Hibernate的执行流程
Ø 掌握Hibernate开发中常用的API
框架:是来解决复杂问题的一种结构或者是一系列的组件
为什么要使用框架?
简化开发、提高开发效率
框架是分领域的:
Hibernate/Mybatis/ApacheORM/Oralce TopLink:主要解决持久层的问题(数据如何保存、数据查询…)
Struts2/Spring MVC:一个MVC框架
Spring:它是一种IOC、AOP框架
Shiro:权限框架
Apache CXF:Web服务框架
到底该如何去学习框架?
1、这个框架主要是来解决什么问题
2、快速入门(HelloWorld)
a) 搭建环境(导入JAR包 + 配置文件)
b) 编写HelloWorld代码(非常简单的、可以运行的一个程序)
3、熟悉框架的各个核心模块(API)
SSH(SSH2):struts2hibernate spring
主要应用于企业开发
SSM(SSI):spring MVC、spring、Mybatis
在互联网公司、在创业公司
MVC(理解)
ORM: ObjectRelation Mapping(重点)
Ø 学习搭建Hibernate环境,编写入门程序
Ø 学习Hibernate常用API(增删改查)
Ø 关联映射(一对一、一对多、多对多)
Ø 检索策略(LEFT JOIN、RIGHT JOIN、自然连接)
Ø Hibernate优化
Ø Hibernate 5.0.7
https://sourceforge.net/projects/hibernate/files/hibernate-orm/5.0.7.Final/
包名:com/cn/org . itheima . 模块名(使用小写)
类名:以大写驼峰式命名(Person/Product)——ProductCategory
字段名:小写驼峰式命名(id/name)
方法名:小写驼峰式命名(getOrder)
常量名:全部用大写,用下划线分隔(SESSION_USER = 1)
Ø 编写实体类
publicclass User {
private Integerid;
private Stringname;
private Stringaddress;
public Integer getId() {
returnid;
}
publicvoid setId(Integerid) {
this.id =id;
}
public String getName() {
returnname;
}
publicvoid setName(Stringname) {
this.name =name;
}
public String getAddress() {
returnaddress;
}
publicvoid setAddress(Stringaddress) {
this.address =address;
}
@Override
public String toString() {
return"User [id=" +id +", name=" +name +", address=" +address
+"]";
}
}
Ø 编写代码的几个阶段:
1、复制粘贴代码——能够看懂老师的代码(不要自己造轮子)
2、参考老师的笔记(代码)自己去编写
3、离开所有的笔记、代码独立编写
Ø Hibernate框架目录中的lib/required所有的JAR包
Ø 数据库驱动JAR包
Ø 日志JAR包
Ø 拷贝日志配置文件
将 hibernate框架目录的project/etc/log4j.properties文件拷贝到项目的src目录下
Ø xxx.hbm.xml:实体类与数据库表的映射文件
位置:实体类所在的包下,名字:类名.hbm.xml
DTD约束可以去hibernate-core-5.0.7.Final.jar的org.hibernate包下拷贝。注意:不要拷贝错了。
catalog:数据库名
name:配置实体的完全限定名称
table:配置数据库表的名称
id:配置主键(必须指定、且必须指定name)
property:配置Java类的属性与数据库的列映射
xmlversion="1.0"?>
DOCTYPEhibernate-mappingPUBLIC
"-//Hibernate/HibernateMapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.itheima.domain.User"table="t_d1h01_user">
<idname="id"column="id">
<generatorclass="native">generator>
id>
<propertyname="name"length="20">property>
<property name="address"length="50">property>
class>
hibernate-mapping>
类名、映射文件的路径都从Eclipse去拷贝,尽量不要手敲
Ø hibernate.cfg.xml:Hibernate框架的核心配置文件
Hibernae核心配置文件的dtd约束也可以从hibernate-core-5.0.7.Final.jar的org.hibernate包下拷贝。
Hibernate中的属性可以从Hibernate框架目录中的project/etc/hibernate.properties尽量从该文件中拷贝,避免因为拼写错误导致程序无法执行的问题。
hibernate.dialet:配置数据库方言(使用哪种数据库就配置成哪种方言)
DOCTYPEhibernate-configurationPUBLIC
"-//Hibernate/HibernateConfiguration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<propertyname="hibernate.connection.driver_class">com.mysql.jdbc.Driverproperty>
<property name="hibernate.connection.url">jdbc:mysql:///hibernateproperty>
<property name="hibernate.connection.username">rootproperty>
<property name="hibernate.connection.password">000000property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialectproperty>
<property name="hibernate.show_sql">trueproperty>
<property name="hibernate.format_sql">trueproperty>
<mappingresource="com/itheima/domain/User.hbm.xml"/>
session-factory>
hibernate-configuration>
Ø 方言
//新增
@Test
publicvoid testAdd01() {
Configuration cfg = new Configuration().configure(); //加载配置
SessionFactory sessionFactory = cfg.buildSessionFactory(); //创建Session工厂
Session session =sessionFactory.openSession(); //创建会话
Transaction t =session.beginTransaction(); //创建事务
User u = new User();
u.setName("王二狗");
u.setAddress("中国南京");
session.save(u); //保存对象
t.commit();//提交事务
session.close(); //关闭会话
sessionFactory.close(); //关闭Session工厂
}
Hibernate执行的SQL语句:
insert
into
t_d1h01_user
(name, address)
values
(?, ?)
注意:使用Hibernate来完成操作数据库是通过直接操作对象来完成。
使用Query去查询所有数据的时候,需要传入的是HQL(”from Customer”),注意不要写成表名,而需要写成对应的实体名称。
Ø 根据ID查询
//根据ID查询
@Test
publicvoidtestGetById01() {
Configuration cfg = newConfiguration().configure();
SessionFactory sessionFactory =cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction t = session.beginTransaction();
User user = session.get(User.class, 1); // 根据ID获取对象
System.out.println(user);
t.commit();
session.close();
sessionFactory.close();
}
Hibernate执行的SQL语句:
select
user0_.id as id1_0_0_,
user0_.name as name2_0_0_,
user0_.address as address3_0_0_
from
t_d1h01_user user0_
where
user0_.id=?
Ø 更新操作
//更新
@Test
publicvoid testUpdate01() {
Configuration cfg = newConfiguration().configure();
SessionFactory sessionFactory =cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction t = session.beginTransaction();
User user = session.get(User.class, 1);
user.setName("王吉祥");
session.update(user); //更新数据
t.commit();
session.close();
sessionFactory.close();
}
Hibernate执行的SQL语句
update
t_d1h01_user
set
name=?,
address=?
where
id=?
Ø 查询所有数据
//列表查询
@Test
publicvoid testFind01() {
Configuration cfg = newConfiguration().configure();
SessionFactory sessionFactory =cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction t = session.beginTransaction();
Query q = session.createQuery("fromUser"); // 执行HQL
System.out.println(q.list());
t.commit();
session.close();
sessionFactory.close();
}
Hibernate执行的SQL语句
select
user0_.id as id1_0_,
user0_.name as name2_0_,
user0_.address as address3_0_
from
t_d1h01_user user0_
Ø 删除数据
//删除
@Test
publicvoid testDelete01() {
Configuration cfg = newConfiguration().configure();
SessionFactory sessionFactory =cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction t = session.beginTransaction();
User user = session.get(User.class, 1);
session.delete(user); //删除数据
t.commit();
session.close();
sessionFactory.close();
}
Hibernate执行的SQL语句
delete
from
t_d1h01_user
where
id=?
Hibernate的工作原理:
Ø 通过Configuration().confige()读取hibernate.cfg.xml配置文件
Ø 由hibernate.cfg.xml中的
Ø 通过config.buildSessionFactory()来得到SessionFactory
Ø 通过sessionFactory.openSession()来得到Session
Ø 通过session.beginTransaction()来开启事务
Ø 通过session.save/update/delete/get/load来执行数据库操作
Ø 通过session.getTransaction().commit()来提交事务
Ø 关闭session
Ø 关闭sessionFactory
Ø hibernate.cfg.xml(开发中常用,需掌握)
数据库相关配置
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driverproperty>
<property name="hibernate.connection.url">jdbc:mysql:///hibernateproperty>
<property name="hibernate.connection.username">rootproperty>
<property name="hibernate.connection.password">000000property>
<propertyname="hibernate.dialect">org.hibernate.dialect.MySQLDialectproperty>
Hibernate属性配置
<property name="hibernate.hbm2ddl.auto">createproperty>
<property name="hibernate.show_sql">trueproperty>
<propertyname="hibernate.format_sql">trueproperty>
hibernate.hbm2ddl.auto配置(掌握)
#hibernate.hbm2ddl.auto create-drop
#hibernate.hbm2ddl.autocreate
#hibernate.hbm2ddl.autoupdate
#hibernate.hbm2ddl.autovalidate
加载映射文件配置
<mappingresource="com/itheima/domain/User.hbm.xml"/>
Ø hibernate.properties
<classname="com.itheima.domain.User"table="t_d1h02_user1">
<idname="id"column="id">
<generator class="native">generator>
id>
<propertyname="name">
<columnname="name"sql-type="longtext">column>
property>
<property name="address"length="50">property>
class>
Ø Hibernate数据类型映射
Configuration、SessionFactory、Session、Transaction、Query、Criteria
主要用于加载Hibernate的配置文件。
new Configuration.configure()加载的是src/hibernate.cfg.xml文件。
newConfiguration()加载的是src/hibernate.properties文件
Ø 加载指定的配置文件
Configuration cfg = newConfiguration().configure("my.hibernate.cfg.xml");
SessionFactoryfactory =cfg.buildSessionFactory();
Ø 编程方式加载hbm映射文件
文件路径方式加载:
/**
* 编程加载hbm映射文件(文件路径方式)
*/
@Test
publicvoid test02() {
Configuration cfg = newConfiguration().configure("my.hibernate.cfg.xml");
// 通过程序来加载映射文件
cfg.addResource("com/itheima/domain/User.hbm.xml");
SessionFactory factory =cfg.buildSessionFactory();
factory.close();
}
类方式加载
/**
* 编程加载hbm映射文件(类方式)
*/
@Test
publicvoid test03() {
Configuration cfg = newConfiguration().configure("my.hibernate.cfg.xml");
cfg.addClass(User.class);
SessionFactory factory =cfg.buildSessionFactory();
factory.close();
}
SessionFactory是通过Configuration得到。
Configuration cfg =new Configuration().configure();
SessionFactorysessionFactory =cfg.buildSessionFactory();
通过SessionFactory可以得到Session。一个项目中有一个SessionFactory即可。
Ø Hibernate工具类HibernateUtil
publicclass HibernateUtils {
privatestatic SessionFactorysessionFactory;
static {
Configuration cfg = newConfiguration().configure();
sessionFactory =cfg.buildSessionFactory();
}
publicstatic Session getSession() {
returnsessionFactory.openSession();
}
publicstaticvoid close() {
sessionFactory.close();
}
}
Ø 使用HibernateUtils来进行数据操作
//测试HibernateUtils保存
@Test
publicvoid test01() {
Session session = HibernateUtils.getSession();
session.beginTransaction();
User u = new User();
u.setName("测试");
u.setAddress("地址");
session.save(u);
session.getTransaction().commit();
Query q = session.createQuery("fromUser");
System.out.println(q.list());
session.close();
HibernateUtils.close();
}
Connection Pool
Ø 导入C3P0 JAR包
可以从Hibernate框架目录中的lib\optional\c3p0中复制
Ø 在hibernate.cfg.xml核心配置中添加C3P0配置
C3P0相关的配置可以从project\etc\hibernate.properties中找到
DOCTYPEhibernate-configurationPUBLIC
"-//Hibernate/HibernateConfiguration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driverproperty>
<property name="hibernate.connection.url">jdbc:mysql:///hibernateproperty>
<property name="hibernate.connection.username">rootproperty>
<property name="hibernate.connection.password">000000property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialectproperty>
<property name="hibernate.hbm2ddl.auto">updateproperty>
<property name="hibernate.show_sql">trueproperty>
<property name="hibernate.format_sql">trueproperty>
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProviderproperty>
<property name="hibernate.hibernate.c3p0.max_size">10property>
<property name="hibernate.c3p0.min_size">2property>
<mapping resource="com/itheima/User.hbm.xml"/>
session-factory>
hibernate-configuration>
Session接口是线程不安全的,需要在方法内部创建。
通过SessionFactory.openSession/getCurrentSession来获取。
save:保存
update:更新
delete:删除
get:根据ID查询(立即加载)
load:根据ID查询(懒加载)
saveOrUpdate:没有ID、有ID执行update
createQuery:获取Query对象,来执行查询(HQL语句)
createSqlQuery:获取可以执行SQL的Query对象(SQL语句)
createCriteria:获取一个Criteria,来进行QBC查询
Transaction是Hibernate的事务接口,使用它可以进行事务提交、回滚操作。
使用Session.beginTransaction()获取事务。默认每一个数据库操作都会开启事务,但不会自动提交。
可以配置让事务自动提交(不建议使用)
<propertyname="hibernate.connection.autocommit">trueproperty>
Query主要完成查询操作。
Query query =session.createQuery(HQL)
Query query =session.createSqlQuery(SQL)
按住Ctrl + 2,马上按L,自动生成局部变量
Ø 查询所有数据
/**
* HQL查询
*/
@Test
publicvoid test02() {
String hql = "FromUser";
Session s = HibernateUtils.getSession();
Query q =s.createQuery(hql);
System.out.println(q.list());
s.close();
HibernateUtils.close();
}
Ø 分页查询
/**
* HQL分页查询
*/
@Test
publicvoid test03() {
String hql = "From User";
Session s = HibernateUtils.getSession();
Query q = s.createQuery(hql);
q.setFirstResult(0); //从第几条记录开始查询
q.setMaxResults(10); //一共查询多少条数据
System.out.println(q.list());
s.close();
HibernateUtils.close();
}
/**
* 投影查询(取出数据、返回的是Object[])
*/
@Test
publicvoid test04() {
String hql = "SELECT o1.id, o1.name, o1.address FROM Usero1";
Session s = HibernateUtils.getSession();
Query q = s.createQuery(hql);
q.setFirstResult(0);
q.setMaxResults(10);
Object[] row0 = (Object[])q.list().get(0);
System.out.println((Integer)row0[0]);
s.close();
HibernateUtils.close();
}
Ø 将查询的列封装为对象
/**
* 投影查询(取出数据封装为对象)
*/
@Test
publicvoid test06() {
String hql = "SELECT new User(o1.name, o1.address) FROM User o1";
Session s = HibernateUtils.getSession();
Query q = s.createQuery(hql);
q.setFirstResult(0);
q.setMaxResults(10);
List
System.out.println(users);
s.close();
HibernateUtils.close();
}
HQL:不要写成SELECT * FROMUser…
Ø 使用无名称参数条件查询查询单条数据
/**
* 使用unqiueResult查询一条数据
*/
@Test
publicvoid test01() {
Session s = HibernateUtils.getSession();
s.beginTransaction();
String hql = "FROM User o1 WHERE o1.id = ?";
Query q = s.createQuery(hql);
q.setParameter(0, 35);
User u = (User) q.uniqueResult();
System.out.println(u);
s.getTransaction().commit();
s.close();
HibernateUtils.close();
}
Ø 使用有名称参数进行查询
/**
* 使用名称参数
*/
@Test
publicvoid test03() {
Session s = HibernateUtils.getSession();
s.beginTransaction();
String hql = "FROM User o1 WHERE o1.name LIKE :name";
Query q = s.createQuery(hql);
q.setParameter("name","%2%");
List
System.out.println(us);
s.getTransaction().commit();
s.close();
HibernateUtils.close();
}
/**
* 使用原生SQL查询
*/
@Test
publicvoid test01() {
Session s = HibernateUtils.getSession();
s.beginTransaction();
String sql = "SELECT * FROM t_d1h02_user1";
SQLQuery q = s.createSQLQuery(sql);
q.addEntity(User.class);
List
System.out.println(us);
s.getTransaction().commit();
s.close();
HibernateUtils.close();
}
/**
* 条件查询(名称参数)
*/
@Test
publicvoid test02() {
Session s = HibernateUtils.getSession();
s.beginTransaction();
String sql = "SELECT * FROM t_d1h02_user1 t1 WHERE t1.name LIKE:name";
SQLQuery q = s.createSQLQuery(sql);
q.addEntity(User.class);
q.setParameter("name","%3%");
List
System.out.println(us);
s.getTransaction().commit();
s.close();
HibernateUtils.close();
}
允许以面向对象的方式来执行查询。
Ø 基本的条件查询:Restrictions.eq/like/lt/gl/le/…(name = 111, name like …)
Ø 逻辑运算条件:Restrictions.and/or
/**
* 使用Criteria查询所有
*/
@Test
publicvoid test01() {
Session s = HibernateUtils.getSession();
s.beginTransaction();
Criteria c = s.createCriteria(User.class);
List
System.out.println(us);
s.getTransaction().commit();
s.close();
HibernateUtils.close();
}
/**
* 使用Criteria分页查询
*/
@Test
publicvoid test02() {
Session s = HibernateUtils.getSession();
s.beginTransaction();
Criteria c = s.createCriteria(User.class);
c.setFirstResult(0);
c.setMaxResults(5);
List
System.out.println(us);
s.getTransaction().commit();
s.close();
HibernateUtils.close();
}
Ø 条件查询
/**
* 使用Criteria进行多条件查询
*/
@Test
publicvoid test03() {
Session s = HibernateUtils.getSession();
s.beginTransaction();
Criteria c = s.createCriteria(User.class);
c.add(Restrictions.or(Restrictions.eq("address","地址33"), Restrictions.eq("name","测试1")));
List
System.out.println(us);
s.getTransaction().commit();
s.close();
HibernateUtils.close();
}
/**
* 使用Criteria进行排序
*/
@Test
publicvoid test04() {
Session s = HibernateUtils.getSession();
s.beginTransaction();
Criteria c = s.createCriteria(User.class);
c.addOrder(Order.desc("id"));
List
System.out.println(us);
s.getTransaction().commit();
s.close();
HibernateUtils.close();
}
Ø 断点调试(执行单步)
Ø 打log(System.out.println、console.log)
Ø 排除法(把代码注释掉、逐个去放开注释)
Ø 使用Hibernate完成增删改查功能
n 编写并使用HibernateUtils
n 使用C3P0数据源
Ø 掌握常用的主键生成策略
Ø 掌握持久化对象的三种状态
Ø 掌握一级缓存的常用操作(save/update/saveOrUpdate/delete)
Ø 掌握一对多关联映射
Ø 掌握级联操作
Ø 提供无参的构造器
Ø 为每一个实体字段提供对应的getter/setter方法
Ø 每一个实体类都需要提供一个ID(标识属性)
Ø 实体类字段均使用包装类型
Ø 实体类不能使用final修饰
重点
get与load的区别:
get立即加载,load是懒加载(底层是使用动态代理来实现,生成的代理对象需要从实体类中继承)
Ø 自然主键:具有业务意义(身份证号、学号)
Ø 代理主键:没有业务意义
主键生成器 |
描述 |
increment |
代理主键。由hibernate维护一个变量,每次生成主键时自动以递增。 问题:如果有多个应用访问一个数据库,由于每个应用维护自己的主键,所以此时主键可能冲突。建议不采用。 优点:可以方便跨平台 缺点:不适合高并发访问 |
identity |
代理主键。由底层数据库生成表识符。条件是数据库支持自动增长数据类型。比如:mysql的自增主键,oracle不支持主键自动生成。 如果数据库支持自增建议采用。 优点:由底层数据库维护,和hibernate无关 缺点:只能对支持自动增长的数据库有效,例如mysql |
sequence |
代理主键。Hibernate根据底层数据库序列生成标识符。条件是数据库支持序列。比如oracle的序列。 如果数据库支持序列建议采用。 优点:由底层数据库维护,和hibernate无关 缺点:数据库必须支持sequence方案例如oracle |
native |
代理主键。根据底层数据库对自动来选择identity、sequence、hilo 由于生成主键策略的控制权由hibernate控制,所以不建议采用。 优点:在项目中如果存在多个数据库时使用 缺点:效率比较低 |
uuid |
代理主键。Hibernate采用128bit位的UUID算法来生成标识符。该算法能够在网络环境中生成唯一的字符串标识符。 此策略可以保证生成主键的唯一性,并且提供了最好的数据库插入性能和数据库平台的无关性。建议采用。 优点:与数据库无关,方便数据库移植,效率高,不访问数据库就可以直接生成主键值,并且它能保证唯一性。 缺点:uuid长度大(32位),占用空间比较大,对应数据库中类型 char varchar |
assigned |
自然主键。由java程序负责生成标识符。 不建议采用。 尽量在操作中避免手动对主键操作 |
Ø 持久态:session中有,有OID
Ø 瞬时态(临时态):没有OID、session中不存在
Ø 脱管态(游离态):有OID、session中不存在
// 此时Customer就是一个瞬时态
Customer customer=new Customer();
// 此时customer是一个持久态
customer = session.get(Customer.class,1);
// 脱管态
Customer customer=new Customer();
customer.setId(1);
重点要记住:对象是否存在OID、在Session中是否存在
Ø 瞬时态
瞬时态→ 持久态:session.save/saveOrUpdate
瞬时态→脱管态:setId
Ø 持久态
持久态→脱管态:session.close/clear/evict
clear:清空session缓存,这里并不关闭session缓存
evict:从session里清除指定的一个持久化对象
refresh:重新去数据库中查询数据
持久态→瞬时态:session.delete
Ø 脱管态
脱管态→瞬时态:setId(null)
脱管态→持久态:session.update
在session缓存中,维护有Map,这个Map的key是持久化的对象(Customer),Value是对应Custoer的一系列属性(快照)。
注意:当事务提交或者sesssion关闭的时候,会自动将持久化对象与快照(key与value)进行比对,如果发现有改变的地方,Hibernate自动执行Update语句。
Ø update
主要用来更新脱管对象。
Session中只允许有一个唯一的OID的对象。update会将脱管态的对象转换为持久态(要将对象放在session缓存),如果session缓存中已经存在同样的OID的对象,这时候就会出现异常。
Ø saveOrUpdate
当对象是一个瞬时态,save
当对象是一个脱管态,调用的是update
Ø delete
先删除session缓存的对象,然后执行delete语句删除数据库的记录
/**
* 测试session.delete()
* 可直接将游离对象删除
*/
@Test
publicvoid test03() {
Session session = HibernateUtils.getSession();
session.beginTransaction();
// 这里直接New了一个对象,然后设置ID
User u1 = new User();
u1.setId(1);
session.delete(u1);
session.getTransaction().commit();
session.close();
HibernateUtils.close();
}
Ø 外键关联(掌握)
就是在一对一的任意一方,添加一个列,通过这个列就可以查询到另一个表中的数据
Ø 主键关联
通过两个表的主键来进行关联,两个表的主键是一样的。
publicclassEmployee{
privateArchive archive;
}
publicclassArchive{
privateEmployee employee;
}
外键在多的一方维护。在多的一方添加一个列用来关联另一个表。
publicclassCustomer{
privateSet<Order>orders;
}
publicclassOrder{
//缩写是将原因字母删除,将重复的字母删除
//message, msg
privateCustomer cstm;
}
通过中间表来完成多对多关联。中间表中保存了两个张表中的主键。
public class Student {
private Set<Teacher> teachers;
}
public class Teacher {
private Set<Student> students;
}
Ø Customer
publicclass Customer {
privateIntegerid;
private Stringname;
private Stringaddress;
//一个Customer有多个订单,这里使用Set来表示一对多的关系
privateSet
public Set
returnorders;
}
publicvoid setOrders(Set
this.orders =orders;
}
publicInteger getId() {
returnid;
}
publicvoid setId(Integerid) {
this.id =id;
}
public String getName() {
returnname;
}
publicvoid setName(Stringname) {
this.name =name;
}
public String getAddress() {
returnaddress;
}
publicvoid setAddress(Stringaddress) {
this.address =address;
}
}
Ø Order
publicclass Order {
private Stringid;
private DatecreateTime;
//多个Order订单可以对应一个Customer
privateCustomercustomer;
public Customer getCustomer() {
returncustomer;
}
publicvoid setCustomer(Customercustomer) {
this.customer =customer;
}
public String getId() {
returnid;
}
publicvoid setId(Stringid) {
this.id =id;
}
public Date getCreateTime() {
returncreateTime;
}
publicvoid setCreateTime(DatecreateTime) {
this.createTime =createTime;
}
}
找谁,怎么找?
(Customer查找订单Order了,通过Customer的id和t_order表中的外键cid来查找)
(Order查找客户Customer,也是通过t_order表的外键cid和Customer的id来查找)
Customer类中有一个Set
name表示的是要映射到的实体类中的哪个属性。
Customer要去查找到它的订单,是通过订单中外键cid来进行关联。
<set name="orders">
<keycolumn="cid">key>
<one-to-many class="com.itheima.Order"/>
set>
column属性就是指定用哪个列(外键)去查找对应的表。class配置的是要查找的表的完全限定名称
<many-to-onename="customer"class="com.itheima.Customer"column="cid">many-to-one>
Ø Customer.hbm.xml
DOCTYPEhibernate-mappingPUBLIC
"-//Hibernate/HibernateMapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.itheima.Customer"table="t_d2h02_customer">
<id name="id">
<generator class="identity">generator>
id>
<property name="name"length="20">property>
<property name="address"length="50">property>
<set name="orders">
<key column="cid">key>
<one-to-many class="com.itheima.Order"/>
set>
class>
hibernate-mapping>
Ø Order.hbm.xml
DOCTYPEhibernate-mappingPUBLIC
"-//Hibernate/HibernateMapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.itheima.Order"table="t_d2h02_order">
<id name="id"length="32">
<generator class="uuid">generator>
id>
<property name="createTime"type="date">property>
<many-to-one name="customer"class="com.itheima.Customer"column="cid">many-to-one>
class>
hibernate-mapping>
Ø 在hibernate.cfg.xml中导入映射文件
<mapping resource="com/itheima/Customer.hbm.xml"/>
<mappingresource="com/itheima/Order.hbm.xml"/>
Ø 保存测试代码
@Test
publicvoid test02() {
Customer cstm = new Customer();
cstm.setName("李三思");
cstm.setAddress("上海");
Order order1 = new Order();
order1.setCreateTime(new Date());
order1.setCustomer(cstm);
Order order2 = new Order();
order2.setCreateTime(new Date());
order2.setCustomer(cstm);
cstm.getOrders().add(order1);
cstm.getOrders().add(order2);
Session session = HibernateUtils.getSession();
session.beginTransaction();
session.save(order1);
session.save(order2);
session.save(cstm);
session.getTransaction().commit();
session.close();
HibernateUtils.close();
}
Ø Hibernate执行的SQL语句
Hibernate:
insert
into
t_d2h02_order
(createTime, cid, id)
values
(?, ?, ?)
Hibernate:
insert
into
t_d2h02_order
(createTime, cid, id)
values
(?, ?, ?)
Hibernate:
insert
into
t_d2h02_customer
(name, address)
values
(?, ?)
Hibernate:
update
t_d2h02_order
set
createTime=?,
cid=?
where
id=?
Hibernate:
update
t_d2h02_order
set
createTime=?,
cid=?
where
id=?
Hibernate:
update
t_d2h02_order
set
cid=?
where
id=?
Hibernate:
update
t_d2h02_order
set
cid=?
where
id=?
在保存一个实体对象时,如果这个实体对象关联了另一个实体对象且这个实体对象是一个瞬时态的,配置级联保存后,它也会同时将这个瞬时态的实体对象保存到数据库中。
如果这个实体对象是持久态的,这时会发出一个update语句来更新外键(cid)。
如果这个实体对象是一个脱管态的,且这个脱管态的实体对象的OID是不存在的,Hibernate会直接抛出异常。
Ø 映射文件配置
DOCTYPEhibernate-mappingPUBLIC
"-//Hibernate/HibernateMapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.itheima.Order"table="t_d2h02_order">
<id name="id"length="32">
<generator class="uuid">generator>
id>
<property name="createTime"type="date">property>
<many-to-one name="customer"class="com.itheima.Customer"column="cid"cascade="save-update">many-to-one>
class>
hibernate-mapping>
Ø 级联保存代码
@Test
publicvoid test03() {
Customer cstm = new Customer();
cstm.setName("李三思");
cstm.setAddress("上海");
Order order1 = new Order();
order1.setCreateTime(new Date());
order1.setCustomer(cstm);
Order order2 = new Order();
order2.setCreateTime(new Date());
order2.setCustomer(cstm);
Session session = HibernateUtils.getSession();
session.beginTransaction();
// 建立关联关系,如果没有建立关联关系,及时配置了级联保存,Hibernate也是不会自动保存Customer的
order1.setCustomer(cstm);
order2.setCustomer(cstm);
// 因为配置了级联保存,Hibernate会自动执行一条Insert语句来保存Customer
session.save(order1);
session.save(order2);
session.getTransaction().commit();
session.close();
HibernateUtils.close();
}
Ø Hibernate执行的SQL语句
Hibernate:
insert
into
t_d2h02_customer
(name, address)
values
(?, ?)
Hibernate:
insert
into
t_d2h02_order
(createTime, cid, id)
values
(?, ?, ?)
Hibernate:
insert
into
t_d2h02_order
(createTime, cid, id)
values
(?, ?, ?)
在保存实体的时候,尽量避免建立双方双向关联映射。
Customer cstm = new Customer();
Order order1 = new Order();
Order order2 = new Order();
// 这里已经建立order与custoer的关联
order1.setCustomer(cstm);
order2.setCustomer(cstm);
// 这里的代码其实是多余的,开发中要尽量避免
cstm.getOrders().addOrder(order1);
cstm.getOrders().addOrder(order2);
Ø inverse
order.setCustomer //在建立order与customer的关联关系,数据库中是通过外键来建立关联。
如果Inverse为false的话,它会执行一个update语句来维护数据库的外键关联关系。
如果inverse为true的话,它会放弃对外键的维护。也就是说它不再会发起update语句。
Ø Customer.hbm.xml
配置inverse=true,表示外键交给另一方维护(也就是说保存/更新Customer时,Hiberante不再发出Update语句去更新外键)
DOCTYPEhibernate-mappingPUBLIC
"-//Hibernate/HibernateMapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.itheima.Customer"table="t_d2h02_customer">
<id name="id">
<generator class="identity">generator>
id>
<property name="name"length="20">property>
<property name="address"length="50">property>
<set name="orders"cascade="save-update"inverse="true">
<key column="cid">key>
<one-to-many class="com.itheima.Order"/>
set>
class>
hibernate-mapping>
删除一个实体对象时,会将它所关联的对象也一并删除。
cascade=”delete”
none |
默认值。不使用级联操作 |
save-update |
save update或save-update完成操作,级联保存临时对象,如果是游离对象,会执行update |
delete |
级联删除 |
delete-orphan |
删除与当前对象解除关系的对象 |
all |
save-update delete操作 |
all-delete-orphan |
delete-orphan与all操作 |
Ø 创建一个Customer、Order,建立Customer与Order的一对多关联关系
Ø 编写代码完成双向关联
Ø 编写代码完成级联保存
Ø 编写代码完成级联删除
Ø 使用注解完成PO类的编写
Ø 使用注解完成关联映射
Ø 掌握HQL、QBC、本地SQL检索数据
@Entity:声明一个实体
@Table:配置指定映射的表名
@Id:唯一主键ID
@GenerateValue:主键生成策略
@Column:配置属性与列的映射
@Temporal:配置日期格式(DATE、TIME、TIMESTAMP)
@Entity
@Table(name ="t_d3h01_book")
publicclass Book {
@Id
@GeneratedValue(strategy =GenerationType.IDENTITY)
private Integerid;
private Stringname;
@Temporal(TemporalType.DATE)
private DatepublicDate;
@Column(precision = 20,scale = 2)
privateDoubleprice;
public Integer getId() {
returnid;
}
publicvoid setId(Integerid) {
this.id =id;
}
public String getName() {
returnname;
}
publicvoid setName(Stringname) {
this.name =name;
}
public Date getPublicDate() {
returnpublicDate;
}
publicvoid setPublicDate(DatepublicDate) {
this.publicDate =publicDate;
}
public Double getPrice() {
returnprice;
}
publicvoid setPrice(Doubleprice) {
this.price =price;
}
}
Ø 使用注解的方式来配置UUID的生成策略,需要先使用@GenericGenerator定义一个UUID的生成器,然后使用@GeneratedValue来引用它
@Entity
@Table(name="t_man")
publicclass Man {
@Id
@GenericGenerator(name="sysuuid", strategy="uuid")
@GeneratedValue(generator="sysuuid")
private Stringid;
@Transient //这个是忽略该属性的注解
private Integerage;
@Type(type="float") //定义数据库中列的类型
private Doublemoney;
}
Ø 在hibernate.cfg.xml文件里面添加
@OneToMany
@ManyToOne
targetEntity:配置要关联的实体类名。它可以省略。
mappedBy:和inverse很像。其实就是表示外键由另外一方来维护。这个mappedBy是配置的关联类的哪一个属性来维护外键。所以这个Customer中的,@OneToMany的mapperBy属性配置的是Order类中的customer。
@Cascade:这个是使用的是Hibernate中的注解,所以我们需要引入Hibernate中的数据类型。
在多的一方,有一个@JoinColumn,它主要就是配置关联的外键,所以它的值配置为外键的名词。
Ø Customer
@Entity
@Table(name ="t_d3h01_customer")
publicclass Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integerid;
private Stringname;
@OneToMany(mappedBy="customer")
privateSet
public Integer getId() {
returnid;
}
publicvoid setId(Integerid) {
this.id =id;
}
public String getName() {
returnname;
}
publicvoid setName(Stringname) {
this.name =name;
}
}
Ø Order
@Entity
@Table(name="t_d3h01_order")
publicclass Order {
@Id
@GenericGenerator(name="sysuuid", strategy="uuid")
@GeneratedValue(generator="sysuuid")
private Stringid;
private Stringname;
@ManyToOne
@JoinColumn(name="cid")
private Customercustomer;
public String getId() {
returnid;
}
publicvoid setId(Stringid) {
this.id =id;
}
public String getName() {
returnname;
}
publicvoid setName(Stringname) {
this.name =name;
}
public Customer getCustomer() {
returncustomer;
}
publicvoid setCustomer(Customercustomer) {
this.customer =customer;
}
}
找谁,怎么找?
@ManyToMany要通过一个中间表(使用@JoinTable来指定中间表的表名)来找。首先找自己,再找别人。
通过配置joinColumn来找到中间表中与StudentID对应的列,再配置inverseJoinColumn来找到中间表中与Teach ID对应的列。
Ø XML中配置多对多映射
DOCTYPEhibernate-mappingPUBLIC
"-//Hibernate/HibernateMapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.itheima.Student"table="t_d3h06_student">
<id name="id">
<generator class="identity">generator>
id>
<property name="name">property>
<set name="teachers"cascade="save-update"table="t_d3h06_std_tchr">
<key column="sid">key>
<many-to-many class="com.itheima.Teacher"column="tid">many-to-many>
set>
class>
hibernate-mapping>
Ø Student
@Entity
@Table(name="t_d3h02_student")
publicclass Student {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integerid;
private Stringname;
@ManyToMany
@Cascade(CascadeType.SAVE_UPDATE)
@JoinTable(name="t_d3h02_std_tchr",
joinColumns=@JoinColumn(name="std_id"),
inverseJoinColumns=@JoinColumn(name="tchr_id"))
private Set
public Integer getId() {
returnid;
}
publicvoid setId(Integerid) {
this.id =id;
}
public String getName() {
returnname;
}
publicvoid setName(Stringname) {
this.name =name;
}
public Set
returnteachers;
}
publicvoid setTeachers(Set
this.teachers =teachers;
}
}
Ø Teacher
@Entity
@Table(name ="t_d3h02_teacher")
publicclass Teacher {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integerid;
private Stringname;
@ManyToMany(mappedBy="teachers")
@Cascade(CascadeType.SAVE_UPDATE)
private Set
public Integer getId() {
returnid;
}
publicvoid setId(Integerid) {
this.id =id;
}
public String getName() {
returnname;
}
publicvoid setName(Stringname) {
this.name =name;
}
public Set
returnstudents;
}
publicvoid setStudents(Set
this.students =students;
}
}
注意:要谨慎配置双方的级联删除。
在实际项目开发过程中,要谨慎的去使用删除数据功能。会将删除功能实现为隐藏,添加一个表示状态的字段。删除只是在前端不展示这个数据,数据库中并不直接将数据删除。
@Test
publicvoid test01() {
Session s = HibernateUtils.openSession();
s.beginTransaction();
Student stu1 = new Student();
stu1.setName("四丢等特1");
Student stu2 = new Student();
stu2.setName("四丢等特2");
Teacher tchr1 = new Teacher();
tchr1.setName("提却1");
Teacher tchr2 = new Teacher();
tchr2.setName("提却2");
stu1.getTeachers().add(tchr1);
stu1.getTeachers().add(tchr2);
stu2.getTeachers().add(tchr1);
s.save(stu1);
s.save(stu2);
s.getTransaction().commit();
s.close();
HibernateUtils.close();
}
Ø IdCard
@Entity
@Table(name="t_d3h03_idcard")
publicclass IdCard {
@Id
@GenericGenerator(strategy="uuid", name="sysuuid")
@GeneratedValue(generator="sysuuid")
private Stringid;
@OneToOne
@Cascade(CascadeType.ALL)
@JoinColumn(name="ic_Id")
private Personperson;
public Person getPerson() {
returnperson;
}
publicvoid setPerson(Personperson) {
this.person =person;
}
public String getId() {
returnid;
}
publicvoid setId(Stringid) {
this.id =id;
}
}
Ø Person
@Entity
@Table(name ="t_d3h03_person")
publicclass Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integerid;
private Stringname;
private Datebirthday;
@OneToOne(mappedBy="person")
@Cascade(CascadeType.ALL)
private IdCardidCard;
public IdCard getIdCard() {
returnidCard;
}
publicvoid setIdCard(IdCardidCard) {
this.idCard =idCard;
}
public Integer getId() {
returnid;
}
publicvoid setId(Integerid) {
this.id =id;
}
public String getName() {
returnname;
}
publicvoid setName(Stringname) {
this.name =name;
}
public Date getBirthday() {
returnbirthday;
}
publicvoid setBirthday(Datebirthday) {
this.birthday =birthday;
}
}
@Test
publicvoid test01() {
Session s = HibernateUtils.openSession();
s.beginTransaction();
Person p = new Person();
p.setName("配神");
p.setBirthday(new Date());
IdCard idCard = new IdCard();
idCard.setPerson(p);
p.setIdCard(idCard);
s.save(p);
s.getTransaction().commit();
s.close();
HibernateUtils.close();
}
Ø Husband
@Entity
@Table(name="t_d3h04_husband")
publicclass Husband {
@Id
@GenericGenerator(strategy="uuid", name="sysuuid")
@GeneratedValue(generator="sysuuid")
private Stringid;
private Stringname;
@OneToOne
@PrimaryKeyJoinColumn//这个注解表示使用主键映射
@Cascade(CascadeType.ALL)
private Wifewife;
public Wife getWife() {
returnwife;
}
publicvoid setWife(Wifewife) {
this.wife =wife;
}
public String getName() {
returnname;
}
publicvoid setName(Stringname) {
this.name =name;
}
public String getId() {
returnid;
}
publicvoid setId(Stringid) {
this.id =id;
}
}
Ø Wife
@Entity
@Table(name ="t_d3h04_wife")
publicclass Wife {
@Id
// 这个生成策略表示去参照另一方的主键来生成
@GenericGenerator(name="fk", strategy="foreign", parameters={@Parameter(name="property", value="husband")})
@GeneratedValue(generator="fk")
private Stringid;
private Stringname;
@OneToOne
@PrimaryKeyJoinColumn
@Cascade(CascadeType.ALL)
private Husbandhusband;
public Husband getHusband() {
returnhusband;
}
publicvoid setHusband(Husbandhusband) {
this.husband =husband;
}
public String getId() {
returnid;
}
publicvoid setId(Stringid) {
this.id =id;
}
public String getName() {
returnname;
}
publicvoid setName(Stringname) {
this.name =name;
}
}
对象导航:只要建立了实体与实体的关联关系,就可以使用实体的get方法去获取其他对象
OID:get/load去加载实体获取对象
HQL:Hibernate中提供的面向对象的查询语言
SQL:createSqlQuery去执行本地的SQL语句
QBC:主要是通过Criteria(条件)来进行查询,不需要写SQL语句,直接通过Criteria中封装的条件来进行查询
new Configuration().configure();
config.buildSessionFactory();
sessionFactory.openSession();
session.beginTransaction();
Query query = session.createQuery(“FROMCustomer”);
query.list()/query.uniqueResult()
session.getTransacction().commit();
session.close()
sessionFactory.close();
注意:在HQL里面要使用实体对象的名称,而不能使用表名。
@Test
publicvoid test01() {
Session s = HibernateUtils.openSession();
s.beginTransaction();
String hql = "FROMCustomer";
Query q = s.createQuery(hql);
System.out.println(q.list());
System.out.println(((Customer)q.list().get(0)).getOrders());
s.getTransaction().commit();
s.close();
}
Ø 编写代码的时候要注意代码的格式:
静态测试工具(扫描代码格式、统计代码复杂度)
缩进,使用TAB键来进行缩进(往前缩进SHIFT+TAB),保持代码的层次感
回车换行:要保持代码的逻辑层次,用回车来分层次
一行最好不要超过200个字符
《写给大家看的设计书》——对比、重复、对齐
注意:如果没有使用别名,直接写字段的名字进行排序。
/**
* 排序检索
*/
@Test
publicvoid test02() {
Session s = HibernateUtils.openSession();
s.beginTransaction();
String hql = "FROMCustomer c ORDER BY c.name";
Query q = s.createQuery(hql);
System.out.println(q.list());
s.getTransaction().commit();
s.close();
}
Ø 学会分解,从编写短小的子程序(方法)开始
可以使用Xmind或者其他的思维导图工具来将一个复杂问题分解成若干个简单的问题。
public String A功能(){
步骤A()
步骤B()
}
publicvoid步骤B(){
步骤B1()
步骤B2()
步骤B3()
}
publicvoid步骤B1(){
步骤B11()
...
}
注意:位置参数是从0开始的。
/**
* 条件查询(位置参数)
*/
@Test
publicvoid test03() {
Session s = HibernateUtils.openSession();
s.beginTransaction();
String hql = "FROM Customer c WHERE c.id = ?";
Query q = s.createQuery(hql).setInteger(0,1);
System.out.println(q.list());
System.out.println(((Customer)q.list().get(0)).getOrders());
s.getTransaction().commit();
s.close();
}
/**
* 条件查询(命名参数)
*/
@Test
publicvoid test04() {
Session s = HibernateUtils.openSession();
s.beginTransaction();
String hql = "FROM Customer c WHERE c.id = :id";
Query q = s.createQuery(hql).setInteger("id", 1);
System.out.println(q.list());
System.out.println(((Customer)q.list().get(0)).getOrders());
s.getTransaction().commit();
s.close();
}
Ø 尽量不要写过长的方法(<200)
研究发现,方法的长度与错误量成反比
复杂度高,维护成本高
可读性低
setFirstResult:是从第几条开始查起((页数 – 1) * 每页显示多少条)
setMaxResult:查询几条(每页查询多少条数据)
/**
* 分页检索
*/
@Test
publicvoid test05() {
Session s = HibernateUtils.openSession();
s.beginTransaction();
String hql = "FROM Order o ORDER BY id";
Query q = s.createQuery(hql).setFirstResult(0).setMaxResults(3);
System.out.println(q.list());
s.getTransaction().commit();
s.close();
}
//在编写代码的早期就尽量减少错误,不要等到把代码全都写完再来测试
//养成编写测试用例的好习惯
回归测试
例如:写完Service,可以去创建一个测试用例来测试Service里面的方法
group by name1,name2,根据哪些字段来进行分组
聚合函数(avg、sum、count)
注意:group by 后边的字段要写成实体中的属性名称,不要写成表的列名。
/**
* 分组统计检索
* 1)分组统计
*/
@Test
publicvoid test061() {
Session s = HibernateUtils.openSession();
s.beginTransaction();
String hql = "SELECTSUM(o.price), o.customer FROM Order o GROUP BY o.customer";
Query q = s.createQuery(hql);
for(Objecto :q.list()) {
for(Objecto1 : (Object[])o) {
System.out.print(o1 +" | ");
}
System.out.println();
}
s.getTransaction().commit();
s.close();
}
在HQL中使用SELECT new com.itheima.Order(o.name,o.price) FROM Order o进行封装,需要提供对应参数的构造方法,同时不要忘了去实现一个默认的构造器。
/**
* 投影查询
*/
@Test
publicvoid test07() {
Session s = HibernateUtils.openSession();
s.beginTransaction();
String hql = "SELECT new com.itheima.Order(o.name,o.price) FROMOrder o";
Query q = s.createQuery(hql);
List
System.out.println(orders);
s.getTransaction().commit();
s.close();
}
取名字很重要,特别是数据库表的名称、实体的名称
尽量取一些容易记忆、不要太长、太复杂的名字
保持名字一致(Java代码、Javascript代码、HTML命名等)
如果是做企业(特定行业)开发,有一些术语:中文拼写比英文更容易记忆、表达
当在开发过程中,如果写了很多重复的SQL,就可以考虑将这些重复的SQL放在注解(或者XML映射文件)中。
query.setEntity——可以传入一个对象的参数。
Ø 在实体类上添加
@NamedQuery(name="q2", query="FROM Customer ORDER BY id ASC")
* 命名查询1
*/
@Test
publicvoid test08() {
Session s = HibernateUtils.openSession();
s.beginTransaction();
Query q = s.getNamedQuery("q2");
System.out.println(q.list());
s.getTransaction().commit();
s.close();
}
/**
* 基本检索
*/
@Test
publicvoid test01() {
Session s =HibernateUtils.openSession();
s.beginTransaction();
Criteria c = s.createCriteria(Customer.class);
System.out.println(c.list());
s.getTransaction().commit();
s.close();
}
Ø 表驱动编程法(Table-Driven)
if(param==1){
month="一月";
}
elseif(flag==2){
month="二月";
}
elseif(flag==3){
month="三月";
}
elseif(flag==4){
month="四月";
}
elseif(flag==5){
month="五月";
}
else...
String[] monthTable={"一月","二月","三月","四月","五月"...};
month = monthTable[param];
Map<String, String> monthMap =new HashMap<String, String>();
monthMap.put("1","一月");
monthMap.put("2","二月");
monthMap.put("3","三月");
Map<String, String> monthMap =new HashMap<String, String>();
monthMap.put("1","method1");
monthMap.put("2","method2");
monthMap.put("3","method3");
month = monthMap.get(param);
Method m = object.getClass().getMethod(monthMap[param], Object.class);
m.invoke(object,"参数");
/**
* 排序检索
*/
@Test
publicvoid test02() {
Session s = HibernateUtils.openSession();
s.beginTransaction();
Criteria c = s.createCriteria(Customer.class);
c.addOrder(Order.desc("id"));
System.out.println(c.list());
s.getTransaction().commit();
s.close();
}
Ø 高内聚、低耦合
单一职责(少管闲事),一个类只做自己相关的事
OrderService:编写的都是与订单相关的代码(方法)
CustomerService:编写的都是与客户相关的代码(方法)
查询条件:Restrictions.eq(实体属性的名称,值)
逻辑运算条件:Restrictions.or/and
/**
* 条件检索
*/
@Test
publicvoid test03() {
Session s = HibernateUtils.openSession();
s.beginTransaction();
Criteria c = s.createCriteria(Customer.class);
c.add(Restrictions.eq("name","卡斯特么2"));
System.out.println(c.list());
s.getTransaction().commit();
s.close();
}
/**
* 分页检索
*/
@Test
publicvoid test04() {
Session s = HibernateUtils.openSession();
s.beginTransaction();
Criteria c = s.createCriteria(Order.class);
c.setFirstResult(0).setMaxResults(3);
System.out.println(c.list());
s.getTransaction().commit();
s.close();
}
/**
* 统计检索
*/
@Test
publicvoid test05() {
Session s = HibernateUtils.openSession();
s.beginTransaction();
Criteria c = s.createCriteria(com.itheima.Order.class);
ProjectionList plist = Projections.projectionList();
// 类似于添加聚合函数
plist.add(Projections.sum("price"));
// 类似于配置group by 的属性
plist.add(Projections.groupProperty("customer"));
c.setProjection(plist);
for(Objectrow :c.list()) {
for(Objectval : (Object[])row) {
System.out.print(val);
}
System.out.println();
}
s.getTransaction().commit();
s.close();
}
可以在没有Session的情况下去创建一个DetachedCriteria(用法与Criteria一样),例如:可以在web层去拼接一个DC,然后传递到DAO层来去使用。执行查询的时候,还是需要一个Session。
/**
* 统计检索
*/
@Test
publicvoid test05() {
Session s = HibernateUtils.openSession();
s.beginTransaction();
Criteria c = s.createCriteria(com.itheima.Order.class);
ProjectionList plist = Projections.projectionList();
plist.add(Projections.sum("price"));
plist.add(Projections.groupProperty("customer"));
c.setProjection(plist);
for(Objectrow :c.list()) {
for(Objectval : (Object[])row) {
System.out.print(val);
}
System.out.println();
}
s.getTransaction().commit();
s.close();
}
/**
* SQL查询数据
*/
@Test
publicvoid test01() {
Session s = HibernateUtils.openSession();
s.beginTransaction();
String sql = "SELECT t1.id, t1.name, t1.address FROMt_d3h05_customer t1 "
+"LEFT JOIN t_d3h05_order t2 ON t1.id = t2.cid";
Query q = s.createSQLQuery(sql).addEntity(Customer.class);
System.out.println(q.list());
s.getTransaction().commit();
s.close();
}
@NamedNativeQuery(name="q4",
query="SELECT t1.id, t1.name, t1.address FROM t_d3h05_customer t1 "
+ "LEFT JOIN t_d3h05_order t2 ON t1.id = t2.cid",
resultClass=Customer.class)
/**
* 命名SQL查询数据
*/
@Test
publicvoid test02() {
Session s = HibernateUtils.openSession();
s.beginTransaction();
Query q = s.getNamedQuery("q4");
System.out.println(q.list());
s.getTransaction().commit();
s.close();
}
Ø 基于注解完成客户与订单的一对多映射,并编写测试代码
n 练习HQL方式检索(基本检索、排序检索、条件检索、分页检索、分组统计)
n 练习QBC方式检索(基本检索、排序检索、条件检索、分页检索、分组统计)
n 练习本地SQL方式检索
Ø 基于注解完成学生与老师的多对多映射,并编写测试代码
Ø 基于注解完成一对一的外键映射(Husband、Wife)
Ø 掌握使用HQL完成多表检索操作
Ø 理解注解中fetch与lazy的配置
重点要掌握:左外连接
-- 内连接
SELECT*FROM t_customer t1INNERJOIN t_order t2ON t1.`id`= t2.`customer_id`
-- 隐式内连接
SELECT*FROM t_customer t1, t_order t2 WHERE t1.`id`= t2.`customer_id`
-- 左外连接
SELECT*FROM t_customer t1LEFTJOIN t_order t2ON t1.`id`= t2.`customer_id`;
SELECT*FROM a
LEFTJOIN bON a.`C`= b.`c`
LEFTJOIN dON d.`c`= b.`c`;
SELECT*FROM
((SELECT a.`A1`AS a1, a.`C`AS ac, b.`b1`AS b1, b.`c`AS bcFROM a
LEFTJOIN b
ON a.`C`= b.`c`)AS a_join_b
LEFTJOIN dON a_join_b.ac= d.`c`)
任何的表连接后,生成的中间结果也是一张表。
Ø 内连接
显示内连接
隐式内连接
迫切内连接
Ø 外连接
左外连接
迫切外连接
右外连接
使用with来进行关联条件的编写
注意:HQL中不能够出现表名,它是以对象方式来操作的。查询结果是一个Object[]
HQL:FROM Order o INNER JOIN o.customer
Order o:相当于取一个别名
o.customer:Order对象中的customer属性
/**
* HQL内连接
*/
@Test
publicvoidtest01() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
Query query = session.createQuery("FROM Order o INNER JOINo.customer");
System.out.println(query.list());
session.getTransaction().commit();
session.close();
}
/**
* 隐式内连接
*/
@Test
publicvoidtest02() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
Query query = session.createQuery("FROM Order o WHERE o.customer.id= 1");
System.out.println(query.list());
session.getTransaction().commit();
session.close();
}
迫切内连接:相当于Hibearnte会发出一条SELECT语句将映射的实体所有的属性一次性全部查出来,封装到实体中。
/**
* 迫切内连接
*/
@Test
publicvoid test03() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
Query query = session.createQuery("FROM Order o INNER JOINFETCH o.customer");
System.out.println(query.list());
session.getTransaction().commit();
session.close();
}
注意:使用迫切左外连接时,如果需要指定条件进行查询时,使用的是where,而不是with。
/**
* 左外连接
*/
@Test
publicvoidtest04() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
Query query = session.createQuery("FROM Order o LEFT JOINo.customer");
System.out.println(query.list());
session.getTransaction().commit();
session.close();
}
/**
* 迫切左外连接
*/
@Test
publicvoidtest05() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
Query query = session.createQuery("FROM Order o LEFT JOIN FETCHo.customer");
System.out.println(query.list());
session.getTransaction().commit();
session.close();
}
Ø 事务
一组业务操作(例如:转账——从某个账户转出,再转入到另一个账户),它组合和若干数据库操作。这些操作要么全部成功,要么全部失败。
Ø 事务的特性
原子性:事务是不可分割的
一致性:事务在执行前后,保证数据是一致的。
我们开启了12:00一个事务,在事务中执行了一条SELECT语句,查询时间超过10分钟。这10分钟之外,其他的连接或者事务又插入一些数据、更改了一些数据。它SELECT出来的数据是12:00时的数据。
隔离性:事务与事务之间不能互相干扰
持久性:事务结束,能够将数据保存到数据库中
Ø 不考虑事务的隔离性,会产生的问题
脏读:一个事务读取到另一个事务未提交的数据
不可重复读:一个事务读取到另一个事务提交的数据
虚读(幻读):一个事务读取到另一个事务提交的数据
Ø 配置数据库事务的隔离级别
READ_UNCOMMITED:读取未提交,会引发所有的隔离问题
READ_COMMITED:读取已提交,解决脏读问题
REPEATABLE_READ:解决脏读、不可重复读
SERIALIZABLE:串行化。解决所有事务隔离问题
hibernate.connection.isolation
它可取的值有 1 2 4 8
ž 1代表的事务隔离级别为READ UNCOMMITTED
ž 2代表的事务隔离级别为READ COMMITTED
ž 4.代表的事务隔离级别为 REPEATABLE READ
ž 8代表的事务隔离级别为 SERIALIZABLE
注意:Hiberante中的配置属性不能加额外的空格,否则Hiberante会报一些异常。
<propertyname="hibernate.connection.isolation">4property>
<propertyname="hibernate.current_session_context_class">threadproperty>
使用sessionFactory.getCurrentSession()获取Session,session不需要close
使用绑定参数的原因是让数据库一次解析SQL,对后续的重复请求可以使用用生成好的执行计划,这样做节省CPU时间和内存。
避免SQL注入
如果where子句中包含not关键字,那么执行时该字段的索引失效。
Having在检索出所有记录后才对结果集进行过滤,这个处理需要一定的开销,而where子句限制记录的数目,能减少这方面的开销
在含有子查询的HQL中,尽量减少对表的查询,降低开销
当在HQL语句中连接多个表时,使用别名,提高程序阅读性,并把别名前缀与每个列上,这样一来,可以减少解析时间并减少列歧义引起的语法错误。
在hibernate3以后支持hql的update与delete操作
Ø 批量update
/**
* 测试批量更新
*/
@Test
publicvoid test01() {
SessionFactory sessionFactory =newConfiguration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
Query query = session.createQuery("update Customer c set c.name = '我爱你中国' where c.name like '%1%'");
query.executeUpdate();
session.getTransaction().commit();
session.close();
sessionFactory.close();
}
Hiberntae执行的SQL
update
t_d4h08_customer
set
name='我爱你中国'
where
name like '%1%'
Ø 批量delete
/**
* 测试批量删除
*/
@Test
publicvoid test02() {
SessionFactory sessionFactory =newConfiguration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
Query query = session.createQuery("delete Customer c where c.namelike '%1%'");
query.executeUpdate();
session.getTransaction().commit();
session.close();
sessionFactory.close();
}
Hibernate:
delete
from
t_d4h08_customer
where
name like '%1%'
@Test
publicvoid test01() {
SessionFactory sessionFactory =newConfiguration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
for(inti = 0;i < 100000; ++i) {
Customer customer = new Customer();
customer.setName("测试" +i);
session.save(customer);
// 插入大量数据时,可以清理下缓存
if(i % 500 == 0) {
session.clear();
}
}
session.getTransaction().commit();
session.close();
sessionFactory.close();
}
Ø 类级别检索
get/load去检索数据
@Entity
@Table(name ="t_d4h09_customer")
@Proxy(lazy=false)
publicclassCustomer
@Test
publicvoid test02() {
SessionFactory sessionFactory =newConfiguration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
Customer customer =session.load(Customer.class, 1);
session.getTransaction().commit();
session.close();
sessionFactory.close();
}
Hibernate:
select
customer0_.id as id1_0_0_,
customer0_.name as name2_0_0_
from
t_d4h09_customer customer0_
where
customer0_.id=?
Ø 关联级别检索
通过对象导航去获取关联的属性
org.hibernate.LazyInitializationException:could not initialize proxy - no Session
atorg.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:148)
atorg.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:266)
atorg.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:68)
atcn.itheima.domain.Customer_$$_jvst757_1.toString(Customer_$$_jvst757_1.java)
at java.lang.String.valueOf(UnknownSource)
at java.io.PrintStream.println(UnknownSource)
atcn.itheima.test.HibernateTest.test01(HibernateTest.java:45)
atsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(UnknownSource)
atsun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
atjava.lang.reflect.Method.invoke(Unknown Source)
atorg.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
atorg.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
atorg.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
atorg.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
atorg.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
atorg.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
atorg.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
atorg.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
atorg.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
atorg.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
atorg.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
atorg.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
atorg.junit.runners.ParentRunner.run(ParentRunner.java:309)
atorg.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
/**
* 解决延迟加载Session关闭问题
*/
@Test
publicvoid test01() {
SessionFactory sessionFactory =newConfiguration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
Customer customer = session.load(Customer.class, 1);
// 注意:Hibernate.initialize方法调用要放在session.close之前
Hibernate.initialize(customer);
session.getTransaction().commit();
session.close();
System.out.println(customer);
sessionFactory.close();
}
Customer {
Set
}
Ø fetch:定义如何去查询关联的数据
通过Customer去查询订单时,有多种查询方式,使用SELECT、SUBSELECT(子查询)、JOIN(表连接去查询)
Customer cstm =get(Customer.class, 1)
cstm.getOrders();
Ø lazy:配置是否使用延迟加载
使用get方法或者load方法获取Customer时,是否使用延迟加载去加载订单。
Ø 在一方配置抓取策略
@Fetch(FetchMode.SELECT)
@LazyCollection(LazyCollectionOption.TRUE)
Ø 在多方配置抓取策略
@Fetch(FetchMode.SELECT)
@LazyToOne(LazyToOneOption.PROXY)
注意:如果你发现测试的时候,某个配置不起效果,检查一下你是否修改的是正确的Customer文件。因为项目多了,文件多了,名字都一样了。
Ø Fetch为SELECT, LazyCollectionOption.FALSE
@Fetch(FetchMode.SELECT)
@LazyCollection(LazyCollectionOption.TRUE)
执行Customer customer =session.get(Customer.class, 1)时,只会发起SELECT查询Customer,并没有将orders(订单)查询出来
Hibernate:
select
customer0_.id as id1_0_0_,
customer0_.name as name2_0_0_
from
t_d4h09_customer customer0_
where
customer0_.id=?
当执行customer.getOrders().size()时,会发出SELECT将orders查询出来。
Hibernate:
select
orders0_.c_customer_id asc_custom4_1_0_,
orders0_.id as id1_1_0_,
orders0_.id as id1_1_1_,
orders0_.c_customer_id asc_custom4_1_1_,
orders0_.money as money2_1_1_,
orders0_.receiverInfo as receiver3_1_1_
from
t_d4h09_order orders0_
where
orders0_.c_customer_id=?
Ø Fetch为SELECT, LazyCollectionOption.FALSE
@Fetch(FetchMode.SELECT)
@LazyCollection(LazyCollectionOption.FALSE)
执行get时,会直接发出两条SELECT语句将Customer、Order查出
Hibernate:
select
customer0_.id as id1_0_0_,
customer0_.name as name2_0_0_
from
t_d4h09_customer customer0_
where
customer0_.id=?
Hibernate:
select
orders0_.c_customer_id asc_custom4_1_0_,
orders0_.id as id1_1_0_,
orders0_.id as id1_1_1_,
orders0_.c_customer_id asc_custom4_1_1_,
orders0_.money as money2_1_1_,
orders0_.receiverInfo as receiver3_1_1_
from
t_d4h09_order orders0_
where
orders0_.c_customer_id=?
Ø Fetch为SELECT, LazyCollectionOption.EXTRA
@Fetch(FetchMode.SELECT)
@LazyCollection(LazyCollectionOption.EXTRA)
执行
Customer customer = session.get(Customer.class, 1);
System.out.println(customer.getOrders().size());
Hibernate首先发出SELECT语句将Customer查询出来,执行customer.getOrders().size()仍然没有将orders查询出来,而是发一个SELECTCOUNT将orders的总数查询出来
Hibernate:
select
customer0_.id as id1_0_0_,
customer0_.name as name2_0_0_
from
t_d4h09_customer customer0_
where
customer0_.id=?
Hibernate:
select
count(id)
from
t_d4h09_order
where
c_customer_id =?
Ø Fetch为JOIN
当调用get方法时,会发出一条SELECT…LEFT JOIN语句将Customer、orders数据全部查出来。此时懒加载失效
@Fetch(FetchMode.JOIN)
@LazyCollection(LazyCollectionOption.EXTRA)
Hibernate:
select
customer0_.id as id1_0_0_,
customer0_.name as name2_0_0_,
orders1_.c_customer_id asc_custom4_1_1_,
orders1_.id as id1_1_1_,
orders1_.id as id1_1_2_,
orders1_.c_customer_id asc_custom4_1_2_,
orders1_.money as money2_1_2_,
orders1_.receiverInfo as receiver3_1_2_
from
t_d4h09_customer customer0_
left outer join
t_d4h09_order orders1_
oncustomer0_.id=orders1_.c_customer_id
where
customer0_.id=?
Ø Fetch为SUBSELECT,LazyCollectionOption为TRUE
注意:SUBSELECT对单条数据的查询和SELECT效果一样。(数据库中要准备>1条的Customer、Order数据)
@Fetch(FetchMode.SUBSELECT)
@LazyCollection(LazyCollectionOption.TRUE)
当执行下列代码时:
Query query = session.createQuery("FROMCustomer");
List
System.out.println(list.get(0).getOrders().size());
System.out.println(list.get(1).getOrders().size());
Hibernate先发出一条SELECT语句将Customer数据查询出来,然后再发出一条SELECT子查询语句一次将所有orders的数据查询出来
Hibernate:
select
customer0_.id as id1_0_,
customer0_.name as name2_0_
from
t_d4h09_customer customer0_
Hibernate:
select
orders0_.c_customer_id asc_custom4_1_1_,
orders0_.id as id1_1_1_,
orders0_.id as id1_1_0_,
orders0_.c_customer_id asc_custom4_1_0_,
orders0_.money as money2_1_0_,
orders0_.receiverInfo as receiver3_1_0_
from
t_d4h09_order orders0_
where
orders0_.c_customer_id in (
select
customer0_.id
from
t_d4h09_customercustomer0_
)
Ø Fetch为SUBSELECT,LazyCollectionOption为FALSE
@Fetch(FetchMode.SUBSELECT)
@LazyCollection(LazyCollectionOption.FALSE)
执行以下代码时,
Query query = session.createQuery("FROMCustomer");
List
System.out.println(list.get(0).getOrders().size());
System.out.println(list.get(1).getOrders().size());
Hibernate会直接执行发一条SELECT将Customer查询出来,然后再发一条SELECT子查询语句将所有订单数据查询出来(没有懒加载)
Hibernate:
select
customer0_.id as id1_0_,
customer0_.name as name2_0_
from
t_d4h09_customer customer0_
Hibernate:
select
orders0_.c_customer_id asc_custom4_1_1_,
orders0_.id as id1_1_1_,
orders0_.id as id1_1_0_,
orders0_.c_customer_id asc_custom4_1_0_,
orders0_.money as money2_1_0_,
orders0_.receiverInfo as receiver3_1_0_
from
t_d4h09_order orders0_
where
orders0_.c_customer_id in (
select
customer0_.id
from
t_d4h09_customer customer0_
)
Ø Fetch为SUBSELECT,LazyCollectionOption为EXTRA
@Fetch(FetchMode.SUBSELECT)
@LazyCollection(LazyCollectionOption.EXTRA)
执行一下代码时,
Query query = session.createQuery("FROMCustomer");
List
System.out.println(list.get(0).getOrders().size());
System.out.println(list.get(1).getOrders().size());
效果与SELECT一样,也使用使用机器懒惰的方法进行加载
Hibernate:
select
customer0_.id as id1_0_,
customer0_.name as name2_0_
from
t_d4h09_customer customer0_
Hibernate:
select
count(id)
from
t_d4h09_order
where
c_customer_id =?
Hibernate:
select
count(id)
from
t_d4h09_order
where
c_customer_id =?
Ø FetchMode为SELECT,LazyToOneOption.PROXY,Customer上添加@Proxy(lazy=true)默认是为true
@Fetch(FetchMode.SELECT)
@LazyToOne(LazyToOneOption.PROXY)
@Proxy(lazy=true)
publicclassCustomer {…}
执行以下代码时:Orderorder =session.get(Order.class,1);
Hibrenate会执行以下SELECT语句将order数据查出
Hibernate
Hibernate:
select
order0_.id as id1_1_0_,
order0_.c_customer_id asc_custom4_1_0_,
order0_.money as money2_1_0_,
order0_.receiverInfo as receiver3_1_0_
from
t_d4h09_order order0_
where
order0_.id=?
执行到以下代码时: order.getC().getName()时,再发出SELECT语句将Customer查出
Hibernate:
select
customer0_.id as id1_0_0_,
customer0_.name as name2_0_0_
from
t_d4h09_customer customer0_
where
customer0_.id=?
Ø FetchMode为SELECT,Customer上添加@Proxy(lazy=false)
此时,Customer延迟加载失效,执行get(Order.class, 1)时,Hibernate会直接执行SELECT语句将Customer查询出来
Hibernate:
select
order0_.id as id1_1_0_,
order0_.c_customer_id asc_custom4_1_0_,
order0_.money as money2_1_0_,
order0_.receiverInfo as receiver3_1_0_
from
t_d4h09_order order0_
where
order0_.id=?
Hibernate:
select
customer0_.id as id1_0_0_,
customer0_.name as name2_0_0_
from
t_d4h09_customer customer0_
where
customer0_.id=?
Ø FetchMode为SELECT,LazyToOneOption.FALSE
懒加载失效,Hibearnte直接发出两条SELECT将数据查询出来
Hibernate:
select
order0_.id as id1_1_0_,
order0_.c_customer_id asc_custom4_1_0_,
order0_.money as money2_1_0_,
order0_.receiverInfo as receiver3_1_0_
from
t_d4h09_order order0_
where
order0_.id=?
Hibernate:
select
customer0_.id as id1_0_0_,
customer0_.name as name2_0_0_
from
t_d4h09_customer customer0_
where
customer0_.id=?
Ø Fetch为JOIN
@Fetch(FetchMode.JOIN)
@LazyToOne(LazyToOneOption.FALSE)
Hibeante会直接发出SELECT.. LEFT JOIN直接将所有数据查询出来
Hibernate:
select
order0_.id as id1_1_0_,
order0_.c_customer_id asc_custom4_1_0_,
order0_.money as money2_1_0_,
order0_.receiverInfo as receiver3_1_0_,
customer1_.id as id1_0_1_,
customer1_.name as name2_0_1_
from
t_d4h09_order order0_
left outer join
t_d4h09_customer customer1_
onorder0_.c_customer_id=customer1_.id
where
order0_.id=?
N + 1问题:
1 + N,更容易理解
session.createQuery(“from Customer”).list();
首先,Hiberante发出一条SELECT语句将所有的Customer数据查出来
每一次调用customer.get(i).getOrders().size()的时候,都会发出一条SELECT语句去将Customer所对应的Order查出来。
批量抓取
它会一次性的查询出来多个(@BatchSize(n))Customer的订单。
BatchSize都是在主表中设置(主表和子表区分的规则:就是外键在哪一方,哪一方就是子表)
@Entity
@Table(name ="t_d4h09_customer")
@Proxy(lazy=true)
publicclass Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integerid;//主键
private Stringname;// 姓名
@OneToMany(mappedBy ="c")
@Cascade(CascadeType.ALL)
@Fetch(FetchMode.SELECT)
@LazyCollection(LazyCollectionOption.TRUE)
//一次会将size数量的Customer的数据查询出来
@BatchSize(size=2)
private Set
// getter/setter省略
}
Hibernate:
select
customer0_.id as id1_0_,
customer0_.name as name2_0_
from
t_d4h09_customer customer0_
Hibernate:
select
orders0_.c_customer_id asc_custom4_1_1_,
orders0_.id as id1_1_1_,
orders0_.id as id1_1_0_,
orders0_.c_customer_id asc_custom4_1_0_,
orders0_.money as money2_1_0_,
orders0_.receiverInfo as receiver3_1_0_
from
t_d4h09_order orders0_
where
orders0_.c_customer_id in (
?, ?
)
Ø 使用客户与订单练习HQL的连接操作
Ø 使用客户与订单测试延迟加载与抓取策略
Ø 多对多练习(较难)
用户(user):一个用户可以具有多个角色 张三 李四
角色(role):一个角色可以有多个权限 一个角色可以赋予给多个用户simple vip admin
权限(permission):search update delete add
操作:
1. 得到一个用户----根据id获取
2.得到用户的所有角色 List 根据用户去查询角色
3. 得到每一个角色的权限 List 权限角色去查询权限