• Hibernate笔记


    一、hibernate配置文件和映射

          配置文件:hibernate.cfg.xml

    <?xml version="1.0" encoding="GBK"?>  
    <!-- 指定Hibernate配置文件的DTD信息 -->  
    <!DOCTYPE hibernate-configuration PUBLIC  
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"  
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">  
    <!-- hibernate- configuration是连接配置文件的根元素 -->  
    <hibernate-configuration>  
        <session-factory>  
            <!-- 指定连接数据库所用的驱动 -->  
            <property name="connection.driver_class">com.mysql.jdbc.Driver</property>  
            <!-- 指定连接数据库的url,hibernate连接的数据库名 -->  
            <property name="connection.url">jdbc:mysql://localhost/数据库名</property>  
            <!-- 指定连接数据库的用户名 -->  
            <property name="connection.username">root</property>  
            <!-- 指定连接数据库的密码 -->  
            <property name="connection.password">32147</property>  
            <!-- 指定连接池里最大连接数 -->  
            <property name="hibernate.c3p0.max_size">20</property>  
            <!-- 指定连接池里最小连接数 -->  
            <property name="hibernate.c3p0.min_size">1</property>  
            <!-- 指定连接池里连接的超时时长 -->  
            <property name="hibernate.c3p0.timeout">5000</property>  
            <!-- 指定连接池里最大缓存多少个Statement对象 -->  
            <property name="hibernate.c3p0.max_statements">100</property>  
            <property name="hibernate.c3p0.idle_test_period">3000</property>  
            <property name="hibernate.c3p0.acquire_increment">2</property>  
            <property name="hibernate.c3p0.validate">true</property>  
            <!-- 指定数据库方言 -->  
            <property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>  
            <!-- 根据需要自动创建数据表 -->  
            <property name="hbm2ddl.auto">update</property>  
            <!-- 显示Hibernate持久化操作所生成的SQL -->  
            <property name="show_sql">true</property>  
            <!-- 将SQL脚本进行格式化后再输出 -->  
            <property name="hibernate.format_sql">true</property>  
            <!-- 罗列所有的映射文件 -->  
            <mapping resource="映射文件路径/News.hbm.xml"/>  
        </session-factory>  
    </hibernate-configuration>  
    View Code

         映射文件:

    <?xml version="1.0"?>  
    <!DOCTYPE hibernate-mapping PUBLIC   
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">      
    <!--   
        <hibernate-mapping>一般不去配置,采用默认即可。  
        schema:指定映射数据库的schema(模式/数据库),如果指定该属性,则表名会自动添加该schema前缀  
        package:指定包前缀 指定持久化类所在的包名 这样之后calss子元素中就不必使用全限定性的类名  
        default-cascade="none":默认的级联风格,表与表联动。  
        default-lazy="true":默认延迟加载  
     -->  
    <hibernate-mapping>  
        <!--   
            <class>:使用class元素定义一个持久化类。  
            name="cn.javass.user.vo.UserModel":持久化类的java全限定名;  
            table="tbl_user":对应数据库表名,默认持久化类名作为表名;  
            proxy:指定一个接口,在延迟装载时作为代理使用,也可在这里指定该类自己的名字。  
            mutable="true":默认为true,设置为false时则不可以被应用程序更新或删除,等价于所有<property>元素的update属性为false,表示整个实例不能被更新。  
            dynamic-insert="false":默认为false,动态修改那些有改变过的字段,而不用修改所有字段;  
            dynamic-update="false":默认为false,动态插入非空值字段;  
            select-before-update="false":默认为false,在修改之前先做一次查询,与用户的值进行对比,有变化都会真正更新;  
            optimistic-lock="version":默认为version(检查version/timestamp字段),取值:all(检查全部字段)、dirty(只检查修改过的字段);  
                                       none(不使用乐观锁定),此参数主要用来处理并发,每条值都有固定且唯一的版本,版本为最新时才能执行操作;  
            如果需要采用继承映射,则class元素下还会增加<subclass.../>元素等用于定义子类。  
         -->  
        <class name="cn.javass.user.vo.UserModel" table="tbl_user" >  
              
            <!--   
                <id>:定义了该属性到数据库表主键字段的映射。  
                type  指定该标识属性的数据类型,该类型可以是Hibernate的内建类型,也可以是java类型,如果是java类型则需要使用全限定类名(带包名)。该属性可选,如果没有指定类型, 则hibernate自行判断该标识属性数据类型。通常建议设定。  
                name="userId":标识属性的名字;  
                column="userId":表主键字段的名字,如果不填写与name一样;  
                  
             -->  
            <id name="userId">  
                <!-- <generator>:指定主键由什么生成,推荐使用uuid,assigned指用户手工填入。设定标识符生成器  
                适应代理主键的有:  
                    increment:有Hibernat自动以递增的方式生成标识符,每次增量1;  
                    identity:由底层数据库生成标识符,前提条件是底层数据库支持自动增长字段类型。(DB2,MYSQL)  
                    uuid:用128位的UUID算法生成字符串类型标识符。  
                适应自然主键:  
                    assigned:由java程序负责生成标识符,为了能让java应用程序设置OID,不能把setId()方法设置成private类型。  
                    让应用程序在save()之前为对象分配一个标识符。相当于不指定<generator.../>元素时所采用的默认策略。  
                    应当尽量避免自然主键  
                -->  
                <generator class="uuid"/>  
            </id>  
              
            <!--   
                <version/>:使用版本控制来处理并发,要开启optimistic-lock="version"和dynamic-update="true"。  
                name="version":持久化类的属性名,column="version":指定持有版本号的字段名;  
             -->  
            <version name="version" column="version"/>  
              
            <!--   
                <property>:为类定义一个持久化的javaBean风格的属性。  
                name="name":标识属性的名字,以小写字母开头;  
                column="name":表主键字段的名字,如果不填写与name一样;  
                update="true"/insert="true":默认为true,表示可以被更新或插入;  
                access="property/field":指定Hibernate访问持久化类属性的方式。默认property。property表示使用setter/getter方式。field表示运用java反射机制直接访问类的属性。  
                formula="{select。。。。。}":该属性指定一个SLQ表达式,指定该属性的值将根据表达式类计算,计算属性没有和它对应的数据列。  
                formula属性允许包含表达式:sum,average,max函数求值的结果。  
                例如:formula="(select avg(p.price) from Product P)"  
             -->  
            <property name="name" column="name" />  
            <property name="sex" column="sex"/>  
            <property name="age" column="age"/>  
              
            <!--   
                组件映射:把多个属性打包在一起当一个属性使用,用来把类的粒度变小。  
                <component name="属性,这里指对象">  
                    <property name="name1"></property>  
                    <property name="name2"></property>  
                </component>  
             -->  
               
             <!--   
                <join>:一个对象映射多个表,该元素必须放在所有<property>之后。  
                <join table="tbl_test:子表名">  
                    <key column="uuid:子表主键"></key>  
                <property name="name1:对象属性" column="name:子表字段"></property>  
             </join>  
              -->  
               
        </class>    
    </hibernate-mapping>  
    View Code

    二、hibernate查询  

         2.1  HQL查询方式            

     
    public class TestGetHql {  
        private static Configuration cfg = new Configuration().configure();  
        private static SessionFactory fac = cfg.buildSessionFactory();  
        private static Session son = fac.openSession();  
      
        // hql普通查询 Card为类名,不是表名,可以写全路径  
        public static void from() {  
            String hql = "from Card";  
            Query query = son.createQuery(hql);  
            List<Card> cards = query.list();  
            for (Card c : cards) {  
                System.out.println(c.getCardName());  
                System.out.println(c.getCreateDate());  
            }  
        }  
      
        // 条件查询 where  
        public static void where() {  
            String hql = "from Card where cardName='三国无双'";  
            Query query = son.createQuery(hql);  
            List<Card> cardss = query.list();  
            for (Card c : cardss) {  
                System.out.println(c.getCardName());  
                System.out.println(c.getCreateDate());  
            }  
        }  
      
        // 模糊查询 like  
        public static void like() {  
            String hql = "from Card where cardName like '%世%'";  
            Query query = son.createQuery(hql);  
            List<Card> cards = query.list();  
            for (Card c : cards) {  
                System.out.println(c.getCardName());  
                System.out.println(c.getCreateDate());  
            }  
        }  
      
        // 逻辑条件查询 >  
        public static void gt() {  
            String hql = "from Card c where c.createDate >'2011-08-08'";  
            Query query = son.createQuery(hql);  
            List<Card> cards = query.list();  
            for (Card c : cards) {  
                System.out.println(c.getCardName());  
                System.out.println(c.getCreateDate());  
            }  
        }  
      
        // 逻辑条件查询 between and 此处用了别名,省略了as关键字  
        public static void between() {  
            String hql = "from Card c where c.createDate between '2011-08-08' and '2022-11-11'";  
            Query query = son.createQuery(hql);  
            List<Card> cards = query.list();  
            for (Card c : cards) {  
                System.out.println(c.getCardName());  
                System.out.println(c.getCreateDate());  
            }  
        }  
      
        // 逻辑多条件查询and  
        public static void and() {  
            String hql = "from Card c where c.createDate between '2011-01-08' and '2022-11-11' and c.cardName like '%世%'";  
            Query query = son.createQuery(hql);  
            List<Card> cards = query.list();  
            for (Card c : cards) {  
                System.out.println(c.getCardName());  
                System.out.println(c.getCreateDate());  
            }  
        }  
      
        // update 更新  
        public static void update() {  
            String hql = "update Card as c set c.createDate='2011-03-03' where c.cardType.cardTypeId=3";  
            Query query = son.createQuery(hql);  
            int num = query.executeUpdate();  
            System.out.println(num + "行被更新。。。");  
        }  
      
        // delete删除  
        public static void delete() {  
            String hql = "delete from  Card as c where c.createDate='2011-03-04'";  
            Query query = son.createQuery(hql);  
            int num = query.executeUpdate();  
            System.out.println(num + "行被删除。。。");  
        }  
      
        // 单个属性查询  
        public static void simpleProperty() {  
            String hql = "select c.cardName from  Card as c where c.cardType.cardTypeId=1";  
            Query query = son.createQuery(hql);  
            List<String> name = query.list();  
            for (String s : name) {  
                System.out.println(s);  
            }  
        }  
      
        // 多个属性查询 其中cardTypeName直接通过card对象的cardType对象获得,省去了使用普通的sql语句必须多表连接查询的麻烦  
        public static void mulProperty() {  
            String hql = "select c.cardName,c.cardType.cardTypeName,c.createDate from  Card as c where c.cardType.cardTypeId=1";  
            Query query = son.createQuery(hql);  
            List<Object[]> obj = query.list();  
            for (Object[] o : obj) {  
                System.out.println(o[0] + "	" + o[1] + "	" + o[2]);  
            }  
        }  
      
        // 多个属性查询 面向对象方式  
        public static void orientedObject() {  
            String hql = "select new Card(c.cardName,c.createDate) from  Card as c";  
            Query query = son.createQuery(hql);  
            List<Card> cards = query.list();  
            for (Card c : cards) {  
                System.out.println(c.getCardName() + "	" + c.getCreateDate());  
            }  
        }  
      
        // 函数查询  
        public static void function() {  
            String hql = "select count(*),max(c.createDate) from  Card as c";  
            Query query = son.createQuery(hql);  
            List<Object[]> oo = query.list();  
            for (Object[] o : oo) {  
                System.out.println("总记录数:" + o[0] + "	最新日期为:" + o[1]);  
            }  
        }  
      
        // 排序  
        public static void orderBy() {  
            String hql = "from  Card as c order by c.createDate desc";  
            Query query = son.createQuery(hql);  
            List<Card> cards = query.list();  
            for (Card c : cards) {  
                System.out.println(c.getCardName() + "	" + c.getCreateDate());  
            }  
        }  
      
        // 分组  
        public static void groupBy() {  
            String hql = "from  Card as c group by c.cardType.cardTypeId";  
            Query query = son.createQuery(hql);  
            List<Card> cards = query.list();  
            for (Card c : cards) {  
                System.out.println(c.getCardName() + "	" + c.getCreateDate());  
            }  
        }  
      
        // 单个对象查询 呵呵,奇怪吧,对象可以查询出来  
        public static void simpleObject() {  
            String hql = "select c.cardType from  Card as c";  
            Query query = son.createQuery(hql);  
            query.setMaxResults(1);// 必须在查询之前指定,使其返回单个对象  
            CardType cardType1 = (CardType) query.uniqueResult();  
            System.out.println(cardType1.getCardTypeName() + "	"  
                    + cardType1.getCreateDate());  
        }  
      
        // 按照命令行参数 格式为: :参数名  
        public static void parameter() {  
            String hql = "select c.cardType from  Card as c where c.cardType.cardTypeId=:id";  
            Query query = son.createQuery(hql);  
            query.setParameter("id", 1);  
            query.setMaxResults(1);// 必须在查询之前指定,使其返回单个对象  
            CardType cardType = (CardType) query.uniqueResult();  
            System.out.println(cardType.getCardTypeName() + "	"  
                    + cardType.getCreateDate());  
        }  
      
        // 按照参数位置 从0开始  
        public static void parameterPosition() {  
            String hql = "select c.cardType from  Card as c where c.cardType.cardTypeId=?";  
            Query query = son.createQuery(hql);  
            query.setParameter(0, 1);  
            query.setMaxResults(1);// 必须在查询之前指定,使其返回单个对象  
            CardType cardType = (CardType) query.uniqueResult();  
            System.out.println(cardType.getCardTypeName() + "	"  
                    + cardType.getCreateDate());  
        }  
      
        // 多个参数  
        public static void mulParameter() {  
            String hql = "from  Card as c where c.cardType.cardTypeId in (3,2)";  
            Query query = son.createQuery(hql);  
            // query.setParameterList("id", new Object[]{1,2});  
            List<Card> cards = query.list();  
            for (Card o : cards) {  
                System.out.println(o.getCardName());  
            }  
        }  
      
        // inner join 查询结果为多个对象的集合  
        public static void innerJoin() {  
            String hql = "from  Card as c inner join c.cardType";  
            Query query = son.createQuery(hql);  
            List<Object[]> cards = query.list();  
            for (Object[] o : cards) {  
                System.out.println(((Card) o[0]).getCardName() + "	"  
                        + ((CardType) o[1]).getCreateDate());  
            }  
        }  
      
        // leftJoin 查询结果为多个对象的集合  
        public static void leftJoin() {  
            String hql = "from  CardType as c left join c.cards";  
            Query query = son.createQuery(hql);  
            List<Object[]> cards = query.list();  
            for (Object[] o : cards) {  
                // 由于保存卡片时在多的一方card进行操作,使用了级联。但手动插入的cardType可能没有相应的卡片  
                if (o[1] != null) {// 当卡片不为空时  
                    System.out.println(((CardType) o[0]).getCardTypeName() + "	"  
                            + ((Card) o[1]).getCardName());  
                } else {  
                    System.out.println(((CardType) o[0]).getCardTypeName()  
                            + "	没有相应的卡片");  
                }  
            }  
        }  
      
        // rightJoin 查询结果为多个对象的集合  
        public static void rightJoin() {  
            String hql = "from  CardType as c right join c.cards";  
            Query query = son.createQuery(hql);  
            List<Object[]> cards = query.list();  
            // 插入时保证了每张卡片的类型,所以此处不用判断卡片类型是否为空  
            for (Object[] o : cards) {  
                System.out.println(((CardType) o[0]).getCardTypeName() + "	"  
                        + ((Card) o[1]).getCardName());  
            }  
        }  
      
        // 使用子查询  
        public static void childSelect() {  
            String hql = "from  CardType as c where (select count(*) from c.cards)>0";  
            Query query = son.createQuery(hql);  
            List<CardType> cards = query.list();  
            for (CardType c : cards) {  
                System.out.println(c.getCardTypeName() + "	" + c.getCreateDate());  
            }  
        }  
      
        // 程序入口  
        public static void main(String[] args) {  
            // 测试方法  
            Transaction tr = son.beginTransaction();  
      
            // update();  
            mulParameter();  
            tr.commit();  
            son.close();  
            fac.close();  
        }  
    }  
    View Code

        2.2  Criteria查询

    1. 创建一个Criteria 实例 
    org.hibernate.Criteria接口表示特定持久类的一个查询。Session是 Criteria实例的工厂。 
    Criteria crit = sess.createCriteria(Cat.class); 
    crit.setMaxResults(50); 
    List cats = crit.list(); 
    
    2. 限制结果集内容 
    一个单独的查询条件是org.hibernate.criterion.Criterion 接口的一个实例。 
    
    org.hibernate.criterion.Restrictions类 定义了获得某些内置Criterion类型的工厂方法。 
    List cats = sess.createCriteria(Cat.class) 
    .add( Restrictions.like("name", "Fritz%") ) 
    .add( Restrictions.between("weight", minWeight, maxWeight) ) 
    .list(); 
    
    约束可以按逻辑分组。 
    
    List cats = sess.createCriteria(Cat.class) 
    .add( Restrictions.like("name", "Fritz%") ) 
    .add( Restrictions.or( 
      Restrictions.eq( "age", new Integer(0) ), 
      Restrictions.isNull("age") 
    ) ) 
    .list(); 
    
    List cats = sess.createCriteria(Cat.class) 
    .add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) ) 
    .add( Restrictions.disjunction() 
      .add( Restrictions.isNull("age") ) 
      .add( Restrictions.eq("age", new Integer(0) ) ) 
      .add( Restrictions.eq("age", new Integer(1) ) ) 
      .add( Restrictions.eq("age", new Integer(2) ) ) 
    ) ) 
    .list(); 
    
    Hibernate提供了相当多的内置criterion类型(Restrictions 子类), 但是尤其有用的是可以允许 
    
    你直接使用SQL。 
    
    List cats = sess.createCriteria(Cat.class) 
    .add( Restrictions.sql("lower({alias}.name) like lower(?)", "Fritz%", 
    
    Hibernate.STRING) ) 
    .list(); 
    
    {alias}占位符应当被替换为被查询实体的列别名。 
    Property实例是获得一个条件的另外一种途径。你可以通过调用Property.forName() 创建一个 
    
    Property。 
    
    Property age = Property.forName("age"); 
    List cats = sess.createCriteria(Cat.class) 
    .add( Restrictions.disjunction() 
      .add( age.isNull() ) 
      .add( age.eq( new Integer(0) ) ) 
      .add( age.eq( new Integer(1) ) ) 
      .add( age.eq( new Integer(2) ) ) 
    ) ) 
    .add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) ) 
    .list(); 
    
    3. 结果集排序 
    你可以使用org.hibernate.criterion.Order来为查询结果排序。 
    
    List cats = sess.createCriteria(Cat.class) 
    .add( Restrictions.like("name", "F%") 
    .addOrder( Order.asc("name") ) 
    .addOrder( Order.desc("age") ) 
    .setMaxResults(50) 
    .list(); 
    
    List cats = sess.createCriteria(Cat.class) 
    .add( Property.forName("name").like("F%") ) 
    .addOrder( Property.forName("name").asc() ) 
    .addOrder( Property.forName("age").desc() ) 
    .setMaxResults(50) 
    .list(); 
    
    4. 关联 
    你可以使用createCriteria()非常容易的在互相关联的实体间建立 约束。 
    
    List cats = sess.createCriteria(Cat.class) 
    .add( Restrictions.like("name", "F%") 
    .createCriteria("kittens") 
      .add( Restrictions.like("name", "F%") 
    .list(); 
    
    
    注意第二个 createCriteria()返回一个新的 Criteria实例,该实例引用kittens 集合中的元素。 
    接下来,替换形态在某些情况下也是很有用的。 
    
    List cats = sess.createCriteria(Cat.class) 
    .createAlias("kittens", "kt") 
    .createAlias("mate", "mt") 
    .add( Restrictions.eqProperty("kt.name", "mt.name") ) 
    .list(); 
    
    
    (createAlias()并不创建一个新的 Criteria实例。) 
    Cat实例所保存的之前两次查询所返回的kittens集合是 没有被条件预过滤的。如果你希望只获得 
    
    符合条件的kittens, 你必须使用returnMaps()。 
    
    List cats = sess.createCriteria(Cat.class) 
    .createCriteria("kittens", "kt") 
    .add( Restrictions.eq("name", "F%") ) 
    .returnMaps() 
    .list(); 
    Iterator iter = cats.iterator(); 
    while ( iter.hasNext() ) { 
    Map map = (Map) iter.next(); 
    Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS); 
    Cat kitten = (Cat) map.get("kt"); 
    } 
    
    5. 动态关联抓取 
    你可以使用setFetchMode()在运行时定义动态关联抓取的语义。 
    
    List cats = sess.createCriteria(Cat.class) 
    .add( Restrictions.like("name", "Fritz%") ) 
    .setFetchMode("mate", FetchMode.EAGER) 
    .setFetchMode("kittens", FetchMode.EAGER) 
    .list(); 
    
    这个查询可以通过外连接抓取mate和kittens。 
    
    6. 查询示例 
    org.hibernate.criterion.Example类允许你通过一个给定实例 构建一个条件查询。 
    
    Cat cat = new Cat(); 
    cat.setSex('F'); 
    cat.setColor(Color.BLACK); 
    List results = session.createCriteria(Cat.class) 
    .add( Example.create(cat) ) 
    .list(); 
    
    
    版本属性、标识符和关联被忽略。默认情况下值为null的属性将被排除。 
    可以自行调整Example使之更实用。 
    
    Example example = Example.create(cat) 
    .excludeZeroes()     //exclude zero valued properties 
    .excludeProperty("color") //exclude the property named "color" 
    .ignoreCase()       //perform case insensitive string comparisons 
    .enableLike();       //use like for string comparisons 
    List results = session.createCriteria(Cat.class) 
    .add(example) 
    .list(); 
    
    
    甚至可以使用examples在关联对象上放置条件。 
    
    List results = session.createCriteria(Cat.class) 
    .add( Example.create(cat) ) 
    .createCriteria("mate") 
      .add( Example.create( cat.getMate() ) ) 
    .list(); 
    
    
    7. 投影(Projections)、聚合(aggregation)和分组(grouping) 
    org.hibernate.criterion.Projections是 Projection 的实例工厂。我们通过调用 
    
    setProjection()应用投影到一个查询。 
    
    List results = session.createCriteria(Cat.class) 
    .setProjection( Projections.rowCount() ) 
    .add( Restrictions.eq("color", Color.BLACK) ) 
    .list(); 
    
    List results = session.createCriteria(Cat.class) 
    .setProjection( Projections.projectionList() 
      .add( Projections.rowCount() ) 
      .add( Projections.avg("weight") ) 
      .add( Projections.max("weight") ) 
      .add( Projections.groupProperty("color") ) 
    ) 
    .list(); 
    
    
    在一个条件查询中没有必要显式的使用 "group by" 。某些投影类型就是被定义为 分组投影,他 
    
    们也出现在SQL的group by子句中。 
    
    可以选择把一个别名指派给一个投影,这样可以使投影值被约束或排序所引用。下面是两种不同的 
    
    实现方式: 
    
    List results = session.createCriteria(Cat.class) 
    .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) ) 
    .addOrder( Order.asc("colr") ) 
    .list(); 
    
    
    
    List results = session.createCriteria(Cat.class) 
    .setProjection( Projections.groupProperty("color").as("colr") ) 
    .addOrder( Order.asc("colr") ) 
    .list(); 
    
    alias()和as()方法简便的将一个投影实例包装到另外一个 别名的Projection实例中。简而言之, 
    
    当你添加一个投影到一个投影列表中时 你可以为它指定一个别名: 
    
    List results = session.createCriteria(Cat.class) 
    .setProjection( Projections.projectionList() 
      .add( Projections.rowCount(), "catCountByColor" ) 
      .add( Projections.avg("weight"), "avgWeight" ) 
      .add( Projections.max("weight"), "maxWeight" ) 
      .add( Projections.groupProperty("color"), "color" ) 
    ) 
    .addOrder( Order.desc("catCountByColor") ) 
    .addOrder( Order.desc("avgWeight") ) 
    .list(); 
    
    
    List results = session.createCriteria(Domestic.class, "cat") 
    .createAlias("kittens", "kit") 
    .setProjection( Projections.projectionList() 
      .add( Projections.property("cat.name"), "catName" ) 
      .add( Projections.property("kit.name"), "kitName" ) 
    ) 
    .addOrder( Order.asc("catName") ) 
    .addOrder( Order.asc("kitName") ) 
    .list(); 
    
    
    也可以使用Property.forName()来表示投影: 
    
    List results = session.createCriteria(Cat.class) 
    .setProjection( Property.forName("name") ) 
    .add( Property.forName("color").eq(Color.BLACK) ) 
    .list(); 
    List results = session.createCriteria(Cat.class) 
    .setProjection( Projections.projectionList() 
      .add( Projections.rowCount().as("catCountByColor") ) 
      .add( Property.forName("weight").avg().as("avgWeight") ) 
      .add( Property.forName("weight").max().as("maxWeight") ) 
      .add( Property.forName("color").group().as("color" ) 
    ) 
    .addOrder( Order.desc("catCountByColor") ) 
    .addOrder( Order.desc("avgWeight") ) 
    .list(); 
    
    
    8. 离线(detached)查询和子查询 
    DetachedCriteria类使你在一个session范围之外创建一个查询,并且可以使用任意的 Session来 
    
    执行它。 
    
    DetachedCriteria query = DetachedCriteria.forClass(Cat.class) 
    .add( Property.forName("sex").eq('F') ); 
    //创建一个Session 
    Session session = .; 
    Transaction txn = session.beginTransaction(); 
    List results = query.getExecutableCriteria(session).setMaxResults(100).list(); 
    txn.commit(); 
    session.close(); 
    
    
    DetachedCriteria也可以用以表示子查询。条件实例包含子查询可以通过 Subqueries或者 
    Property获得。 
    
    DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class) 
    .setProjection( Property.forName("weight").avg() ); 
    session.createCriteria(Cat.class) 
    .add( Property.forName("weight).gt(avgWeight) ) 
    .list(); 
    DetachedCriteria weights = DetachedCriteria.forClass(Cat.class) 
    .setProjection( Property.forName("weight") ); 
    session.createCriteria(Cat.class) 
    .add( Subqueries.geAll("weight", weights) ) 
    .list(); 
    
    相互关联的子查询也是有可能的: 
    
    DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2") 
    .setProjection( Property.forName("weight").avg() ) 
    .add( Property.forName("cat2.sex").eqProperty("cat.sex") ); 
    session.createCriteria(Cat.class, "cat") 
    .add( Property.forName("weight).gt(avgWeightForSex) ) 
    .list(); 
    
    
    补充:
    criteria.add(Expression.eq("status",new Integer(status))); 
    criteria.add(Expression.in("status", optParm.getQueryStatus()));
    View Code

       2.3  SQL查询

    A.获取所有的Order对象,得到一个List集合
    public void list(){
        String sql = "select * from orders";
        NativeQuery<Order> query = session.createNativeQuery(sql, Order.class);
        List<Order> list = query.getResultList();
        for(Order o : list){
             System.out.println(o.getId() + "::" + o.getOrderId());
        }
    }
    
    B.获取Order的分页数据,得到一个List集合
    /**
     * 虽然为原生的SQL查询,但是依然可以使用setFirstResult()和setMaxResults()方法。从而屏蔽了
     * 底层数据库的差异性。
     */
    @Test
    public void pageList(){
        String sql = "select * from orders";
        //setFirstResult()从0开始
        Query<Order> query = session.createNativeQuery(sql, Order.class).setFirstResult(1).setMaxResults(4);
        List<Order> list = query.getResultList();
        for(Order o : list){
             System.out.println(o.getId());
        }
    }
    
    C.多条件查询,返回List集合(第一种形式:索引占位符)
    
    @Test
    public void multiCretiera(){
        String sql = "select * from orders where create_time between ? and ? and order_id like ?";
        Query<Order> query = session.createNativeQuery(sql, Order.class);
        String beginDateStr = "2016-07-26 00:00:00";
        String endDateStr = "2016-07-28 23:59:59";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        Date beginDate = null;
        Date endDate = null;
        try {
             beginDate = sdf.parse(beginDateStr);
             endDate = sdf.parse(endDateStr);
        } catch (ParseException e) {
             e.printStackTrace();
        }
        //分页从0开始
        query.setParameter(0, beginDate).setParameter(1, endDate).setParameter(2, "%D%").setFirstResult(0).setMaxResults(1);
        List<Order> list = query.getResultList();
        for(Order o : list){
             System.out.println(o.getOrderId() + "::" + o.getCreateTime());
        }
    }
    
    D.多条件查询,返回List集合(第二种形式:命名占位符)
    @Test
    public void multiCretiera1(){
        String sql = "select * from orders where order_id like :orderId and create_time between :beginDate and :endDate";
        Query<Order> query = session.createNativeQuery(sql, Order.class);
        String beginDateStr = "2016-07-26 00:00:00";
        String endDateStr = "2016-07-28 23:59:59";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        Date beginDate = null;
        Date endDate = null;
        try {
             beginDate = sdf.parse(beginDateStr);
             endDate = sdf.parse(endDateStr);
        } catch (ParseException e) {
             e.printStackTrace();
        }
        query.setParameter("orderId", "%D%").setParameter("beginDate", beginDate).setParameter("endDate", endDate);
        List<Order> list = query.getResultList();
        for(Order o : list){
             System.out.println(o.getId() + "::" + o.getOrderId());
        }
    }
    
    E.大于条件的查询,使用索引占位符
    @Test
    public void gt(){
        String sql = "select * from orders where id > ?";
        Query<Order> query = session.createNativeQuery(sql, Order.class).setParameter(0, 3);
        List<Order> list = query.getResultList();
        for(Order o : list){
            System.out.println(o.getId() + "::" + o.getOrderId());
        }
    }
    
    F.删除操作
    @Test
    public void delete(){
        String sql = "delete from orders where id in (:idList)"; 
        Transaction tx = session.beginTransaction();
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        Query<?> query = session.createNativeQuery(sql).setParameter("idList", list);
        int i = query.executeUpdate();
        System.out.println(i);
        tx.commit();
        session.close();
    }
    
    G.获取某一列的值
    @Test
    public void singleValue(){
        String sql = "select order_id from orders";
        Query<String> query = session.createNativeQuery(sql);
        List<String> list = query.getResultList();
        for(String str : list){
            System.out.println(str);
        }
    }
    
     H.获取关联对象的结果集
    @Test
    public void getCustomer(){
        String sql = "select c.* from orders o join customer c on o.customer_id = c.id where c.id = 8";
        Query<Customer> query = session.createNativeQuery(sql, Customer.class);
        List<Customer> list = query.getResultList();
        for(Customer o : list){
            System.out.println(o.getId() + ";;");
        }
    }
    
    I.多列数据的查询
    @Test
    public void getObjectArray(){
        String sql = "select c.name, c.phone_number, o.order_id, o.create_time from orders o join customer c on o.customer_id = c.id";
        Query<Object[]> query = session.createNativeQuery(sql);
        List<Object[]> list = query.getResultList();
        for(Object[] o : list){
             System.out.println(o[0] + ";;" + o[1] + ";;" + o[2]);
        }
    }
    
    J.函数查询
    @Test
    public void functionQuery(){
        String sql = "select max(id), count(*) from orders";
        Query<Object[]> query = session.createNativeQuery(sql);
        Object[] obj = query.getSingleResult();
        System.out.println(obj[0] + "::" + obj[1]);
    }
    
     K.排序
    @Test
    public void descQuery(){
        String sql = "select * from orders order by id desc";
        Query<Order> query = session.createNativeQuery(sql, Order.class);
        List<Order> list = query.getResultList();
        for(Order o : list){
            System.out.println(o.getId() + "::" + o.getOrderId());
        }
    }
    
    L.右连接
    @Test
    public void rightJoin(){
        String sql = "select c.* from orders o right join customer c on o.customer_id = c.id";
        Query<Customer> query = session.createNativeQuery(sql, Customer.class);
        List<Customer> list = query.getResultList();
        for(Customer c : list){
            System.out.println(c.getId());
        }
    }
    View Code

    三、 持久化对象

      transient(瞬时态):尚未与Session关联对象,失去引用的话,就会被JVM回收。一般就是直接New创建的对象。
      persistent(持久态):已经与当前session产生关联,并且相关联的session没有关闭,并且事务尚未提交。
      detached(脱管态):存在持久化OID,但没有与当前session关联,脱管状态改变hibernate不能检测到。

            Session session = HibernateUtils.openSession();  
            // 开启事务  
            Transaction transaction = session.beginTransaction();  
            Book book = new Book(); // 瞬时态(没有OID,未与Session关联)  
            book.setName("hibernate精通");  
            book.setPrice(56d);  
    
            session.save(book);// 持久态(具有OID,与Session关联)  
      
            // 提交事务,关闭Session  
            transaction.commit();  
            session.close();  
            System.out.println(book.getId()); // 脱管态(具有 OID,与Session断开关联) 

    四、hibernate一级缓存

     hibernate向一级缓存放入数据时,同时保存快照数据,当修改一级缓存的时候,在flush操作时,对比缓存和快照,如果不一致,自动更新。

    一级缓存的管理:

    4.1.flush  修改一级缓存数据,针对内存操作,需要在session执行flush操作时,将缓存变化同步在数据库,而只有在缓存数据与快照区不一致的时候,才会生成update语句。

    @Test  
        public void fun7() {  
            // 通过工具类获取session值  
            Session session = HibernateUtils.getSession();  
            // 启动事务操作  
            session.beginTransaction();  
      
            // session.setFlushMode(FlushMode.MANUAL);  
      
            // 通过ID从数据库中获取值,此时会产生快照  
            Book book1 = (Book) session.get(Book.class, 1);  
            // 修改属性值  
            book1.setName("struts璇﹁В");  
            // 手动flush,刷新缓存到数据库,此时只是生成SQL语句,但是数据库中并没有发生变化,只有commit后,数据库才会发生相应的变化。  
            session.flush();  
            // 手动提交事务  
            session.getTransaction().commit();  
            // 关闭session的资源  
            session.close();  
        }
    View Code

    4.2.clear  清处所有对象的一级缓存,对对象所做的修改,全部都没有了,跟当初的快照一样。

    public void fun7() {  
            // 通过工具类获取session值  
            Session session = HibernateUtils.getSession();  
            // 启动事务操作  
            session.beginTransaction();  
      
            // session.setFlushMode(FlushMode.MANUAL);  
      
            // 通过ID从数据库中获取值,此时会产生快照  
            Book book1 = (Book) session.get(Book.class, 1);  
            // 修改属性值  
            book1.setName("struts璇﹁В");  
            //清除一级缓存操作,此时当作事务提交的时候,数据库中并没有发生任何的变化  
            session.clear();  
            // 手动提交事务  
            session.getTransaction().commit();  
            // 关闭session的资源  
            session.close();  
        }  
    View Code

    4.3.evict  清除一级缓存指定对象

    @Test  
        public void fun5() {  
              
            Session session = HibernateUtils.getSession();  
              
            session.beginTransaction();  
      
            //当执行一次操作后,会把对象放置到Session缓存中  
            Book book1 = (Book) session.get(Book.class, 1);  
            Book book2 = (Book) session.get(Book.class, 2);  
      
      
      
            session.evict(book2); // 从缓存中清楚book2对象所做的修改  
            // 当再次执行操作时,book2还会发出SQL语句操作  
            Book book11 = (Book) session.get(Book.class, 1);   
            Book book22 = (Book) session.get(Book.class, 2);  
      
            // 手动提交事务  
            session.getTransaction().commit();  
            // 关闭资源  
            session.close();  
        }  
    View Code

    4.4.refresh 重新查询数据库,更新快照和一级缓存

    @Test  
        public void fun6() {  
              
            Session session = HibernateUtils.getSession();  
              
            session.beginTransaction();  
      
            // 从数据库中查询book,并放置到Session缓存中一份  
              
            Book book1 = (Book) session.get(Book.class, 1);   
            //修改缓存对象的值  
            book1.setName("spring璇﹁В");   
      
            //又进行了一次查询操作,此时把快照中的数据与数据库一致  
            session.refresh(book1);  
      
            System.out.println(book1);  
      
            // 4.鎻愪氦  
            session.getTransaction().commit();  
            // 5.閲婃斁璧勬簮  
            session.close();  
        }
    View Code

     4.5.Session手动控制缓存

     在hibernate中也为 我们提供了手动控制缓存的机制,具体如下
     Always:每次查询时,session都会flush;
     Auto:有些查询时,session会默认flush,例如commit。session.flush;
     Commit:在事务提交的时候;
     Manual:只有手动调用sessionflush才会刷出;

    public void fun7() {  
            // 通过工具类获取session值  
            Session session = HibernateUtils.getSession();  
            // 启动事务操作  
            session.beginTransaction();  
      
             session.setFlushMode(FlushMode.MANUAL);  
      
            // 通过ID从数据库中获取值,此时会产生快照  
            Book book1 = (Book) session.get(Book.class, 1);  
            // 修改属性值  
            book1.setName("struts璇﹁В");  
            //因为上面开启了,手动提交缓存,所以只有手动提交,才能同步到数据库操作  
            session.flush();  
            // 手动提交事务  
            session.getTransaction().commit();  
            // 关闭session的资源  
            session.close();  
        }  
    View Code

    五、hibernate二级缓存

    * 二级缓存也分为了两种
    内置缓存:Hibernate自带的,不可卸载,通常在Hibernate的初始化阶段,Hibernate会把映射元数据和预定义的SQL语句放置到SessionFactory的缓存中。该内置缓存是只读的。
    外置缓存:通常说的二级缓存也就是外置缓存,在默认情况下SessionFactory不会启用这个缓存插件,外置缓存中的数据是数据库数据的复制,外置缓存的物理介质可以是内存或者硬盘

    * 并发访问策略

     

    transactional

    (事务型)


    仅在受管理的环境中适用

    提供Repeatable Read事务隔离级别

    适用经常被读,很少修改的数据

    可以防止脏读和不可重复读的并发问题

    缓存支持事务,发生异常的时候,缓存也能够回滚

    read-write

    (读写型)

    提供Read Committed事务隔离级别

    在非集群的环境中适用

    适用经常被读,很少修改的数据

    可以防止脏读

    更新缓存的时候会锁定缓存中的数据

    nonstrict-read-write

    (非严格读写型)

    适用极少被修改,偶尔允许脏读的数据(两个事务同时修改数据的情况很少见)

    不保证缓存和数据库中数据的一致性

    为缓存数据设置很短的过期时间,从而尽量避免脏读

    不锁定缓存中的数据

    read-only

    (只读型)

    适用从来不会被修改的数据(如参考数据)

    在此模式下,如果对数据进行更新操作,会有异常

    事务隔离级别低,并发性能高

    在集群环境中也能完美运作


    分析:通过上述表格分析如下:适合放入二级缓存中数据,很少被修改,不是很重要的数据,允许出现偶尔的并发问题,不适合放入二级缓存中的数据,经常被修改,财务数据,绝对不允许出现并发问题,与其他应用数据共享的数据。

    * 二级缓存的配置

    1.hibernate支持的缓存插件

      •EHCache: 可作为进程范围内的缓存,存放数据的物理介质可以是内存或硬盘,对Hibernate的查询缓存提供了支持

      •OpenSymphony`:可作为进程范围内的缓存,存放数据的物理介质可以是内存或硬盘,提供了丰富的缓存数据过期策略,对Hibernate的查询缓存提供了支持

      •SwarmCache:可作为集群范围内的缓存,但不支持Hibernate的查询缓存

      •JBossCache:可作为集群范围内的缓存,支持Hibernate的查询缓存

      四种缓存插件支持的并发范围策略如下图

    2.二级缓存使用

    2.1 拷贝jar包   如要第三方的jar包ehcache-1.5.0.jar,并且依赖于依赖backport-util-concurrent 和 commons-logging
    2.2 在hibernate.cfg.xml中开启二级缓存<propertyname="hibernate.cache.use_second_level_cache">true</property>
    2.3 配置二级缓存技术提供商<propertyname="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
    2.4 配置缓存数据对象并发策略

         在hbm文件中配置:

    <class name="cn.itcast.domain.Customer" table="customers" catalog="hibernate3day4" >  
                    <!-- 类级别缓存 -->  
                    <cache usage="read-write"/>  
                    <set name="orders" cascade="all-delete-orphan" inverse="true" >  
                        <!-- 关联集合级别缓存 -->  
                        <cache usage="read-write"/>     
                    </set>  
    </class>  

        在cgf文件中配置:

    <!-- 类级别缓存 -->  
    <class-cache usage="read-write" class="cn.itcast.domain.Customer"/>  
    <class-cache usage="read-write" class="cn.itcast.domain.Order"/>  
    <!-- 集合缓存 -->  
    <collection-cache usage="read-write" collection="cn.itcast.domain.Customer.orders"/>  

    2.5 添加二级缓存配置文件

     在src中配置ehcache.xml,将ehcache.jar包中的ehcache-failsafe.xml 改名 ehcache.xml 放入 src

    ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">  
      
        <diskStore path="java.io.tmpdir"/> 配置二级缓存硬盘临时目录位置   
             <defaultCache    
                maxElementsInMemory="10000" // 内存中最大对象数量 ,超过数量,数据会被缓存到硬盘   
                eternal="false"  
                timeToIdleSeconds="120" // 是否缓存为永久性 false 不永久  
                timeToLiveSeconds="120" // 存活时间,对象不管是否使用,到了时间回收  
                overflowToDisk="true" // 是否可以缓存到硬盘  
                maxElementsOnDisk="10000000" // 硬盘缓存最大对象数量   
                // 当jvm结束时是否持久化对象 true false 默认是false  
                diskExpiryThreadIntervalSeconds="120"  // 指定专门用于清除过期对象的监听线程的轮询时间   
                memoryStoreEvictionPolicy="LRU"   
      
                />  
      
    </ehcache>  
    View Code

    2.6 测试

    @Test  
        public void fun1() {  
      
            Session s1 = HibernateUtils.getSession();  
            s1.beginTransaction();  
            Customer c1 = (Customer) s1.get(Customer.class, 1); // 从数据库中加载数据  
            System.out.println(c1.getName());//此时才会发出SQL语句  
            s1.getTransaction().commit();  
            s1.close(); // 关闭session级别的一级缓存  
      
            Session s2 = HibernateUtils.getSession();  
            s2.beginTransaction();  
            Customer c2 = (Customer) s2.get(Customer.class, 1); // 因为有了二级缓存的存在,直接从二级缓存中取出即可  
            System.out.println(c2.getName());  
      
            Customer c3 = (Customer) s2.get(Customer.class, 1); //从二级缓存中取出  
            System.out.println(c3.getName());  
      
            s2.getTransaction().commit();  
            s2.close();  
      
        }  
    View Code

     

  • 相关阅读:
    轮播效果
    获取用户请求过来的URL
    前端框架——AmazeUI学习
    评论功能——多说插件学习
    SqlServer中——查找杀死阻塞进程
    Java 时区(转)
    大型网站技术演进的思考(转)
    elasticsearch threadpool
    UML 类图
    elasticsearch No node available
  • 原文地址:https://www.cnblogs.com/java-oracle/p/7761778.html
Copyright © 2020-2023  润新知