1.1 hibernate概述
1.1.1 什么是hibernate
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用。
*什么是orm
对象关系映射(英语:Object Relation Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。
对象-关系映射,是随着面向对象的软件开发方法发展而产生的。面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系,而在数据库中,关系数据无法直接表达多对多关联和继承关系。因此,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。
ORM模型的简单性简化了数据库查询过程。使用ORM查询工具,用户可以访问期望数据,而不必理解数据库的底层结构。
1.1.2 运行环境搭建
1. 导入jar包
2. 创建数据库和表
3. 编写核心配置文件(hibernate.cfg.xml)--> 配置获得链接等参数
l 位置:类路径(classpath、src)-->WEB-INF/classes
l 名称:hibernate.cfg.xml
l 内容:
添加约束:
4.编写Javabean和映射文件 hibernate mapping(*.hbm.xml)
l 文件位置:javabean同包
l 文件名称:javabean同名
l 扩展名:类名.hbm.xml
l 内容:
添加约束:
hibernate核心jar包下的org.hibernate包下hibernate-mapping-3.0.dtd文件中查找
publicclass User {
/* * create table t_user( id int auto_increment primary key, username varchar(50), password varchar(30) ); */ private Integer uid; private String username; private String password; |
<!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.a_hello.User" table="t_user"> <!-- 主键 --> <id name="uid"> <!-- 固定值:主键生成策略 --> <generator class="native"></generator> </id>
<!-- 普通属性 --> <property name="username"></property> <property name="password"></property>
</class> </hibernate-mapping>
|
5 使用api测试
1.1.3 hibernate的工作原理
hibernate工作原理:
1、通过Configuration().configure();读取并解析hibernate.cfg.xml配置文件。
2、由hibernate.cfg.xml中的<mappingresource="xx/xx/xxx.hbm.xml"/>读取解析映射信息。
3、通过config.buildSessionFactory();//得到sessionFactory。
4、sessionFactory.openSession();//得到session。
5、session.beginTransaction();//开启事务。
6、persistent operate;
7、session.getTransaction().commit();//提交事务
8、关闭session;
9、关闭sessionFactory;
1.1.4 hibernate的优点
a、Hibernate对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码
b、Hibernate是一个基于jdbc的主流持久化框架,是一个优秀的orm实现,它很大程度的简化了dao层编码工作
c、Hibernate是企业级开发中主流框架。映射的灵活性很出色。它支持很多关系型数据库
1.2 配置文件详解
1.2.1 核心配置文件
1. 可以加载数据库相关信息
2. hibernate相关配置
<!--设置session获取方式为getCurrentSessin-->
<property name=”hibernate.hbm2ddl.auto>update</property>(设置自动更新表)
*方言配置必不可少
* Create-drop 每次都会创建一个新的表,执行完成后删除。一般在测试中使用
Create 每次都会创建一个新的表,一般是在测试中使用
update 如果数据库中有表,不创建,没有表创建,如果映射不匹配,会自动更新表 结构(只能添加)
validate 只会使用存在的表,并且会对映射关系进行校验.
3. 加载映射配置文件
*加载映射配置文件用resource,加载类中注解用class,必不可少
1.2.1 映射配置文件
1. 统一声明包名,这样在<class>中就不需要写类的全名.
2. 关于<class>标签配置
name属性:类的全名称
table 表的名称,可以省略,这时表的名称就与类名一致
catalog属性:数据库名称可以省略.如果省略,参考核心配置文件中url路径中的库名称
3. 关于<id>标签
首先它必须存在。<id>是用于建立类中的属性与表中的主键映射。
name 类中的属性名称
column 表中的主键名称 column它也可以省略,这时列名就与类中属性名称一致
length 字段长度
type属性 指定类型
<generator>它主要是描述主键生成策略.(不可或缺)
4. 关于<property>标签
它是描述类中属性与表中非主键的映射关系
关于hibernate的映射文件中类型问题
对于type属性它的取值,可以有三种:
1. java中的数据类型
2. hibernate中的数据类型
3. SQL的数据类型
默认是hibernate中数据类型
1.3常用API
1.3.1 Configuration
它主要是用于加载hibernate配置.
Configuration config=newConfiguration().config(); 主要加载src下的hibernate.cfg.xml
Configuration config=new Configuration();主要加载的src下的hibernate.properties
Configuration config=newConfiguration().config(核心配置文件名称);加载指定的名称的配置文件
问题:我们是在hibernate.cfg.xml文件中有xxx.hbm.xml文件的位置。如果我们使用的是hibernate.properties这种核心配置,它如何加载映射配置?
1.3.2 sessionFactory
首先SessionFactory它的获取是通过Configuration得到。
SessionFactory接口负责初始化Hibernate。它充当数据存储源的代理,并负责创建Session对象。这里用到了工厂模式。需要注意的是SessionFactory并不是轻量级的,因为一般情况下,一个项目通常只需要一个SessionFactory就够,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。
通过SessionFactory可以得到Session.(测试用)
是从连接池中获取一个连接。(开发用,执行完后不用close())
获取一个与线程绑定的Session.
SessionFactory它不是轻量级的,不要频繁创建关闭它。在一个项目中有一个SessionFactory就可以,通过SessionFactory来获取Session进行操作。
问题:怎样可以保证在一个项目中所使用的SessionFactory是同一个哪?
SessionFactory内部还维护了一个连接池,如果我们要想使用c3p0连接池,应该怎样处理?
1. 我们要导入c3p0的相关jar包
在hibernate/lib/options下有关于c3p0连接池jar包
2. 在hibernate.cfg.xml文件中配置c3p0连接
可以查看etc/hibernate.properties中关于c3p0的配置
1.3.3 Session
Session接口负责执行被持久化对象的CRUD操作(CRUD的任务是完成与数据库的交流,包含了很多常见的SQL语句)。但需要注意的是Session对象是非线程安全的。
问题:我们如何解决session的安全问题?
我们只需要在方法内部来使用Session就可以。
问题:Session如何获取到?
SessionFactory.openSession() ; 相当于直接通过SessionFactory创建一个新的Session,使用完成后要手动调用close来关闭。
SessionFactory.getCurrentSession();获取一个与线程绑定的Session,当我们提交或事务回滚后会自动关闭。
Session常用的方法:
save 保存对象
update修改操作
delete删除
get/load 根据id进行查询(get采用立即获取策略,load采用延迟获取策略)
savenOrUpdate执行save或update操作
createQuery()获取一个Query对象
CreateSQLQUery()获取一个可以操作sql的SQLQuery对象
createCriteria()获取一个Criteria它可以完成条件查询
*saveOrUpdate
如果对象是一个瞬时对象 --------执行save操作
如果对象是一个脱管对象---------执行update
如果是一个持久对象-------直接返回
delete
删除一个脱管对象,与session关联,在删除
注意:如果执行delete操作,先删除一级缓存,再除数据库中的数据。
1.3.4 Transaction
Transaction接口主要用于管理事务,它是hibernate的事务接口,对底层的事务进行了封装。使用它可以进行事务操作。
commit 事务提交
rollback 事务回滚
问题:如果获取一个Transaction对象
Session.beginTransaction();
问题:如果在程序中没有开启事务,是否存在事务?
有事务,session的每一个操作就会开启一个事务。
默认情况下事务是不会自动提交的。
默认不自动提交
事务自动提交.
1.3.5 Query
Query接口让你方便地对数据库及持久对象进行查询,它可以有两种表达方式:HQL语言或本地数据库的SQL语句。Query经常被用来绑定查询参数、限制查询记录数量,并最终执行查询操作。
通过Query主要完成查询操作.
我们通过Query可以执行hql语句.
Query query=Session.createQuery(hql);
下面这个可以执行sql语句
SQLQUery sqlQuery=Session.createSQLQuery(sql);
SQLQuery是Query的子.
查询所有操作---使用HQL
分页查询
查询指定列信息
Select name ,address from Customer; 得到的是List<Object[]>结果
要想得到List<Customer>结果
1. 在Customer类中生成以name,address为参数的构造,注意,无参数构造也要有。
2. Select newCustomer(name,address) from Customer;
条件查询
可以使用where关键字
无名称参数 from Customer where name=?
对其进行赋值 query.setParameter(0,”张三”)(从0开始)
有名称参数 from Customer where name=:myname;
对其进行赋值 query.setParameter(“myname”,”李四”);
如果查询结果可以保证就是唯一 的,我们可以使用
query. uniqueResult()来得到一个单独对象.
1.3.6 SQLQuery
要想执行本地sql
SQLQuerysqlQuery=session.createSqlQuery(String sql);
使用addEntity方法来将结果封装到指定的对象中,如果不封装,得到的是List<Object>
如果sql中有参数,我们使用setParameter方法完成参数传递。
如果结果就是一个可以使用uniqueResult()来得到一个单独对象。
1.3.7 Criteria
Criteria接口与Query接口非常类似,允许创建并执行面向对象的标准化查询。值得注意的是Criteria接口也是轻量级的,它不能在Session之外使用。
首先我想使用Criteria,必须得到Criteria
Criteria criteria=Session.createCriteria()
查询所有操作
Session.createCriteria(实体类.class)得到一个Criteria对象,调用list查询所有
分页操作与query的方法一样
setFirstResult() setMaxResults()
条件查询
criteria.add(Restrictions.eq(“name”,”xxxx”));
criteria.add(Restrictions.or(Restricitons.eq(),Restrictions.list()…..))
1.4 hibernate持久化对象管理
1.4.1 持久化对象的三种状态
1. 瞬时态:也叫做临时态或自由态,它一般指我们new出来的对象,它不存在OID,与hibernate session无关联,在数据库中也无记录。它使用完成后,会被jvm直接回收掉,它只是用于信息携带。
简单说:无OID 与数据库中的信息无关联,不在session管理范围内。
2. 持久态:在hibernate session管理范围内,它具有持久化标识OID它的特点,在事务未提交前一直是持久态,当它发生改变时,hibernate是可以检测到的。
简单说:有OID 由session管理,在数据库中有可能有,也有可有没有。
3. 托管态:也叫做游离态或离线态,它是指持久态对象失去了与session的关联,托管态对象它存在OID,在数据库中有可能存在,也有可能不存在。
对于托管态对象,它发生改变时hibernet不能检测到。
1.4.2 三种状态的关系
1. 瞬时态(new 出来的)
瞬时------à持久 save saveOrUpdate
瞬时-----à脱管(游离) 手动设置oid
2. 持久态 它是由session管理
持久-----à瞬时 删除对象的oid
持久-----à脱管 注意:session它的缓存就是所说的一级缓存
evict(清除一级缓存中指定的一个对象)
clear(清空一级缓存)
close(关闭,清空一级缓存)
3. 脱管态 (它是无法直接获取)
脱管-----à瞬时 直接将oid删除
脱管----à持久 update saveOrUpdate lock(过时)
1.4.3 hibernate一级缓存
Hibernate的一级缓存就是指session缓存。
actionQueue它是一个行列队列,它主要记录crud操作的相关信息
persistenceContext它是持久化上下文,它其实是真正缓存。
在session中定义了一系列的集合来存储数据,它们构成session缓存。
只要session没有关闭,它就会一直存在。
当我们通过hibernate中的session提供的一些API例如 save get update等进行操作时,就会将持久化对象保存到session中,当下一次在去查询缓存中具有的对象(OID值来判断),
就不会去从数据库查询,而是直接从缓存中获取。
Hibernate的一级缓存存在的目的就是为了减少对数据库访问。
在hibernate中还有一个二级缓存,它是SessionFactory级别缓存。
*一级缓存特点
1. 当我们通过session的save,update saveOrupdate进行操作时,如果一级缓存中没有对象,会将这些对象从数据库中查询到,存储到一级缓存。
2. 当我们通过session的load,get,Query的list等方法进行操作时,会先判断一级缓存中是否存在,如果没有才会从数据库获取,并且将查询的数据存储到一级缓存中。
3. 当调用session的close方法时,session缓存清空。
clear 清空一级缓存.
evict 清空一级缓存中指定的一个对象。
refresh重新查询数据库,用数据库中信息来更新一级缓存与快照
1.5 注解开发
1.5.1 PO类注解
@Entity 声明一个实体
@Table来描述类与表对应
@Id来声明一个主键
@GenerateValue 用它来声明一个主键生成策略
默认情况下相当于native
可以选择的主键生成策略AUTO IDENTITY SEQUENCE
@Column来定义列
注意:对于PO类中所有属性,如果你不写注解,默认情况下也会在表中生成对应的列。
列的名称就是属性的名称
@Temporal来声明日期类型
可以选择
TemporalType.DATA 只有年月日
TemporalType.TIME 只有小时分钟秒
TemporalType.TIMESTAMP 有年月日小时分钟秒
我们最终需要在hibernate.cfg.xml文件中将我们类中的注解配置引用生效
问题:1.如果我们主键生成策略想使用UUID类型?
问题2:如果设定类的属性不在表中映射?
1.5.2 数据对象的三种关系介绍
一对一
原则有两种:
1. 唯一外键对应:在任意一方添加外键来描述对应关系(推举)
2. 主键对应:一方的主键作为另一方的主键
Class Employee{
Private Archives archives;
}
Class Archives{
Private Employee employee;
}
一对多(多对一)
客户与订单之间一对多关系(多对一)
建表原则:在多的一方添加外键来描述关联关系
Class Customer{
Private Set<Order> orders = new HashSet<Order>();
}
Class Order{
Private Customer c;
}
多对多
建表原则:通过一张中间表来描述其对应关系
Class Student{
Set<Teacher> ts = new HashSet<Student>();
}
Class Teacher{
Set<Student> ss = new HashSet<Student>();
}
1.5.3 一对一注解
外键映射(推举)
创建实体
User类
mappedBy等同(inverse=“true”),其值为外键名称,宣告本方放弃对外键的维护权利
IDCard类
joinColumn指定外键列名称,当前配置外键是在t_idcard表中
测试代码
主键映射(了解)
以Husband与Wife为例
Wife的主键生成策略是identity
@PrimaryKeyJoinColumn 说明husband与wife是使用主键映射
Husband的主键我们设置成参考wife的主键方式
测试操作
1.5.4 一对多注解
Customer类
targetEntity,其值为对方的类型
Order类
示例:保存客户时,保存订单
对于这个示例我们需要在Customer中配置cascade操作,save-update,来获取关联
第一种方式,可以使用JPA提供的注解
mappedBy宣告本方放弃维护外键c,仅由Order方维护(多的一方维护)
第二种方式:可以使用hibernate提供的注解(推举)
测试代码
扩展:关于hibernate注解@Cascade中的DELETE_ORPHAN过时
使用下面方案来替换过时方案
删除时,关联方案用orphanRemoval=true
1.5.5 多对多
Teacher类中
Student类中
在维护方配置中间表
级联保存操作测试
因为我们将外键的维护权利由Student来维护,我们演示保存学生时,将都也级联保存。
我们在Student类中配置了级联
级联删除操作测试
1.6 hibernate检索方式
1导航对象图检索方式,根据已加载的对象导航到其它对象
2.OID检索方式,按照对象的OID来检索对象
3.HQL检索方式,使用面向对象的HQL查询语言
4.QBC检索方式,使用QBC(Query by Criteria)API来检索对象,这种API封装了基于字符串形式的查询语句,提供了更加面向对象的查询接口
5.本地SQL检索方式,使用本地数据库的SQL查询语句
1.6.1 导航对象图
Customer c=session.get(Customer.class,2);
c.getOrders().size()
通过在hibernate中进行映射关系,在hibernate操作时,可以通过导航方式得到
其关联的持久化对象信息。
1.6.2 OID
Session.get(Customer.class,3);
Session.load(Order.class,1);
Hibernate中通过get/load方法查询指定的对象,要通过OID来查询。
1.6.3 HQL
HQL是我们在hibernate中是常用的一种检索方式。
HQL(Hibernate Query Language)提供更加丰富灵活、更为强大的查询能力
因此Hibernate将HQL查询方式立为官方推荐的标准查询方式,HQL查询在涵盖Criteria查询的所有功能的前提下,提供了类似标准SQL语 句的查询方式,同时也提供了更加面向对象的封装。完整的HQL语句形式如下:Select/update/delete…… from …… where …… group by …… having …… order by ……asc/desc 其中的update/delete为Hibernate3中所新添加的功能,可见HQL查询非常类似于标准SQL查询。
基本步骤:
1. 得到Session
2. 编写HQL语句
3. 通过session.createQuery(hql)创建一个Query对象
4. 为Query对象设置条件参数
5. 执行list查询所有,它反胃的是List集合 uniqueResut()返回一个查询结果。
基本检索:from 类名
排序检索:order by 默认asc升序,desc为降序
条件检索:where 限制参数+条件+条件参数(无名称参数 ?,有名称参数 :name)
分页检索:query.setFirstResult(num)设置开始位置
query.setMaxResult(num)设置条数
分组统计检索: 分组 group by
统计 count max min avg sum
投影检索:形如“selectnew User(id,name) from User”(获取对象的部分属性)
我们必须在PO类中提供对应属性的构造方法,也要有无参数构造。
命名检索
我们可以将hql语句先定义出来,在使用时通过session.getNamedQuery(hqlName);得到一个Query,在执行.
问题:hql定义在什么位置?
1.如果你有hbm配置文件,那么当前的hql操作是对哪一个实体进行操作,就在哪一个 实体的配置文件中声明。
2.如果是使用注解来描述PO的配置
我们直接在PO类中使用
如何使用?
1.6.4 QBC
QBC(query by criteria),它是一种更加面向对象的检索方式。
QBC步骤:
1.通过Session得到一个Criteria对象 session.createCriteria()
2.设定条件 Criterion实例 它的获取可以通过Restrictions类提供静态。
Criteria的add方法用于添加查询条件
3. 调用list进行查询 criterfia.list.
基本检索
排序检索
注意在criteri.addOrder()方法的参数使用的Order是hibernate中的对象
条件检索
分页检索
统计分组检索
Count sum avg max min
离线条件检索
1.6.5 本地sql
本地sql也支持命名查询。
可以将sql语句定义在hbm文件中,也可以使用注解。
本地命名sql注解定义
如果执行这个命名的sql会产生异常
出现问题的原因:是hibernate不知道执行select * from t_customer后如果将结果封装。
2.7 Hibernate优化
2.7.1 HQL优化
1.使用参数绑定
1.使用绑定参数的原因是让数据库一次解析SQL,对后续的重复请求可以使用用生成好的执行计划,这样做节省CPU时间和内存。
2.避免SQL注入
2.尽量少全长NOT
如果where子句中包含not关键字,那么执行时该字段的索引失效。
3.尽量使用where来替换having
Having在检索出所有记录后才对结果集进行过滤,这个处理需要一定的开销,而where子句限制记录的数目,能减少这方面的开销
4.减少对表的查询
在含有子查询的HQL中,尽量减少对表的查询,降低开销
5.使用表的别名
当在HQL语句中连接多个表时,使用别名,提高程序阅读性,并把别名前缀与每个列上,这样一来,可以减少解析时间并减少列歧义引起的语法错误。
6.实体的更新与删除
在hibernate3以后支持hql的update与delete操作
2.7.2 一级缓存管理
一级缓存也叫做session缓存,在一个hibernate session有效,这级缓存的可干预性不强,大多于hibernate自动管理,但它提供清除缓存的方法,这在大批量增加(更新)操作是有效果的,例如,同时增加十万条记录,按常规进行,很可能会出现异常,这时可能需要手动清除一级缓存,session.evict以及session.clear.
2.8 检索策略
2.8.1 检索策略概述
检索策略分为两种:
1. 类级别检索
2. 关联级别检索
类级别检索
类级别检索是通过session直接检索某一类对应的数据,例如
Customerc=session.load(Customer.class,1)
Session.createQuery(“fromOrder”)
类级别检索策略分为立即检索与延迟检索,默认是延迟检索,类级别的检索策略可以通过<class>元素的lazy属性来设置 ,默认值是true
在hbm配置文件中设置
在类中使用注解
如果将lazy设置为false,代表类级别检索也使用立即检索。这时load与get就一样,都是立即检索。
如果对一个延迟代理对象进行初始化?
关联级别检索
查询到某个对象,获得其关联的对象或属性,这种称为关联级别检索,例如
c.getOrders().size()
c.getName()
总结:Fetch主要描述的是SQL语句的格式(例如是多条,子查询,多表联查
Lazy 控制SQL语句何时发送
通常采用延迟加载,需要立即加载时,用join fetch来实现
2.8.2 set上的fetch与lazy
set上的fetch与lazy它主要是用于设置关联的集合信息的抓取策略。
Fetch可取值有:
1. SELECT 多条简单的sql (默认值)
2. JOIN 采用迫切左外连接L
3. lazy可取值有:
SUBSELECT 将生成子查询的SQ
1. TURE 延迟检索 (默认值)
2. FALSE 立即检索
3. EXTRA 加强延迟检索(及其懒惰)
第一种组合
会首先查询客户信息,当需要订单信息时,才会关联查询订单信息。
第二种组合
当查询客户信息时,就会将订单信息也查询,也就是说订单信息没有进行延迟。
第三种组合
当查询客户信息时,不会查询订单信息,当需要订单的个数时,也不会查询订单信息,
只会通过count来统计订单个数。
当我们使用size(),contains()或isEmpty()方法时不会查询订单信息。
第四种组合
如果fetch选择的是join方案,那么lazy它会失效。
生成SQl将采用的是迫切左外连接(left outer join fetch)
会立即查询。
第五种组合
会生成子查询,但是我们在查询订单时采用的是延迟加载。
第六种组合
会生成子查询,在查询客户信息时,就会将订单信息也查询出来
第七种组合
在查询订单时,只会根据情况来确定是否要订单信息,如果不需要,例如我们
程序中size操作,那么就会发出select count(*) from Orderwhere c_customer_id=?
2.8.3 one上的fetch和lazy
<set fetch lazy>它主要是设置在获取到一的一方时,如果去查询多的一方。
在<many-to-one>或<one-to-one>如果去查询对方。
对于程序 就是在多的一方如何查询一的主方信息
例如:获取到一个订单对象,要查询客户信息。
Fetch可取值:
select默认值,代表发送一条或多条简单的select语句
join 发送一条迫切左外连接
lazy可取值
false不采用延迟加载
proxy默认值 是否采用延迟,需要另一方的类级别延迟策略来决定
no-proxy不用研究
第一种组合
注意:Customer的类级别延迟策略
当我们执行时,会首先发送一条sql只查询订单信息,客户信息会延迟,只有真正需要客户信息时,才会发送sql来查询客户信息.
第二种组合
注意:Customer的类级别延迟策略
当查询订单时,就会将客户信息也查询到,原因是Customer它的类级别延迟为false,也就是立即查询。
第三种组合
当查询订单时,不会对客户信息进行延迟,立即查询客户信息
第四种组合
如果fetch值为join,那么lazy失效。
会发送一条迫切左外连接来查询,也就立即查询。
2.8.4 批量抓取
我们在查询多个对象的关联对象时,可以采用批量抓取方式来对程序进行优化.
要想实现批量抓取:
可以在配置文件中batch-size属性来设置
可以使用注解@BatchSize(size=4)
可以采用批量抓取来解决N+1问题.
查询客户,查询订单
可以在客户配置文件中配置batch-size,是在<set>标签上
查询订单,查询客户
订单与客户,客户它是一个主表,订单是一个从表。
在设置批量抓取时都是在主表中设置
在配置文件中在主表的<calss>标签上设置batch-size
在注解使用中
注意:无论是根据哪一方来查询别一方,在进行批量抓取时,都是在父方来设置 ,
如果是要查询子信息,那么我们是在<set>上来设置batch-size,如果是从子方来查询父方,
也是在父方设置在<class>设置batch-size.
父与子区分:
有外键的表是子 ( 从关联方就是父 ( 主 )) 表