Hibernate

hibernate在hibernate.cfg.xml中配置数据库驱动,url,账号密码等

 

hibernate是有3种状态的,分别是瞬时、持久、脱管。其中new className()时数据库中还没有对应记录,这个时候className对象的状态是瞬时。

通过session的save把该对象保存在了数据库中,该对象也和session产生了联系,此时的状态应该是持久的。

最后把session关闭了,这个对象在数据库中有了对应的数据,但是已经和session失去了联系,相当于脱离了管理,状态是脱管。

 

 

Hibernate有五大接口,分别是session、Query、Sessionfactory、configuration、Translation,

  1、实例化的session是一个轻量级的类,它的创建和注销都不会产生太大的损失,在设计中最好是一个线程只创建一个session对象,session可以看作介于数据库连接与事务管理之间的一种接口,可以将session想象成一个持久的缓冲区,Hibernate能检测到这些持久层对象的改变,并及时刷新数据库,以及从数据库获得他们

  2、SessionFactory接口负责初始化Hibernate。它充当数据存储源的代理,负责创建Session对象,用到了工厂模式,这里的sessionFactory并不是轻量级的,在一般情况下一个项目只需要一个SessionFactory,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory

  3、Transaction接口负责事务相关操作,一般在Hibernate的增删查改中出现,但是使用Hibernate的人一般使用spring去管理事务

  4、Query负责执行各种数据库查询,它可以使用HQL或者SQL语言,返回值一般是List

  5、Configuration对象用于配置并启动Hibernate,Hibernate应用通过Configuration实例来指定对象关系映射文件的位置或者动态配置Hibernate的属性,然后创建SessionFactory

循行顺序为:

  1、应用程序先调用Configuration类读取该类中的配置信息

  2、使用这些信息生成SessionFactory对象,再使用sessionFactory对象生成session对象

  3、使用session对象生成Transaction对象

  4、通过session对象进行加载、保存、更新、删除等操作

  5、在查询情况下可以通过session对象生成Query对象,然后利用Query对象执行查询操作,如果没有异常的话Transaction对象将这些操作提交到数据库中

 

 

 

 

hibernate有两种面向对象的查询方法,分别是criteria和hql

 

hibernate有多对一,一对多,多对多的关系。例如Product和Category是多对一的关系,则应该在Product.hbm.xml文件中设置<many-to-one>,再在hibernate.cfg.xml中增加Category的映射。

 

 

public class CategoryDAOImpl implements zhongfucheng.dao.CategoryDao{

