hibernate

简介

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。

特点

面向对象
不用写sql语句
简洁
要写dao实现

缺点

不能处理批量

hibernate快速入门

1、导包

hibernate_第1张图片
image.png

2、配置文件



    
        
        com.mysql.jdbc.Driver
        jdbc:mysql://localhost:3306/hibernate
        root
        
        
        org.hibernate.dialect.MySQL5InnoDBDialect
        
        true       
        
        true
        
        update     
        
        
    

注意:主配置文件名,一般默认是hibernate.cfg.xml,并且在src根目录中 上面的配置文件,可以参考etc文件夹下的配置文件

创建类

public class User {
    private int uid;
    private String username;
    private String password;
    //get/set方法 必须要有
}

3、映射文件

  

    
        
            
            
        
        
        
    

4、事务

Configuration configure = new Configuration().configure("hibernate.cfg.xml");
    SessionFactory factory = configure.buildSessionFactory();
    Session session = factory.openSession();// 获取连接
    // 开启事务
    Transaction tx = session.beginTransaction();
    User user = new User("黄蓉", "123");
    session.save(user);
    tx.commit();// 提交事务
    session.close();// 关闭连接
hibernate_第2张图片
image.png

sessioin查询api

save、delete、update

get 不支持延迟查询

load 延迟查询:如果使用了对象中非id的属性时才会发送sql语句

saveOrUpdate

瞬时态执行save(),游离态执行update()

merge

两个相同id的对象合并

实体类的三种状态

瞬时态:

无id,与session无关联,与数据库无关联

持久态:

有id,与session有关联,与数据库关联 持久态对象修改数据,会自动修改数据库的数据

游离态(离线):

有id,与session无关联,与数据库有关

hibernate_第3张图片
image.png

关联关系

多对一

多个Customer对应一个User

hibernate_第4张图片
image.png

一对多

一个User对应多个Customer

hibernate_第5张图片
image.png

多对多

hibernate_第6张图片
image.png

hibernate查询api

oid

就是根据对象的id查询,例如get()、load()

hql Query

