最近觉得有必要将以前学的框架整理和回顾一下,同时也为还未学习的小伙伴儿们做个了解,先从hibernate开始,作为SSH三大框架之一,尤其是对数据进行操作的框架,其无疑使应该被重视的。
一. 首先我们先创建一个持久化类所谓持久化类,即JavaBean类和映射文件的结合,持久化类有几个编写规则需要说一下:
需要提供无参数的构造方法。
类的属性需要私有,对私有的属性提供public的get和set方法。
提供一个唯一标识(OID)的属性与表的主键对应。
Java里面使用地址区分是否是同一个对象。数据库中是通过主键区分是否是同一个记录。Hibernate通过唯一标识区分是否在内存中是同一个对象。
类不要使用final修饰。
类中的属性尽量使用包装类类型。
JavaBean就不再啰嗦了,这里说一下映射文件,映射文件命名规则为 类名.hbm.xml,放在与JavaBean同一个包下,配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- ORM:Object Relational Mapping,将实体类O和数据库的表R 建立映射关系 -->
<class name="实体类全类名" table="表名">
<!-- 类中的属性与表中的主键对应 -->
<id name="id" column="id">
<generator class="native"/>
</id>
<!-- 类中的属性与表中的字段对应 -->
<property name="name" column="name"/>
......
</class>
</hibernate-mapping>
这里约束如上,从Web App Libraries---hibernate-mapping-3.0.dtd中拷出,这里特别要说的是,实体类中必须有一个属性和表中的主键相对应,generator是主键的生成策略,identity一般用于主键自增长的数据库,如mysql,db2等,Sequemce一般用于有序列的数据库,如oracle,native则是自动判断数据库用于适合的配置,所以这里我们选择native。当然也可以用注解或者自动生成的方式配置映射。
二.接下来配置它的核心配置文件,默认文件名为hibernate.cfg.xml,放在src下,配置如下
<?xml version="1.0" encoding="UTF-8"?>
<!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>
<property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
<property name="hibernate.connection.username">账户</property>
<property name="hibernate.connection.password">密码</property>
<!-- 数据库的方言:根据底层的数据库生成不同的SQL -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 配置显示SQL -->
<property name="hibernate.show_sql">true</property>
<!-- 配置格式化SQL -->
<property name="hibernate.format_sql">true</property>
<!-- 配置hbm2ddl -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 加载映射文件 -->
<mapping resource="这里是映射文件"/>
</session-factory>
</hibernate-configuration>
约束如图上Web App Libraries---hibernate-configuration-3.0.dtd,这里特别说一下hbm2ddl的配置,一般用crete和update,create一般用在测试的时候,意思是每次都会创建一个新的表,update表示在原表上更新,如果有小伙伴在测试的时候用create可能会导致错误,这个之后再说,还有,配置了映射文件的话别忘了加载!
同时,考虑到安全问题,还应该增加隔离级别这一条件
<!-- 设置事务的隔离级别 -->
<property name="hibernate.connection.isolation">4</property>
三.hibernate的几个方法
Configuration对象,主要作用是加载核心配置文件和加载映射文件:
Configuration cfg = new Configuration().configure();
SessionFactory
SessionFactory用于管理session,管理二级缓存,线程安全,通常一个项目创建一个SessionFactory就行了,因为每次都会用到这些方法,所以一般将它们抽取为一个工具类HibernateUtils:
public class HibernateUtils {
private static final Configuration configuration;
private static final SessionFactory sessionFactory;
static{
configuration = new Configuration().configure();
sessionFactory = configuration.buildSessionFactory();
}
public static Session openSession(){
return sessionFactory.openSession();
}
}
但是因为会进行事务的管理,为了避免代码入侵并且保证方法都在一个事务中,一般会将session绑定到当前线程,所以将工具类改造如下
package com.wkesi.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
private static final Configuration configuration;
private static final SessionFactory sessionFactory;
static{
configuration=new Configuration().configure();
sessionFactory=configuration.buildSessionFactory();
}
//获取当前线程绑定的会话
public static Session getCurrentSession(){
return sessionFactory.getCurrentSession();
}
public static Session openSession(){
return sessionFactory.openSession();
}
}
那同时要在核心配置文件hibernate.cfg.xml中增加一条
<!-- 配置session绑定本地线程 -->
<property name="hibernate.current_session_context_class">thread</property>
四,一些定义
既然说到了session,那么session又是什么东西呢?其实小伙伴儿不妨把它理解为JDBC中的connection,它是hibernate框架中代码和数据库的桥梁,维护了hibernate的一级缓存,那么缓存又是什么呢?官方一点就是介于应用程序和永久性数据存储源之间,其作用是降低程序直接读取数据库的频率,通俗一点就是一块空间与应用程序和数据库相连,在用hibernate查询对象的时候,会先从缓存中查找属性的OID,如果找到了就会直接从缓存中取出,不会再查询数据库了,这样就减少了查询数据库的次数,提升了性能,响应的,如果找不到就会从数据库中获取,并且将本条对象存入一级缓存以便下次获取。
快照,提到缓存就不得不说快照,这是持久态对象自动更新的原因,首先普及一下hiberbate中对象的三种状态
1)瞬时态,是直接用实体类new出来的对象,不存在持久化标识OID,且未被session管理;
2)持久态,存在持久化表识,并被session管理,如直接查询出来的对象;
3)脱管态,存在持久化表识OID,但未被session管理
接下来给出hibernate的一个测试代码,并解释三种状态
持久态在被存入数据库的时候,一级缓存和快照区都会有记录,一旦其被查询到且改变,在事务提交的时候tx.commit(),会更新缓存中的记录,然后缓存区记录与快照区比对,若比对结果一样就不更新数据库,若比对结果不一样就会自动更新数据库,这就是持久态对象自动更新数据库的原因。
接下来给出几个简单的案例来操作hibernate更新数据库:
Session保存某个对象
public void demo1(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("名字");
session.save(customer);// 保存对象
tx.commit();
session.close();
}
Session中修改某个对象的方法
public void demo3(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
先查询再修改.
Customer customer = session.get(实体类的字节码文件, 4l);
customer.setCust_name("名字");
瞬时态对象自动更新!!!!!!
tx.commit();
session.close();
}
Session删除某个对象的方法
public void demo4(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
先查询,在删除
Customer customer = session.get(Customer.class, 3l);
session.delete(customer);
tx.commit();
session.close();
}
Session查询某个对象
这里有两种方法,get和load
Customer customer = session.get(Customer.class, 100l)
Customer customer = session.load(Customer.class, 300l)
那么它们又有什么区别了,这就说到hibernate自带的一种优化机制了!延迟加载!Load方式就应用了这一机制,那么它和普通get方法有什么区别呢?
get方法采用的是立即加载,执行到该行代码的时候,马上发送SQL语句进行查询。查询之后返回的是真实对象本身,查询一个找不到的对象返回null.
load方法采用的是延迟加载(lazy),执行到改行的代码的时候,不会马上发送SQL语句,只有真正使用这个对象的时候(使用这个对象的普通属性的时候)才会发送SQL语句。比如使用customer对象的cust_name属性的时候,才会真正查询,load方法返回的是代理对象。(产生的是Customer的子类对象,这也就解释了为什么实体类的修饰不能为final),查询一个找不到的对象抛出异常:ObjectNotFoundException
五.hibernate中实体类一对一,多对多的配置
一般我们会遇到这么一种情况,一个客户有多人在维护关系,所以对应关系是一个客户对应很多联系人,将客户和联系人分别创建实体类并建表,这就是典型的一对多关系,建表如下:
【客户的实体】
public class Customer {
private Long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_phone;
private String cust_mobile;
// 联系人的集合:
private Set<LinkMan> linkMans = new HashSet<LinkMan>();
}
【联系人的实体】
public class LinkMan {
private Long lkm_id;
private String lkm_name;
private String lkm_gender;
private String lkm_phone;
private String lkm_mobile;
private String lkm_email;
private String lkm_qq;
private String lkm_position;
private String lkm_memo;
// private Long lkm_cust_id;
private Customer customer;// 联系人对应的客户的对象
}
注意,这里客户对应很多联系人,所以用set对象表示,而每一个联系人对应一个客户,所以创建一个属性表示。
联系人的映射,其它不变,额外配置多对一映射
<!-- 在多的一方配置many-to-one -->
<!--
many-to-one标签:用来描述多对一的关系配置。
* name :一的一方的对象的属性名称。
* class :一的一方的类的全路径
* column :外键的名称
-->
<many-to-one name="customer" class="com.itheima.hibernate.domain.Customer" column="lkm_cust_id"/>
客户的映射,其它不变,额外配置一对多映射
<!-- 配置一对多的关联映射 -->
<!--
set标签:用来描述一的一方存放的多的一方的集合
* name:多的一方的集合属性名称
-->
<set name="linkMans">
<!--
key标签:
* column多的一方的外键的名称
-->
<key column="lkm_cust_id"/>
<!--
one-to-many标签:描述一对多的关系
* class:多的一方的类的全路径
-->
<one-to-many class="com.itheima.hibernate.domain.LinkMan"/>
</set>
此时为了更好的表示关系和操作数据,我们再添加级联属性,对客户,在<set>标签上配置cascade="save-update,delete",对于联系人,在在<many-to-one>标签上配置cascade="save-update,delete",那么在进行添加或者删除的时候,就会级联添加和删除,大家有没有想到省市联动呢?确实很像哦~那么如果是多对多的话,只要同时在实体类中添加set字并在映射文件中配置set属性就行了哦
六.语句
这里单说查询语句,hibernate共有五种查询方式,分别是对象图导航查询,OID检索查询,HQL查询,QBC查询,SQL检索查询,这里每种查询都会涉及到简单的一部分,更加复杂的限于篇幅还要小伙伴儿们多多学习了
首先来看对象图导航查询
@Test
public void demo1(){
Session session = HibernateUtils.getthreadSession();
Transaction tx=session.beginTransaction();
//对象图导航检索是根据已经加载的对象,导航到他的关联对象,前提必须配置了多对一的映射关系
LinkMan linkMan = session.get(LinkMan.class, 1l);
Customer customer = linkMan.getCustomer();
System.out.println(customer);
tx.commit();
}
OID检索查询
@Test
public void demo2(){
Session session = HibernateUtils.getthreadSession();
Transaction tx=session.beginTransaction();
//通过查询OID索引
Customer customer1 = session.get(Customer.class, 1l);
Customer customer2 = session.load(Customer.class, 1l);
System.out.println(customer1);
System.out.println(customer2);
tx.commit();
}
HQL查询,这里列举几个比较常用的
/**
* HQL基本查询
*/
@Test
public void demo3(){
Session session = HibernateUtils.getthreadSession();
Transaction tx=session.beginTransaction();
//查询全部
Query query = session.createQuery("from Customer");
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
/**
* HQL起别名查询
*/
@Test
public void demo4(){
Session session = HibernateUtils.getthreadSession();
Transaction tx=session.beginTransaction();
/*Query query = session.createQuery("from Customer c");
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}*/
Query query = session.createQuery("select c from Customer c");
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
/**
* HQL排序检索
*/
@Test
public void demo5(){
Session session = HibernateUtils.getthreadSession();
Transaction tx=session.beginTransaction();
Query query = session.createQuery("from Customer order by cust_id");
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
/**
* HQL条件检索
*/
@Test
public void demo6(){
Session session = HibernateUtils.getthreadSession();
Transaction tx=session.beginTransaction();
Query query = session.createQuery("from Cudtomer where cust_name=?");
query.setParameter(0, "小明");
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
/**
* HQL按名称绑定参数查询
*/
@Test
public void demo7(){
Session session = HibernateUtils.getthreadSession();
Transaction tx=session.beginTransaction();
Query query = session.createQuery("from Cudtomer where cust_name=:aaa");
query.setParameter("aaa", "小明");
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
/**
* HQL的分组统计查询
*/
@Test
public void demo8(){
Session session = HibernateUtils.getthreadSession();
Transaction tx=session.beginTransaction();
//聚集函数的使用
/*Query query = session.createQuery("select count(*) from Customer");
Long result = (Long) query.uniqueResult();
System.out.println(result);*/
//分组
tx.commit();
}
QBC检索
排序
@Test
/**
* 排序查询
*/
public void demo2(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
Criteria criteria = session.createCriteria(Customer.class);
// 设置排序:
//criteria.addOrder(Order.asc("cust_id"));// 升序
criteria.addOrder(Order.desc("cust_id"));// 降序
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
条件
@Test
/**
* 条件查询
*/
public void demo3(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
Criteria criteria = session.createCriteria(Customer.class);
// criteria.add(Restrictions.like("cust_name", "%明%"));
criteria.add(Restrictions.like("cust_name", "明", MatchMode.ANYWHERE));
criteria.add(Restrictions.eq("cust_source", "互联网"));
List<Customer> list = criteria.list();
for (Customer customer : list) {
System.out.println(customer);
}
tx.commit();
}
分页
@Test
/**
* 分页查询
*/
public void demo4(){
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
Criteria criteria = session.createCriteria(LinkMan.class);
criteria.setFirstResult(10);
criteria.setMaxResults(10);
List<LinkMan> list = criteria.list();
for (LinkMan linkMan : list) {
System.out.println(linkMan);
}
tx.commit();
}
hibernate就到这里吧,要想掌握hibernate还需要小伙伴儿们更深入的学习,请期待下一个框架.....下期见