    @Override
    publicvoidaddCategory(Category category) {

        QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

        String sql = "INSERT INTO category (id, name, description) VALUES(?,?,?)";
        try {
            queryRunner.update(sql, new Object[]{category.getId(), category.getName(), category.getDescription()});

        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Category findCategory(String id) {
        QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());
        String sql = "SELECT * FROM category WHERE id=?";

        try {
            Category category = (Category) queryRunner.query(sql, id, new BeanHandler(Category.class));

            return category;

        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    public List<Category> getAllCategory() {
        QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());
        String sql = "SELECT * FROM category";

        try {
            List<Category> categories = (List<Category>) queryRunner.query(sql, new BeanListHandler(Category.class));

            return categories;
        } catch (SQLException e) {
            throw  new RuntimeException(e);
        }

    }
}

  要比较hibernate和传统的DBUtil的区别,就先看看传统方式是怎么进行crud的,如果是插入一个新的数据,则将对象的属性进行拆分,然后拼装成SQL语句。

  在进行查询时,则是将sql数据的属性拼装成javabean对象,其操作时十分繁琐的。但是如果使用hibernate则直接对对象进行操作。

 

package com.how2java.test;
 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
 
import com.how2java.pojo.Product;
 
public class TestHibernate {
    public static void main(String[] args) {
 
        SessionFactory sf = new Configuration().configure().buildSessionFactory();
 
        Session s = sf.openSession();
        s.beginTransaction();
 
        Product p =(Product) s.get(Product.class, 5);
        s.delete(p);
         
        s.getTransaction().commit();
        s.close();
        sf.close();
    }
 
}

  简直不要太简单!!!

 

假设在一个事务中做了两件事情,第一件事情执行成功但是第二件事情执行失败,则第一个事务执行也就不会生效,只有在表的类型是INNODB时才支持事务


hibernate支持级联操作,作为级联是指在数据库中多个表的对应关系,假设有一张教师信息表,表中的属性有教师的年龄手机号码家庭住址等信息,另一张表是老师和所带的班级之间的信息,一个班级对应一个老师,包括老师的手机号码,如果在表1 中改变老师张三的手机号码,如果设置了级联,则表二中张三的手机号码也会改变

 级联一共有四种:

all:所有的操作都执行级联操作

none:所有的操作都不执行级联操作

delete:删除时执行级联操作

save-update:保存和更新时执行级联操作

级联操作通常在one-many和many-to-many上,几乎不使用在many-one上。

 

 

Hibernate的一级缓存和二级缓存

使用缓存是为了减少对数据库的操作次数,从而提高执行效率,Hibernate的一级缓存是也叫做session缓存,它可以在session的范围内减少数据库的访问次数,若session关闭,则一级缓存失败。当调用session的save/saveOrUpdate/get/load/list/iterator方法的时候,会把对象放入session中,session是由hibernate维护的,可以通过hibernate的evict/clear方法操作,不同session不会共享数据。

使用二级缓存时,需要在hibernate.cfg.xml中开启二级缓存配置,hibernate本身不提供二级缓存,都是使用第三方的二级缓存插件,

<property name="hibernate.cache.use_second_level_cache">true</property>
 <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

 二级缓存可以跨越多个session,即不同的session都可以访问缓存数据

 

 

hibernate的懒加载是当用到数据的时候猜想数据库查询,这就是hibernate的懒加载,使用懒加载是为了提高程序的执行效率

get()方法,及时加载,只要调用该方法就立即向数据库查询

load()方法,默认懒加载,即在使用数据的时候才想数据库发送查询,session关闭后不可以使用懒加载,当session关闭后使用懒加载则会报错,解决方法:

1在关闭session之前使用一下数据,这样数据就缓存在session中了,关闭后依旧正常使用数据。

2关闭懒加载

3强迫代理对象初始化操作:Hibernate.initialize

4在使用完数据之后在关闭session

在对属性不存在的对象处理时,例如查询id=999的对象,而该对象不存在时,get方法会返回null而load方法会抛出异常

 

 

Hibernate中的query.list()与query.iterator()方法的区别

1、list()方法返回的是一个List二iterator()方法返回的是iterator

2、获取数据的方式不一样,list()会直接查询数据库,iterator()会先到数据库中把id都取出来,然后真正要遍历某个对象的时候先到缓存找,如果找不到则以id为条件再发一条sql到数据库,如果缓存中没有数据,则查询数据库的次数是n+1

3、iterator会查询二级缓存,list只查询数据库。

4、list()中返回的List中的每个对象都是原本的对象,iterator中返回的对象是代理对象

5、list()方法会一次去除所有的结果集对象,而且他会依据查询的结果初始化的结果集对象,如果结果集非常大则可能造成内存泄露的情况

6、iterator()方法在执行时不会一次初始化所有的对象,而是根据对结果集的访问情况来初始化对象,可以控制缓存中的对象数量,以避免占用过多的缓存,导致内存溢出的发生。

 

 

Hibernate有两种方法获得session,分别是openSession和getCurrentSession区别在于:

1、openSession每次都会得到一个新的Session对象,getCurrentSession在同一个线程中每次都是获得相同的Session对象,但是在不同的线程中获取的是不同的Session对象。

2、openSession只有在增加、删除、修改的时候需要事务,查询的时候不需要。getCurrentSession是自由所得操作都必须放在事务中进行,并且提交事务后session会自动关闭,不需要再进行关闭。

 

 

hibernate的乐观锁是通过version的值来控制对数据库的存取

乐观并发控制可以有三种方式

Version版本号

时间戳

自动版本控制

仅说明版本好控制的过程

假设数据库中的产品的价格是1000,version是10,session1、session2分别获取了该对象并且都要修改该对象的价格,

session1试图保存到数据库,检测version依旧等于10,成功保存,并把version修改为11

session2试图保存到数据库,检测到version=11,说明改数据已经被其他进程访问过了,保存失败,抛出异常

 

 

hibernate连接池

建立数据库连接是比较消耗时间的,通常会采用数据库连接池来建立多天数据链接,并且持续使用,从而节约建立数据库链接所需要的时间,hibernate常用的数据库连接池是C3P0。具体配置不再细说

 

 

hibernate的注解

对于一个JavaBean类要建立一个JavaBean.hbm.xml是极其麻烦的,使用

package com.how2java.pojo;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "product_")
public class Product {
    int id;
    String name;
    float price;
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    @Column(name = "id")   
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    @Column(name = "name")
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Column(name = "price")
    public float getPrice() {
        return price;
    }
    public void setPrice(float price) {
        this.price = price;
    }
     
}

  

可以不用建立JavaBean.hbm,xml就可以;

 

 

 把Product的getCategory进行多对一映射

@ManyToOne
@JoinColumn(name="cid")
public Category getCategory() {
return category;
}
 


@ManyToOne 表示多对一关系
@JoinColumn(name="cid") 表示关系字段是cid
对比xml中的映射方式:

 
<many-to-one name="category" class="Category" column="cid" />

posted on 2020-02-11 10:15  妄想症T  阅读(167)  评论(0编辑  收藏  举报

导航