hibernate

作者: 奋斗的磊哥 | 来源:发表于2017-10-25 20:56 被阅读0次

    简介

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

    特点

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

    缺点

    不能处理批量

    hibernate快速入门

    1、导包

    image.png

    2、配置文件

    <!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://localhost:3306/hibernate</property>
            <property name="hibernate.connection.username">root</property>
            <property name="hibernate.connection.password"></property>
            <!-- SQL 方言 ,注意使用MySQLInnoDBDialect,才可以使用Innodb引擎-->
            <property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
            <!-- 打印出sql -->
            <property name="show_sql">true</property>       
            <!-- 格式化sql -->
            <property name="format_sql">true</property>
            <!-- 有表更新表,没有表自动创建表 -->
            <property name="hbm2ddl.auto">update</property>     
            <!-- 加载映射文件 -->
            <mapping resource="User.hbm.xml"/>
        </session-factory>
    </hibernate-configuration>
    
    注意:主配置文件名,一般默认是hibernate.cfg.xml,并且在src根目录中 上面的配置文件,可以参考etc文件夹下的配置文件

    创建类

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

    3、映射文件

    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">  
    <hibernate-mapping>
        <class name="com.hibernate.entity.User" table="user">
            <id name="uid" column="uid">
                <!-- 使用数据库默认的生成主键的方案 -->
                <generator class="native"/>
            </id>
            <property name="username" column="username"/>
            <property name="password" column="password"/>
        </class>
    </hibernate-mapping>
    

    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();// 关闭连接
    
    image.png

    sessioin查询api

    save、delete、update

    get 不支持延迟查询

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

    saveOrUpdate

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

    merge

    两个相同id的对象合并

    实体类的三种状态

    瞬时态:

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

    持久态:

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

    游离态(离线):

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

    image.png

    关联关系

    多对一

    多个Customer对应一个User

    image.png

    一对多

    一个User对应多个Customer

    image.png

    多对多

    image.png

    hibernate查询api

    oid

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

    hql Query

    // -----------------条件查询-------------------
        @Test
        public void test1() {
            String hql = "from User u where u.uid=1";
            Query<User> 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<User> 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<User> 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<User> 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<User> 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<User> query = session.createQuery(hql);
            Map<String, String> 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<User> query = session.createQuery(hql);
            query.setParameter(0, "%七%");
            List<User> list = query.getResultList();
            System.out.println(list);
        }
    
        // 查询列表,并且排序
        @Test
        public void test8() {
            String hql = "from User order by password desc";
            Query<User> query = session.createQuery(hql);
            List<User> list = query.getResultList();
            System.out.println(list);
        }
    
        // 分页查询
        @Test
        public void test9() {
            String hql = "from User";
            Query<User> query = session.createQuery(hql);
            query.setFirstResult(0);
            query.setMaxResults(3);
            List<User> 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<User> query = session.createQuery(sb.toString());
            query.setProperties(user);
    
            List<User> 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<Object[]> query = session.createQuery(hql);
            List<Object[]> 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<User> query = session.createQuery(hql);
            List<User> 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<User> query = session.createQuery(hql);
            List<User> 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<Object[]> 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<Object> 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<List<String>> query = session.createQuery(hql);
            List<String> 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<Map<String, String>> query = session.createQuery(hql);
            Map<String, String> 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<User> 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<User> 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<User> list = criteria.list();
            System.out.println(list);
        }
    
        //排序
        @Test
        public void test4() {
            Criteria criteria = session.createCriteria(User.class)
                    .addOrder(Order.desc("password"));//降序
            List<User> list = criteria.list();
            System.out.println(list);
        }
        //分页
        @Test
        public void test5() {
            Criteria criteria = session.createCriteria(User.class)
                    .setFirstResult(3)
                    .setMaxResults(3);
            List<User> 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<Object[]> 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<Object[]> list = criteria.list();
            for (Object[] objects : list) {
                System.out.println(Arrays.toString(objects));
            }
        }
    

    hibernate缓存

    一级缓存

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

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

    二级缓存

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

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

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

    1、导包
    <dependency>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-ehcache</artifactId>
                <version>5.0.12.Final</version>
            </dependency>
    
            <dependency>
                <groupId>net.sf.ehcache</groupId>
                <artifactId>ehcache-core</artifactId>
                <version>2.6.11</version>
            </dependency>
    
    2、在spring-hibernate.xml中配置
    <!-- 开启二级缓存:根据id来查询 -->
    <prop key="hibernate.cache.use_second_level_cache">true</prop>
    <!-- 开启查询缓存:根据非id来查询,需要在query中设置setCacheable(true) -->
    <prop key="hibernate.cache.use_query_cache">true</prop>
    <!-- 高速缓存提供程序 -->
    <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</prop>
    
    3、在resources根目录中添加ehcache.xml文件
    <ehcache>  
          <!--
          指定二级缓存存放在磁盘上的位置,可以使用磁盘目录
            也可以使用Java System Property目录
            user.home是用户目录
            user.dir是用户当前工作目录
            java.io.tmpdir是默认临时文件路径
          -->
        <diskStore path="java.io.tmpdir/cache"/>
    
        <!-- ehcache将缓存分为多个不同的区域,不同的区域可以设置不同的缓存策略 -->
    
        <!--缓存策略:
            name:Cache的唯一标识。
            maxElementsInMemory:内存中最大缓存对象数。
            eternal:Element是否永久有效,一旦设置true,timeout将不起作用。
            timeToIdleSeconds:设置Element在失效前的允许闲置时间。仅当element不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
            timeToLiveSeconds:设置Element在失效前允许存活时间。最大时间介于创建时间和失效时间之间。仅当element不是永久有效时使用,默认是0.,也就是element存活时间无穷大。
            overflowToDisk:配置此属性,当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中。
            maxElementsOnDisk:磁盘中最大缓存对象数,若是0表示无穷大。
            memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略
            去清理缓存中的内容。默认策略是LRU(最近最少使用),你也可以设置为FIFO(先进先出)或是LFU(较少使用) -->
          
        <defaultCache
                maxElementsInMemory="10000"
                eternal="false"
                timeToIdleSeconds="120"
                timeToLiveSeconds="120"
                overflowToDisk="true"
        />
    
        <cache name="simple"
               maxElementsInMemory="1000"
               eternal="true"
               timeToIdleSeconds="0"
               timeToLiveSeconds="0"
               overflowToDisk="false"
        />
    
        <!--可以给每个实体类指定一个配置文件,通过name属性指定,要使用类的全名-->
        <!--<cache name="com.study.entity.User"-->
        <!--maxElementsInMemory="10000"-->
        <!--eternal="false"-->
        <!--timeToIdleSeconds="300"-->
        <!--timeToLiveSeconds="600"-->
        <!--overflowToDisk="true"-->
        <!--/>-->
    </ehcache>
    
    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

          本文链接:https://www.haomeiwen.com/subject/mwscpxtx.html