hibernate
程序员文章站
2022-05-24 12:29:07
...
hibernate是什么
框架是什么
- 框架是用来提高效率的
- 封装好了一些功能,我们需要使用这些功能时调用即可,不需要再手动实现。
- 所以框架可以理解成是一个半成品项目,只要懂得如何驾驭这些功能即可
hibernate框架是什么
- hibernate是帮我们完成数据库操作的orm(对象关系映射)框架,属于Dao层。
hibernate框架的好处
- 让我们以面向对象的方式操作数据库,甚至不用写sql语句
hibernate框架的搭建
- hibernate框架包和驱动包
- 创建数据库(也可以不创建数据库,hibernate将会自动生成数据库和表),准备实体类
- 书写orm元数据(对象与表的配置文件)
- orm元数据的命名规范:对应实体类名.hbm.xml(放置在对应类的包中)
- orm配置文件的书写
- 导入约束
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
- 书写元素
//package属性(可写可不写)若写了则在其子标签中,需要写完整类名的地方只需写其简单类名即可,简化操作
<hibernate-mapping package="">
/*
class元素配置实体与表的对应关系
name属性:对应实体的完整类名
table属性:对应数据库的表名
*/
<class name="" table="" >
//name属性:填写实体中id对应的属性名,column属性(可选属性,一般不写):填写数据库id对应的列名
<id name="" column="" >
//generator属性:主键生成策略,native: 根据所选数据库三选一(开发中就用native就行)
<generator class="native" ></generator>
</id>
/*
property元素:除id之外的普通属性映射
not-null属性:指定该属性值是否不能为空,默认为false
length:配置数据库中对应列的长度
type:配置数据库中对应列的数据类型(建议不写,hibernate将会自动匹配)
*/
<property name="" column="" not-null="false" length="" type="" ></property>
</class>
</hibernate-mapping>
- hibernate主配置文件(放置在src下)
- 导入约束
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration 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.Driver</property>
<!-- 数据库url -->
<property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
<!-- 数据库连接用户名 -->
<property name="hibernate.connection.username">root</property>
<!-- 数据库连接密码 -->
<property name="hibernate.connection.password">123456</property>
<!-- 数据库方言
不同的数据库中,sql语法略有区别. 指定方言可以让hibernate框架在生成sql语句时.针对数据库的方言生成.
sql99标准: DDL 定义语言 库表的增删改查
DCL 控制语言 事务 权限
DML 操纵语言 增删改查
注意: MYSQL在选择方言时,请选择最短的方言.
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 以上五个是必选配置 -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<!-- hibernate.hbm2ddl.auto参数的作用主要用于:自动创建|更新|验证数据库表结构,开发中就选update -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- orm数据文件的路径 -->
<mapping resource="cn/itcast/domain/Customer.hbm.xml"/>
</session-factory>
</hibernate-configuration>
hibernate API介绍
- Configuration对象(加载配置文件):Configuration cfg= new Configuration().configure();
- SessionFactory(Session工厂):SessionFactory factory= cfg.buildSessionFactory();
- SessionFactory:负责保存和使用所有配置信息,消耗内存非常大
- SessionFactory属于线程安全对象
- 保证在一个web项目中只创建一个
- Session(相当于jdbc中的Connection对象):Session session=factory.openSession();
factory.getCurrentSession()获得的是与线程绑定的Session对象,若要使用此方法获得Session对象,就必须在主配置文件中添加配置:
<property name="current_session_context_class">thread</property>
- Transaction(事物操作对象):Transaction tx = session.beginTransaction()
- 若是factory.openSession()方法产生的session,事物操作完成后,需要关闭调用close()方法关闭session,若是factory.getCurrentSession()方法产生的session对象不需要手动关闭session
#hibernate中实体的规则
- 实体类创建的注意事项:
- 必须提供无参的构造方法
- 成员变量需私有,并且提供get和set方法
- 不能用final修饰Class(因为hibernate使用cglib代理来生成代理对象的,而cglib代理是使用继承来实现的)
- 所有成员变量的类型最好使用对应的包装类
- 持久化类中提供的对应属性应与数据库中的对应列同名
-
主键类型一般采用代理主键,并且主键生成方式选择native
#hibernate中对象的三种状态 -
瞬时状态:没有id,没有与session建立关联
-
持久化状态:有id,与session建立了关联
-
游离状态或托管状态:有id,没有与session建立关联
- new出来的对象为瞬时状态,get得到的对象为持久化状态,session关闭后,持久化状态的对象就变为游离状态,update方法可以将游离状态的对象转化为持久化状态
#hibernate中一级缓存
- 作用:提高开效率
hibernate批量查询
HQL查询(多表查询,但不复杂时使用)
//基本查询
String hql="from Customer";
Query query=session.createQuery(hql);
List list=query.list();
//?占位符,条件查询
String hql="from Customer where id=?";
Query query=session.createQuery(hql);
query.setParameter(0,1l);
Customer c=query.uniqueResult();
//冒号占位符,条件查询
String hql="from Customer where id=id";
Query query =session.createQuery(hql);
query.setParameter("id",1);
Customer c=query.uniqueResult();
//hql统计查询
String hql="select new Customer(id,name) from Customer"
Query query=session.createQuery(hql);
Customer c=query.list();
//分页查询
String hql="from Customer"
Query query =session.createQuery(hql);
query.setFirstResult(0);
query.setMaxResults(2);
List list=query.list();
//计数查询
String hql1 = "select count(*) from Customer";
//求和
String hql2 = "select sum(cust_id) from Customer";
//平均数
String hql3 = "select avg(cust_id) from Customer";
//最大值
String hql4= "select max(cust_id) from Customer";
//最小值查询
String hql5 = "select min(cust_id) from Customer";
Query query = session.createQuery(hql4);
Number number = (Number)query.uniqueResult();
Criteria查询
//基本查询
Criteria criteria=session.createCriteria(Customer.class);
List list=criteria.list();
//条件查询
Criteria criteria=session.createCriteria(Customer.class);
criteria.add(Restrictions.eq("cust_id", 16l));
Customer c=(Customer)criteria.uniqueResult();
//分页查询
Criteria criteria = session.createCriteria(Customer.class);
criteria.setFirstResult(0);
criteria.setMaxResults(2);
List list = criteria.list();
//总记录数查询
Criteria criteria = session.createCriteria(Customer.class);
criteria.setProjection(Projections.rowCount());
Long count = (Long) criteria.uniqueResult();
原生sql查询(复杂查询)
//基本查询
String sql="select * from t_customer";
SQLQuery sq=session.createSQLQuery(sql);
//将结果集封装到指定的实体类中
sq.addEntity(Customer.class);
List list=sq.list();
//条件查询
String sql="select * from t_customer where id=?";
SQLQuery sq=session.createSQLQuery(sql);
sq.setParameter(0,10);
sq.addEntity(Customer.class);
Customer c = (Customer) sq.uniqueResult();
//分页查询
String sql="select * from t_customer limit ?,?";
SQLQuery sq=session.createSQLQuery(sql);
//将结果集封装到指定的实体类中
sq.setParamerter(0,0);
sq.setParamerter(1,3);
sq.addEntity(Customer.class);
List list=sq.list();
hibernate中的关系表达
一对多,多对多关系表达
一的一方
- 在一的一方的实体中创建一个HashSet集合对象,用此集合来存储多的一方的实体变量
- 然后在一的一方的配置文件中加入如下配置
/*
name属性:填写一的一方的实例中与多的一方表达关系的集合属性名称
casecade属性:级联操作,有三个值:update、delete、all(save-update+save-delete),直接选用upda
te即可,级联保存更新
key元素中column属性填写对应数据库中外键列名
one-to-many中的class属性填写对应多的一方的全类名
*/
<set name="" casecade="update" >
<key column="" ></key>
<one-to-many class="" />
</set>
多的一方
- 在多的一方的实体中创建一个一的一方的实例变量,用此变量来表达与一的对应关系
- 然后在多的一方的配置文件中加入如下配置
/*
name属性:填写多的一方的实例中与一的一方表达关系的实例变量名
column属性:填写数据库中对应的外键列名
class属性:填写对应一的一方的全类名
*/
<many-to-one name="" column="" class="" ><many-to-one/>
如何用代码表示一对多,多对一的关系:
Customer c = new Customer()
c.setCust_name("百度公司");
LinkMan l1 =new LinkMan();
l1.setLkm_name("黎活明");
LinkMan l2= new LinkMan();
l2.setLkm_name("刘跃东");
//表达客户和联系人的关系
c.getLinkMens().add(l1);
c.getLinkMens().add(l2);
//表达联系人和客户的关系
l1.setcustomer(c);
l2.setCustomer(c);
//将Customer对象和LinkMan对象转化为持久化状态,将数据同步到数据库中
- 注意:LinkMan这一方(即多的一方)执行插入操作时,就已经维护了表之间的关系(即外键),此时hibernate默认Customer(即一的一方)也会维护外键关系,这时就会发现一的一方维护外键关系的sql语句多余了,会降低程序的执行效率,所以此时最好在Customer的orm元数据配置中的set元素中加入inverse属性并将其值设置为true,放弃Customer(即一的一方)关系的维护,多的一方一定不能放弃关系的维护。
- 代码:
<set name="" casecade="update" inverse="true" >
<key column="" ></key>
<one-to-many class="" />
</set>
多对多关系的表达
- 在两个对应实体类中分别创建两个集合,用来保存对方的实体对象,用此集合来在java类中表示关系的维护。
- 还需要在各自实体类中加入如下配置:
/*
name属性:填写实体类中对应的集合变量名
table属性:中间表名
column属性填写本表中的id名(即中间表中外键名)
class属性:与本类构成多表关系的类的完全类名
many-to-many元素中的column属性:填写class属性中对应类所对应表中的id名
*/
<set name="" table="">
<key column=""></key>
<many-to-many class="" column=""></many-to-many>
</set>
- 在多对多关系中,必须有一方要放弃关系的维护,否则双方都会维护中间表的外键关系,会导致向中间表插入记录重复而报错。而且在选择放弃维护关系时,应该视关系情况而定,如员工和职务之间的关系,是由员工维护的,要选择放弃职务对第三张表的维护
- 如何用代码表示多对多的关系:
User u1= new User();
u1.setName("张三");
User u2= new User();
u2.setName("李四");
Role r1 = new Role();
r1.setRo_name("保洁");
Role r1 = new Role();
r1.setRo_name("保安");
//角色表达和职务的关系
u1.getRoles().add(r1);
u1.getRoles().add(r2);
u2.getRoles().add(r1);
u2.getRoles().add(r2);
//职务表达和角色的关系
r1.getRoles().add(u1);
r1.getRoles().add(u2);
r2.getRoles().add(u1);
r2.getRoles().add(u2);
//将关系持久化到数据库中
u1.save();
u2.save();
r1.save();
r2.save();
// **此时一定注意要在orm元数据中放弃其中一方关系的维护**
查询优化
- get方式查询:立即调用数据库查询,加载数据
- load方式查询:应用类级别加载策略,而且返回的是代理对象(采用cglib代理)
/*
lazy:
true:默认取值,它的意思是只有在调用这个集合获取里面的元素对象时,才发出查询语句,加载其
集合元素的数据
false:取消懒加载特性,即在加载对象的同时,就发出第二条查询语句加载其关联集合的数据
extra:一种比较聪明的懒加载策略,即调用集合的size/contains等方法的时候,hibernate并不会去加载整个集合的数据,而是发出一条聪明的SQL语句,以便获得需要的值,只有在真正需要用到这些集合元素对象数据的时候,才去发出查询语句加载所有对象的数据
*/
<class name="Customer" table="cust_customer" lazy="false">
- 注意:使用懒加载时应确保调用属性加载数据时session是打开的,否则会抛出异常
- no-session问题解决:
- 在filter中处理session事务
//在开发时lazy和fetch都选择默认值即可
//batch-size属性:设置每次查询时抓取几条数据
<set name="" lazy="true" fetch="select" batch-size="">