欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

hibernate

程序员文章站 2022-05-24 12:29:07
...

hibernate是什么

框架是什么

  • 框架是用来提高效率的
  • 封装好了一些功能,我们需要使用这些功能时调用即可,不需要再手动实现。
  • 所以框架可以理解成是一个半成品项目,只要懂得如何驾驭这些功能即可

hibernate框架是什么

  • hibernate是帮我们完成数据库操作的orm(对象关系映射)框架,属于Dao层。

hibernate框架的好处

  • 让我们以面向对象的方式操作数据库,甚至不用写sql语句

hibernate框架的搭建

  1. hibernate框架包和驱动包
  2. 创建数据库(也可以不创建数据库,hibernate将会自动生成数据库和表),准备实体类
  3. 书写orm元数据(对象与表的配置文件)
  4. orm元数据的命名规范:对应实体类名.hbm.xml(放置在对应类的包中)
  5. 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介绍

  1. Configuration对象(加载配置文件):Configuration cfg= new Configuration().configure();
  2. SessionFactory(Session工厂):SessionFactory factory= cfg.buildSessionFactory();
  • SessionFactory:负责保存和使用所有配置信息,消耗内存非常大
  • SessionFactory属于线程安全对象
  • 保证在一个web项目中只创建一个
  1. Session(相当于jdbc中的Connection对象):Session session=factory.openSession();
    factory.getCurrentSession()获得的是与线程绑定的Session对象,若要使用此方法获得Session对象,就必须在主配置文件中添加配置:
<property name="current_session_context_class">thread</property>
  1. Transaction(事物操作对象):Transaction tx = session.beginTransaction()
  • 若是factory.openSession()方法产生的session,事物操作完成后,需要关闭调用close()方法关闭session,若是factory.getCurrentSession()方法产生的session对象不需要手动关闭session

#hibernate中实体的规则

  1. 实体类创建的注意事项:
  • 必须提供无参的构造方法
  • 成员变量需私有,并且提供get和set方法
  • 不能用final修饰Class(因为hibernate使用cglib代理来生成代理对象的,而cglib代理是使用继承来实现的)
  • 所有成员变量的类型最好使用对应的包装类
  • 持久化类中提供的对应属性应与数据库中的对应列同名
  1. 主键类型一般采用代理主键,并且主键生成方式选择native
    #hibernate中对象的三种状态

  2. 瞬时状态:没有id,没有与session建立关联

  3. 持久化状态:有id,与session建立了关联

  4. 游离状态或托管状态:有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="">