// -----------------条件查询-------------------
    @Test
    public void test1() {
        String hql = "from User u where u.uid=1";
        Query query = session.createQuery(hql);
        User u = query.uniqueResult();
        System.out.println(u);
    }

    @Test
    public void test2() {
        String hql = "from User u where u.username='lisi' and u.password='123'";
        Query query = session.createQuery(hql);
        User u = query.uniqueResult();
        System.out.println(u);
    }

    // ---------------占位符条件查询------------------
    // 占位符条件查询 ?
    @Test
    public void test3() {
        String hql = "from User u where u.username=? and u.password=?";
        Query query = session.createQuery(hql);
        query.setParameter(0, "lisi");
        query.setParameter(1, "123");
        User u = query.uniqueResult();
        System.out.println(u);
    }

    // 命名占位符条件查询1 parameter
    @Test
    public void test4() {
        String hql = "from User where username=:username and password=:password";
        Query query = session.createQuery(hql);
        query.setParameter("username", "lisi");
        query.setParameter("password", "123");
        User u = query.uniqueResult();
        System.out.println(u);
    }

    // 命名占位符条件查询2 javabean
    @Test
    public void test5() {
        String hql = "from User where username=:username and password=:password";
        Query query = session.createQuery(hql);
        User user = new User("lisi", "123");
        query.setProperties(user);
        User u = query.uniqueResult();
        System.out.println(u);
    }

    // 命名占位符条件查询3 map,可以解决命名占位符与实际参数名不一样的问题
    @Test
    public void test6() {
        String hql = "from User where username=:user and password=:pwd";
        Query query = session.createQuery(hql);
        Map map = new HashMap<>();
        map.put("user", "lisi");
        map.put("pwd", "123");
        query.setProperties(map);
        User u = query.uniqueResult();
        System.out.println(u);
    }

    // 模糊查询
    @Test
    public void test7() {
        String hql = "from User where username like ?";
        Query query = session.createQuery(hql);
        query.setParameter(0, "%七%");
        List list = query.getResultList();
        System.out.println(list);
    }

    // 查询列表,并且排序
    @Test
    public void test8() {
        String hql = "from User order by password desc";
        Query query = session.createQuery(hql);
        List list = query.getResultList();
        System.out.println(list);
    }

    // 分页查询
    @Test
    public void test9() {
        String hql = "from User";
        Query query = session.createQuery(hql);
        query.setFirstResult(0);
        query.setMaxResults(3);
        List list = query.getResultList();
        System.out.println(list);
    }

    // 动态查询
    @Test
    public void test10() {
        User user = new User();
        user.setPassword("123");

        String hql = "from User where 1=1";
        StringBuffer sb = new StringBuffer(hql);

        if (user.getPassword() != null && user.getPassword() != "") {
            sb.append(" and password=:password");
        }

        Query query = session.createQuery(sb.toString());
        query.setProperties(user);

        List list = query.getResultList();
        System.out.println(list);
    }

    // --------------------连接------------------------
    // 内连接,封装成数组,对象数组 查询roleid=1的用户
    @Test
    public void test11() {
        String hql = "from User u inner join u.roleSet ro where ro.roleid=1";
        Query query = session.createQuery(hql);
        List list = query.getResultList();
        for (Object[] obj : list) {
            System.out.println(Arrays.toString(obj));
        }
    }

    // 迫切内连接,直接封装成对象 查询custid=1的用户
    @Test
    public void test12() {
        String hql = "from User u inner join fetch u.custSet c where c.custid=1";
        Query query = session.createQuery(hql);
        List list = query.getResultList();
        System.out.println(list.size());
        System.out.println(list.get(0) + ":" + list.get(0).getCustSet());
    }

    @Test
    public void test13() {
        String hql = "from User u where u.username='洪七公'";
        Query query = session.createQuery(hql);
        List list = query.list();
        System.out.println(list.size());
        System.out.println(list.get(0).getCustSet());
    }

    // -----------------投影查询--------------------

    // 投影查询 object[]
    @Test
    public void test14() {
        String hql = "select username,password from User u where u.uid=1";
        Query query = session.createQuery(hql);
        Object[] obj = query.uniqueResult();
        System.out.println(Arrays.toString(obj));
    }

    // 查询一个值的时候,只能使用Object,不能用数组
    @Test
    public void test15() {
        String hql = "select count(*) from User";
        Query query = session.createQuery(hql);
        Object obj = query.uniqueResult();
        System.out.println(obj);
    }

    // 投影查询 list集合
    @Test
    public void test16() {
        String hql = "select new list(username,password) from User u where u.uid=1";
        Query> query = session.createQuery(hql);
        List list = query.uniqueResult();
        System.out.println(list);
    }

    // 投影查询 map集合
    @Test
    public void test17() {
        String hql = "select new map(username,password) from User u where u.uid=1";
        Query> query = session.createQuery(hql);
        Map map = query.uniqueResult();
        System.out.println(map);
    }

    // 投影查询 自定义对象
    // 注意:new User(uid,username,password)会调用对应的构造方法,没有就会报错
    @Test
    public void test18() {
        String hql = "select new User(username,password) from User u where u.uid=1";
        Query query = session.createQuery(hql);
        User user = query.uniqueResult();
        System.out.println(user);
    }
 
 

qbc Citira

// 模糊查询
    @Test
    public void test2() {
        Criteria criteria = session.createCriteria(User.class)
                .add(Restrictions.like("username", "%七%"));
        List list = criteria.list();
        System.out.println(list);
    }

    // 多条件查询
    @Test
    public void test3() {
        Criteria criteria = session.createCriteria(User.class)
                .add(Restrictions.eq("username", "李四"))
                .add(Restrictions.eq("password", "123"));
        List list = criteria.list();
        System.out.println(list);
    }

    //排序
    @Test
    public void test4() {
        Criteria criteria = session.createCriteria(User.class)
                .addOrder(Order.desc("password"));//降序
        List list = criteria.list();
        System.out.println(list);
    }
    //分页
    @Test
    public void test5() {
        Criteria criteria = session.createCriteria(User.class)
                .setFirstResult(3)
                .setMaxResults(3);
        List list = criteria.list();
        System.out.println(list);
    }

    //---------------------投影查询---------------------

    //聚合函数 count()
    @Test
    public void test6(){
        Criteria criteria = session.createCriteria(User.class);
        criteria.setProjection(Projections.rowCount());//count()
        Object result = criteria.uniqueResult();
        System.out.println(result);
    }

    //分组计算
    @Test
    public void test7(){
        Criteria criteria = session.createCriteria(User.class);
        criteria.setProjection(Projections.projectionList()
                .add(Projections.rowCount())
                .add(Projections.groupProperty("password")));
        List list = criteria.list();
        for (Object[] objects : list) {
            System.out.println(Arrays.toString(objects));
        }
    }

    //选出部分字段
    @Test
    public void test8(){
        Criteria criteria = session.createCriteria(User.class);
        criteria.setProjection(Projections.projectionList()
                .add(Projections.property("username"))
                .add(Projections.property("password")));
        List list = criteria.list();
        for (Object[] objects : list) {
            System.out.println(Arrays.toString(objects));
        }
    }

hibernate缓存

一级缓存

第一次查找,去缓存中找,没有数据,从数据库获取,然后存入一级缓存,并且存入快照区;session没有关闭,并且执行第二次查找,先从一级缓存中获取。如果对象修改了数据,一级缓存中的数据也修改了,那么会将一级缓存和快照区的数据进行比对,如果不相同,就将数据存入数据库。

第一级别的缓存是 Session 级别的缓存,它是属于事务范围的缓存(session的一级缓存)

二级缓存

二级缓存属于SessionFactory级别的缓存,缓存的对象根据提供的实现类不同,放置的位置也不同,主要就是内存和硬盘中。二级缓存是缓存对象的Id,所以只有通过id查询的,二级缓存才能生效。

第二级别的缓存是 SessionFactory 级别的缓存,它是属于进程范围的缓存

二级缓存的实现有很多,我们使用ehcache来实现二级缓存

1、导包

            org.hibernate
            hibernate-ehcache
            5.0.12.Final
        

        
            net.sf.ehcache
            ehcache-core
            2.6.11
        
2、在spring-hibernate.xml中配置

true

true

org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
3、在resources根目录中添加ehcache.xml文件
  
      
    

    

    
      
    

    

    
    
    
    
    
    
    
    

4、在需要使用二级缓存的类上添加注解
//region:标示要使用的区域,不同的区域使用的缓存策略不一样,见上面第3点说明
//usage:指定使用的并非策略
@org.hibernate.annotations.Cache(region ="simple",usage = CacheConcurrencyStrategy.READ_ONLY)
ehcache的四种缓存并发策略如下:
read-write(读写型):

提供Read Committed事务隔离级别
在非集群的环境中适用
适用经常被读,很少修改的数据
可以防止脏读
更新缓存的时候会锁定缓存中的数据

nonstrict-read-write(非严格读写型):

适用极少被修改,偶尔允许脏读的数据(两个事务同时修改数据的情况很少见)
不保证缓存和数据库中数据的一致性
为缓存数据设置很短的过期时间,从而尽量避免脏读
不锁定缓存中的数据

read-only(只读型):

适用从来不会被修改的数据(如参考数据)
在此模式下,如果对数据进行更新操作,会有异常
事务隔离级别低,并发性能高
在集群环境中也能完美运作

5、测试
        AppInfo appInfo = appInfoService.findOneById(1);
        System.out.println(appInfo);

        AppInfo appInfo1 = appInfoService.findOneById(1);
        System.out.println(appInfo1);
注意:

1、list()只查询一级缓存,而iterator()会从二级缓存中查

2、list()方法返回的对象都是实体对象,而iterator()返回的是代理对象

查询缓存

Query Cache只是在特定的条件下才会发挥作用,而且要求相当严格:

完全相同的HQL重复执行。(注意,只有hql)
重复执行期间,Query Cache对应的数据表不能有数据变动(比如添、删、改操作)

绝大多数的查询并不能从查询缓存中受益,所以Hibernate默认是不进行查询缓存的。查询缓存适用于以下场合:

在应用程序运行时经常使用的查询语句(参数相同)
很少对与查询语句检索到的数据进行插入、删除或更新操作

Query query = session.createQuery(hql);     
query.setCacheable(true); //启用查询缓存  
query.setCacheRegion(“queryCacheRegion”); //设置查询缓存区域(数据过期策略)  
query.list();  

你可能感兴趣的:(hibernate)