黑马程序员技术交流社区
标题: 【石家庄校区】Hibernate总结 [打印本页]
作者: 丶笑笑 时间: 2018-6-27 16:17
标题: 【石家庄校区】Hibernate总结
本帖最后由 小石姐姐 于 2018-6-29 10:50 编辑
【石家庄校区】Hibernate总结
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用`对象编程思维来操纵数据库`。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用。
ORM:
对象关系映射(英语:Object RelationMapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。
对象-关系映射,是随着面向对象的软件开发方法发展而产生的。面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系,而在数据库中,关系数据无法直接表达多对多关联和继承关系。因此,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。
ORM模型的简单性简化了数据库查询过程。使用ORM查询工具,用户可以访问期望数据,而不必理解数据库的底层结构。
Hibernate基本配置:导包+前提:导包:
1.导入lib/required下所有的jar
2.导入数据库的驱动jar包
3.日志相关jar包:
log4j-1.2.16.jar
slf4j-api-1.6.1.jar
slf4j-log4j12-1.7.2.jar
4.拷贝hibernate-release-5.0.7.Final\lib\optional\c3p0下所有jar包
c3p0-0.9.2.1.jar
hibernate-c3p0-5.0.7.Final.jar
mchange-commons-java-0.2.3.4.jar
5.将hibernate-release-5.0.7.Final目录下project/etc/log4j.properties文件拷贝到工程src目录下
前提:
数据库表
实体类
核心jar包:hibernate-core-5.0.7.Final.jar
配置映射文件:映射配置文件主要是用于描述<实体类与数据表>之间的映射关系
1.位置:配置文件和实体类在同一包下
2.名称:类名.hbm.xml
3.约束:hibernate核心jar包下的org.hibernate包下hibernate-mapping-3.0.dtd文件中查找
4.标签:
<hibernate-mapping>(mapping:映射)
<class>
<id></id>
<property></property>
</class>
</hibernate-mapping>
<!-- package属性代表javabean所在的包-->
<hibernate-mapping>
<!--
name 实体类的全名
table 表的名称
catalog 数据库名称
-->
<class name="com.b3a4a.domain.Customer" table="t_customer" catalog="db_hibernate_study">
<!--
id它是用于描述主键
name 实体类中哪个属性对应的是主键
column 数据库表中哪一列是主键
-->
<id name="id" column="id">
<!--主键生成策略 -->
<generator class="native"></generator>
</id>
<!--
使用property来描述属性与字段的对应关系
name 实体类中的属性
column 实体类中属性对应数据库表中的列
length 该列的长度限制
-->
<property name="name" column="name" length="20" type="string"></property>
<property name="address" column="address" length="50"></property>
<property name="sex" column="sex" length="20"></property>
</class>
</hibernate-mapping>
配置核心文件:2.配置核心配置文件
它主要是hibernate框架所使用的,它主要包含了连接数据库相关信息,hibernate相关配置等。
1.位置+名称:在src下创建一个hibernate.cfg.xml
2.约束:约束文件所在位置:hiberante核心jar包下的org.hibernate包下hibernate-configuration-3.0.dtd文件
3.在这个文件中如何配置:
可以参考hibernate-release-5.0.7.Final\project\etc\hibernate.properties文件
<hibernate-configuration>
<session-factory>
<!-- 配置关于数据库连接的四个项 driverClass url username password -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///HibernateTest</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123</property>
<!--设置连接提供者 -->
<property name="hibernate.connection.provider_class">
org.hibernate.connection.C3P0ConnectionProvider
</property>
<!-- c3p0连接池的配置 -->
<property name="hibernate.c3p0.max_size">20</property> <!--最大连接数 -->
<property name="hibernate.c3p0.min_size">5</property> <!--最小连接数 -->
<property name="hibernate.c3p0.timeout">120</property> <!--超时 -->
<property name="hibernate.c3p0.idle_test_period">3000</property> <!--空闲连接 -->
<!-- 可以将向数据库发送的sql显示出来 -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化sql -->
<property name="hibernate.format_sql">true</property>
<!-- hibernate的方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 自动创建表 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 用于设置事务提交方式 -->
<property name="hibernate.connection.autocommit">false</property>
<!-- 设置seesion和线程绑定 需要配合SessionFactory的getCurrentSession()使用 -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 配置hibernate的映射文件所在位置-->
<mapping resource="com/b3a4a/domain/Customer.hbm.xml" />
</session-factory>
</hibernate-configuration>
基本入门操作:@Test
public void modifyCustomerTest() {
// 创建一个Customer,提供数据
Customer c = new Customer();
c.setName("张三");
c.setAddress("北京");
c.setSex("男");
// 使用hibernate的api来完成将customer信息保存到mysql中操作
Configuration config = new Configuration().configure(); // 加载hibernate.cfg.xml
SessionFactory sessionFactory = config.buildSessionFactory();
Session session = sessionFactory.openSession(); // 相当于得到一个Connection。
// 开启事务
Transaction transaction = session.beginTransaction();
//--------------------------操作数据库-----------------------
//-----------添加操作-------------
//session.save(c);
//--------------------------------
//-----------查询操作-------------
//查询一条数据
//get/load
//Customer c =session.load(Customer.class, 1);
//查询多条数据
//Query query =session.createQuery("from Customer"); // 这里的from Customer不是sql语句,是HQL,这里的Customer代表的Customer类
//List<Customer> list= query.list();
//--------------------------------
//-----------修改操作-------------
//Customer c =session.get(Customer.class, 2);
//c.setName("王五");
//session.update(c);
//--------------------------------
//-----------删除操作-------------
//Customer c =session.get(Customer.class, 1);
//session.delete(c);
//--------------------------------
//-----------------------------------------------------------
// 事务提交
//和session.getTransaction().commit();区别?
transaction.commit();
session.close();
sessionFactory.close();
}
Hibernate配置详解:1.核心配置文件 hibernate.cfg.xml
参考hibernate-release-5.0.7.Final\project\etc\hibernate.properties文件
##auto schema export
#hibernate.hbm2ddl.autocreate-drop 每次都会创建一个新的表,执行完成后删除。一般在测试中使用
#hibernate.hbm2ddl.autocreate 每次都会创建一个新的表,一般是在测试中使用
#hibernate.hbm2ddl.autoupdate 如果数据库中有表,不创建,没有表创建,如果映射不匹配,会自动更新表结构(只能添加)
#hibernate.hbm2ddl.autovalidate 只会使用存在的表,并且会对映射关系进行校验.
2.映射配置文件:类名.hbm.xml
2.关于<class>标签配置
name属性:类的全名称
table 表的名称,可以省略,这时表的名称就与类名一致
catalog属性:数据库名称 可以省略.如果省略,参考核心配置文件中url路径中的库名称
3. 关于<id>标签
首先它必须存在,且位于第一个。<id>是用于建立类中的属性与表中的主键映射。
name 类中的属性名称
column 表中的主键名称 column它也可以省略,这时列名就与类中属性名称一致
length 字段长度
type属性 指定类型
<generator>它主要是描述主键生成策略.
4. 关于<property>标签
它是描述类中属性与表中非主键的映射关系
关于hibernate的映射文件中类型问题
对于type属性它的取值,可以有三种(配置时使用Hibernate中的数据类型):
1. java中的数据类型
2. hibernate中的数据类型
3. SQL的数据类型
数据类型:看图
核心API介绍:1.ConfigurationConfiguration config=new Configuration().config(); 主要加载src下的hibernate.cfg.xml(看源码)
Configuration config=new Configuration();主要加载的src下的hibernate.properties
可以手动加载映射配置文件
2.SessionFactorySessionFactory接口负责初始化Hibernate。它充当数据存储源的代理,并负责创建Session对象。这里用到了工厂模式。
需要注意的是SessionFactory并不是轻量级的,因为一般情况下,一个项目通常只需要一个SessionFactory就够,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。
* 问题:怎样可以保证在一个项目中所使用的SessionFactory是同一个哪?public class HibernateUtils{
//一个项目加载一次此class,静态属性跟随class加载而加载,因此sessionFactory在一个项目中为同一个
private static Configuration config;
private static SessionFactorysessionFactory;
static{
config = new Configuration().config();
sessionFactory=config.buildSessionFactory;
}
public static openSession(){
return sessionFactory.openSession();
}
}
* 通过SessionFactory可以获得session:1.SessionFactory.openSession();
线程不安全
2.SessionFactory.getCurrentSession();
获取一个与线程绑定的Session.线程安全
还需要在hibernate.cfg.xml中配置
* SessionFactory内部还维护了一个连接池,如果我们要想使用c3p0连接池,应该怎样处理?1. 我们要导入c3p0的相关jar包
在hibernate/lib/options下有关于c3p0连接池jar包
2. 在hibernate.cfg.xml文件中配置c3p0连接
可以查看etc/hibernate.properties中关于c3p0的配置
3. 配置完成后需要配置连接提供者,配置了以后hibernate才知道使用什么连接池
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进行查询
savenOrUpdate 执行save或update操作
createQuery()获取一个Query对象
CreateSQLQUery()获取一个可以操作sql的SQLQuery对象
createCriteria() 获取一个Criteria它可以完成条件查询
4.TransactionSession.beginTransaction();
Transaction接口主要用于管理事务,它是hibernate的`事务接口`,对底层的事务进行了封装。使用它可以进行事务操作。
commit 事务提交
rollback 事务回滚
session.getTransaction()只是根据session获得一个Transaction实例,但是并没有启动它
session.beginTransaction()在获得一个Transaction后调用其begin()方法
5.Query*
Query接口让你方便地对数据库及持久对象进行查询,它可以有两种表达方式:HQL语言或本地数据库的SQL语句。Query经常被用来绑定查询参数、限制查询记录数量,并最终执行查询操作。
通过Query主要完成查询操作.
我们通过Query可以执行hql语句.
Query query=Session.createQuery(hql);
//hql语句面向对象:即JavaBean实体类
下面这个可以执行sql语句
SQLQUery sqlQuery=Session.createSQLQuery(sql);
SQLQuery是Query的子.
hql:模板:
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
...
session.getTransaction().commit();
session.close();
查询所有:
hql="from Customer";
分页查询:
query.setFirstResult(0);//开始位置
query.setMaxResults(3);//查询条数
查询指定列:
Select name ,address from Customer;
得到的是List<Object[]>结果,Object[]中:非常不方便,需要返回结果唯一(返回javabean集合)
要想得到List<Customer>结果
1. 在Customer类中生成以name,address为参数的构造,注意,无参数构造也要有。
2. Selectnew Customer(name,address) fromCustomer;(通过反射操作构造方法)
条件查询:
from Customer where name = ?
from Customer where name =:myname (不能有空格)
query.setParameter(0, "妮娜0");
query.setParameter("myname", "妮娜2");
//百分百确定结果只有一条记录可以使用uniqueResult();
Customer c = (Customer) query.uniqueResult();
sql:要想执行本地sql
SQLQuerysqlQuery=session.createSqlQuery(String sql);
sql为SQL语法
使用sqlQuery.addEntity()结果封装到指定的对象中,如果不封装,得到的是List<Object[]>
sqlQuery.addEntity(Customer.class);
如果sql中有参数,我们使用sqlQuery.setParameter()完成参数传递。
如果结果就是一个可以使用uniqueResult()来得到一个单独对象。
6.Criteria Criteria接口与Query接口非常类似,允许创建并执行面向对象的标准化查询。值得注意的是Criteria接口也是轻量级的,它不能在Session之外使用。
首先我想使用Criteria,必须得到Criteria
Criteriacriteria=Session.createCriteria()
语法:使用时百度即可
注解:注解作用:在hibernate中我们使用注解,可以帮助我们简化hbm文件配置。
注解加在哪?映射文件是为了映射表和实体类的关系,因此注解需要加在实体类中
注解根据功能不同,加在不同位置:类,属性
对于我们以上讲解的关于属性配置的注解,我们也可以在其对应的getXxx方法去使用
注解使用什么包(有例外):javax.persistence
位于hibernate-jpa-2.1-api-1.0.0.Final.jar
基本注解配置:类:@Entity 声明一个实体
@Table来描述类与表对应:
@Table(name="表名",catalog="数据库名")
属性:@Id来声明一个主键
@GenerateValue 用它来声明一个主键生成策略
@GeneratedValue(strategy( 战略,策略)= GenerationType.IDENTITY)
默认情况下相当于native
可以选择的主键生成策略IDENTITY SEQUENCEUUID(额外需要记住怎么配置)
UUID配置(hibernate扩展):
//需要引入包org.hibernate.annotations.GenericGenerator
@GenericGenerator(name = "myuuid", strategy = "uuid")
@GeneratedValue(generator(生产者) = "myuuid")
@Column来定义列
@Column(name="列名")
字符串还需要指定长度,列的其他属性也可以设置,如:nullable = true
注意:对于PO类中所有属性,如果你不写注解,默认情况下也会在表中生成对应的列。列的名称就是属性的名称
如果类中的属性是order这类,在数据库是关键字,这种情况必须设置此注解
@Temporal来声明日期类型(属性)
可以选择
TemporalType.DATA 只有年月日
TemporalType.TIME 只有小时分钟秒
TemporalType.TIMESTAMP 有年月日小时分钟秒
@Transient:设定类的属性不在表中映射
我们最终需要在hibernate.cfg.xml文件中将我们类中的注解配置引用生效(引入类)
级联注解配置:一对多注解开发:@OneToMany(targetEntity=类名.class,mappedBy="多的一方持有本方的对象",orphanRemoval="true")
@Cascade(CascadeType.ALL)
@OneToMany:加在Set<Order>上
mappedBy="customer":由order维护外键,order中获得客户ID通过customer的getID()方法
cascade:
两种方式:
一种是JPA:javax.persistence (包)
cascade属性:
一种是hibernate(对JPA进行了扩展):
@cascade(CascadeType.SAVE_UPDATE)注解形式
导入包:
org.hibernate.annotations.Cascade;
org.hibernate.annotations.CascadeType;
注解中DELETE_ORPHAN过时:看源码,使用orphanRemoval="true"替代
@ManyToOner:加在对象上
@ManyToOne(targetEntity = 类名.class)
@JoinColumn(name = "外键列名")//
@Cascade(CascadeType.SAVE_UPDATE)//只能设置为SAVE_UPDATE
多对多(不能做删除操作!!!!!!!!):哪方维护外键级联保存时保存哪一方
一方:
@ManyToMany(targetEntity=全类名.class,mappedBy="另一方持有本方的对象") //代表放弃维护外键
@Cascade(CascadeType.SAVE_UPDATE)//只能设置为SAVE_UPDATE
另一方
@ManyToMany(targetEntity=全类名.class)
//维护外键的一方设置中间表
@Jointable(name="生成中间表表名",joinColumns="本方在中间表的列名",inverseJoinColumns="对方在中间表的列名")
@Cascade(CascadeType.SAVE_UPDATE)//只能设置为SAVE_UPDATE
//student方维护外键
s1.getTeachers().add(t1);
s1.getTeachers().add(t2);
s2.getTeachers().add(t2);
s2.getTeachers().add(t1);
session.save(s2);
session.save(s1);
一对一(了解)检索方式:分为五种:
1.导航对象图检索方式,根据已加载的对象导航到其它对象
2.OID检索方式,按照对象的OID来检索对象
3.HQL检索方式,使用面向对象的HQL查询语言
4.QBC检索方式,使用QBC(Query by Criteria)API来检索对象,这种API封装了基于字符串形式的查询语句,提供了更加面向对象的查询接口
5.本地SQL检索方式,使用本地数据库的SQL查询语句
导航对象图检索方式(常用于多表查询)Customer c=session.get(Customer.class,2);
c.getOrders().size()
通过在hibernate中进行映射关系,在hibernate操作时,可以通过导航方式得到
其关联的持久化对象信息。
会导致N+1问题
OID检索方式Session.get(Customer.class,3);
Session.load(Order.class,1);
Hibernate中通过get/load方法查询指定的对象,要通过OID来查询。
HQLHQL是我们在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()返回一个查询结果。
重写toString()方法时需要将对象属性去掉
1)基本检索 from 类名
eg:
//关键字不区分大小写,类名区分
String hql = "from Customer";
Query query = session.createQuery(hql).list();
2)排序检索 from 类名 order by 属性 asc/desc
eg:
String hql = "from Orderorder by money desc"; // desc 降序 默认是asc 升序
List<Order> list =session.createQuery(hql).list();
3)条件检索
方式一:from 类名 where 属性=? and 属性=?
eg:
String hql = "from Orderwhere money>? and name=?";
List<Order> list =session.createQuery(hql).setParameter(0,2000).setParameter(1,"张三").list();
//条件为外键时以对象作为条件
Customercustomer = session.load(Customer.class,1);
String hql = "from Orderwhere customer =?";
Query query = session.createQuery(hql);
query.setParameter(0,customer);
方式二:from 类名 where 属性 = :名称
注意:名称随意,要和后面setParameter中的key对应起来,`:名称 `之间不能有空格
eg:
String hql = "from Orderwhere money>:mmmoney and name=:nnname";
List<Order> list =session.createQuery(hql).setParameter("mmmoney",2000).setParameter("nnname","张三").list();
4)分页检索
query.setFirstResult(开始位置)和query.setMaxResults(多少条)
eg:
Query query = session.createQuery("fromOrder");
// 每页显示6条件 ,我们要得到第二页数据
query.setFirstResult((2 - 1) * 6); // 设定开始位置
query.setMaxResults(6); // 设置条数
List<Order> list =query.list();
5)分组统计检索
统计: select 统计函数(属性) from 类名
eg:
// *符号只有在统计函数中才不会被识别为属性
String hql="selectcount(*) from Order";
Object count = session.createQuery(hql).uniqueResult();
sum()对属性有要求:必须为number类型
分组: select 统计函数(属性) from 类名 group by 属性
eg:
String hql="selectcount(*) from Order group by mCostomer";
Object count = session.createQuery(hql).uniqueResult();
6)投影检索(将查询结果封装到po中) select new 类名(属性1,属性2) from 类名
eg:
//必须在PO类中提供无参和对应参数的构造方法
String hql = "select newCustomer(id,name) from Customer";
List<Customer> cs= session.createQuery(hql).list();
7)命名检索(了解)
SQL多表操作:看文档中ORACLE语句
外连接规范语法: 左外LEFT OUTER JOIN 右外RIGHT OUTER JOIN
OUTER可以省略
SELECT * FROM t_customer c LEFT JOIN t_order o ONc.id=o.c_customer_id;
HQL多表操作(了解):多表(fetch和distinct一起使用(查询一的一方需要去重))
迫切内连接
迫切左外连接
查询结果被封装了,封装成from后面的对象!!!
Hibernate事务管理:1.事务介绍:问题:什么是事务?
事务就是逻辑上的一组操作,组成这组操作的各个单元要么全部成功,要么全都失败。
问题:事务四个特性?
原子性:不可分割
一致性:事务在执行前后,要保证数据的一致。
隔离性:一个事务在执行的过程中,不应该受到其它事务的干扰。
持久性:事务一旦结束,数据持久化到数据库。
问题:不考虑事务的**隔离性**,会产生什么问题?
脏读:一个事务读取到另一个事务的未提交数据
不可重复读:一个事务读取到另一个事务提交的数据(主要是指update),会导致两次读取的结果不一致(提交前后不一样)。
虚读(幻读): 一个事务读取到另一个事务提交的数据(主要是指insert),会导致两次读取结果不一致(提交前后不一样)。
问题:对于上述问题如何解决?
我们可以通过设置隔离级别来解决.
READ_UNCOMMITED 读取未提交,它引发所有的隔离问题(基本不用)
READ_COMMITTED 读已提交,阻止脏读,可能发生不可重复读与虚读.
REPEATABLE_READ 重复读 阻止脏读,不可重复读 可能发生虚读
SERIALIZABLE 串行化 解决所有问题 不允许两个事务,同时操作一个目标数据。(效率低下)(基本不用)
**一般使用默认级别,不修改
ORACLE 默认的是事务隔离级别 READ_COMMITTED
MYSQL 默认的事务隔离级别 REPEATABLE_READ
2.Hibernate中设置事务隔离级别:**hibernate.connection.isolation (隔离)**
它可取的值有 1 2 4 8
1代表的事务隔离级别为READ UNCOMMITTED
2代表的事务隔离级别为READ COMMITTED
4.代表的事务隔离级别为 REPEATABLE READ
8代表的事务隔离级别为 SERIALIZABLE
**取值原因:任意组合不会重复
在hibernate.cfg.xml文件中配置
3.Hibernate中session管理 Hibernate提供了三种管理session的方式:
1. Session对象的生命周期与本地线程绑定(ThreadLocal)
底层map key:sessionFactory value:session
2.Session对象的生命周期与JTA事务绑定(分布式事务管理)
3.Hibernate委托程序来管理Session的生命周期
我们之前所使用的是第三种 ,通过程序获取一个Session对象,使用它,最后session.close();
在实际开发中我们一般使用的是前两种
主要介绍关于本地线程绑定Session。(看截图)
步骤:
1. 需要在hibernate.cfg.xml文件配置
<propertyname="hibernate.current_session_context_class">thread</property>
2. 在获取session时不要在使用openSession而是使用getCurrentSession()方法。
**使用getCurrentSession获取的与线程绑定的session对象,在事务关闭时,session对象也会close,简单说,就不需要我们在手动close;**
Hibernate优化方案1.HQL优化1.使用参数绑定```
1.使用绑定参数的原因是让数据库一次解析SQL,对后续的重复请求可以使用用生成好的执行计划,这样做节省CPU时间和内存。
2.避免SQL注入
```
2.尽量少使用NOT```
如果where子句中包含not关键字,那么执行时该字段的索引失效。 ```
3.尽量使用where来替换havingHaving在检索出所有记录后才对结果集进行过滤,这个处理需要一定的开销,而where子句限制记录的数目,能减少这方面的开销
4.减少对表的查询在含有子查询的HQL中,尽量减少对表的查询,降低开销
5.使用表的别名当在HQL语句中连接多个表时,使用别名,提高程序阅读性,并把别名前缀与每个列上,这样一来,可以减少解析时间并减少列歧义引起的语法错误。
6.实体的更新与删除在hibernate3以后支持hql的update与delete操作
2.一级缓存优化一级缓存也叫做session缓存,在一个hibernate session有效,这级缓存的可干预性不强,大多于hibernate自动管理,但它提供清除缓存的方法,这在大批量增加(更新)操作是有效果的,例如,同时增加十万条记录,按常规进行,很可能会出现异常,这时可能需要手动清除一级缓存,session.evict以及session.clear.
3.检索策略(抓取策略)延迟加载延迟加载 是hibernate为提高程序执行的效率而提供的一种机制,即只有真正使用该对象的数据时才会创建。
可以减少缓存的压力
load方法采用的策略延迟加载.
get方法采用的策略立即加载。
检索策略分为两种:
1. 类级别检索 (针对load方法)
2. 关联级别检索(导航对象图查询)
检索总结:类级别(延迟/立即加载)
@Proxy(lazy="false") 针对load方法
关联级别(1对多)
@LazyToOne(多的一方)
@LazyCollection(1的一方)
上面2个注解只是控制加载数据的时机
@Fetch(查询语句的方式 简单sql查询/连接查询/子查询)
上面这个注解决定加载数据的时候是使用哪种sql语句
@LazyToOne(false/proxy)
/*
proxy:跟随主表(一的一方)类级别的策略
*/
@LazyCollection(true/false/extra)
/*
true:立即加载
false:用到时再加载,只要使用就会查询出所有信息
extra:用到什么加载什么,eg:只查订单个数就不会查订单信息
*/
@Fetch(select/join/subselect)
/*
select:简单查询(单表上的查询,格式为多条简单SQL语句)
join:使用join时lazy注解会失效,全部为立即加载,格式为:迫切左外连接
subselect:子查询
*/
记住各个属性,能够自己说出组合的意思
eg:
一的一方
Customerc = session.get(Customer.class,1);
list =c.getOrders();
通过客户查询该客户的所有订单的时候,延迟加载,并且加载的时候是使用的简单sql查询
* 如何对一个延迟代理对象进行初始化?为何要初始化:return c1时session.close()已经关闭,此时c1中没有数据,get方法也无法使用
通过load形式加载的延迟加载的对象如何进行初始化
1.对象.get方法()
2.hibernate.initilize(对象)
**3.openSessionInViewfilter (Spring框架)
a.类级别检索类级别检索是通过session直接检索某一类对应的数据,例如
Customer c=session.load(Customer.class,1)
Session.createQuery(“from Order”)
类级别检索策略分为立即检索与延迟检索,`默认是延迟检索`,类级别的检索策略可以通过<class>元素的lazy属性来设置 ,默认值是true
如果将lazy设置为false,代表类级别检索也使用立即检索。这时load与get就一样,都是立即检索。
在hbm配置文件中设置 :
lazy="true"
在类中使用注解:
@Proxy(lazy=true)
b.关联级别检索查询到某个对象,获得其关联的对象或属性,这种称为关联级别检索
eg:
c.getOrders().size()
c.getName()
对于关联级别检索我们就要研究其检索策略(抓取策略)(检索总结中的组合)
4.N+1问题Customer c
Order o1
Order o2
Order o3
通过客户查询该客户的所有订单时(n+1) @BatchSize =4
客户 1条sql
select * from customer where id =1;
订单 3条sql
select * from t_order where customer_id = 1 and oid =1;
select * from t_order where customer_id = 1 and oid =2;
select * from t_order where customer_id = 1 and oid =3;
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |