zoukankan      html  css  js  c++  java
  • Hibernate

    Hibernate九阴真经

    一、导入jar包。

    二、创建实体类(javabean)

    *hibernate 要求实体类中必须有一个属性是唯一的

    *使用hibernate不需要我们自己手动创建数据库表,hibernate会帮我们把表创建

    三、配置实体类与数据库表的对应关系(ORM映射 )

    1、创建xml格式的配置文件

    映射配置文件和名称没有固定要求,建议:实体类所在包里面创建,实体类名称.xml

    2、配置是xml格式,在配置文件中首先引入xml约束

    学过约束dtd/schema,在hibernate中都是用dtd;

    3、配置映射关系

    <hibernate-mapping>

           <class name=”实体类全路径”  table=”数据库表名称”>配置表与对象的对应关系

      <id name=”实体类的唯一属性” column=”数据库表中的对应列名”>

      <generator class=”native”></generator>配置自增长属性

    </id>

    <property name=”实体类属性” column=”数据库表列名”></property>注意属性名与列名要一一对应,必须相同名,column可以省略默认与属性名一样;type=”表中字段类型varchar等不写默认与属性类型相同”;

    <property name=”实体类属性” column=”数据库表列名”></property>

    ……

    </class>

    </hibernate-mapping>

    四、创建hibernate核心配置文件

    1、位置:必须在src下

    名称:固定hibernate.cfg.xml

    2、引入约束

    3、hibernate操作过程中,只会加载核心配置文件,其他配置文件不会加载

          (1)配置数据库信息

          (2)配置hibernate信息

          (3)把映射文件放到核心配置文件中

    <hibernate-configuration>

           <session-factory>

      配置数据库信息(必须)

    <property name=”hibernate.connection.diver.class”>com.mysql.jdbc.Driver</property>

    <property name=”hibernate.connection.url”>jdbc:mysql:///hibernate_01</property>

    <property name=”hibernate.connection.username”>root</property>

    <property name=”hibernate.connection.password”>123</property>

    ……(配置数据库四大参数)

      配置hibernate信息(可选)

    <property name=”hibernate.show_sql”>true</property> 输出底层sql语句

    <property name=”hibernate.formate_sql”>true</property>输出sql语句格式

    <property name=”hibernate.hbm2ddl.auto”>update</property>自动创建表,update:有则更新,无则创建;

    <property name=”hibernate.dialect”>org.hibernate.dialect.MySQLDialect</property>配置数据库方言,例如在mysql中使用limit/oracle中使用rownum进行分页

      把映射文件放到核心配置文件中(必须)

    <mapping resource=”映射配置文件的全路径”/>

    </session-factory>

    </hibernate-configuration>

    五、代码逻辑

    1、加载配置文件

    Configuration conf = new Configuration();

    conf.configure();

    调用方法后src下hibernate核心配置文件就被加载完成

    2、创建SessionFactory(重点)

    SessionFactory  sf = conf.buildSessionFactory();

    根据核心配置文件,有数据库配置,有映射文件部分,到数据库里面根据映射关系创建表

    创建过程特别耗损资源,建议一个项目一般创建一个SessionFactory对象,(静态代码块实现);

    private static Confiuration conf  =null;

    private static SessionFactory sf =null;

    static{

           new Configuration();

           conf.confiure();

           sf = conf.buildSessionFactory();

    }

    3、得到Session

    Session session = sf.openSession();

    理解:类似于jsbc中的connection

    调用session里面不同的方法实现crud操作:

    (1)添加save();

    (2)修改update();

    (3)删除delete();

    (4)按照id查询get(id);

    ……

    session是单线程对象,每个人只能用自己的(ThreadLocal);

    4、Transaction 事物

    Transaction tx = session.beginTransaction();

    主要方法:tx.commit(); tx.rollback();

    ?解决配置文件没有提示的问题:

    1、可以上网,会自动引入提示;

    2、把约束文件引入到eclipse中,window-preferences  搜索xml Catalog  点击add 将配置文件路径复制到 URI(要选)下  ,点击file System 寻找到本地约束文件 ,点击OK结束;重启eclipse;

    六、hibernate主键生成策略:

    native:代理主键,自动增长;

    uuid:hibernate会自动帮我们生成一个32位16进制字符串;

    例:实体类中定义唯一属性 private String uid;

          映射配置文件给uid设置uuid  <generator class=”uuid”></ generator>

    七、对实体类的增删改查操作

    添加操作:User.setUsername(“xiaoma”); user.setAge(10);  session.save();

    根据id查询:

    1、调用session中的get方法实现;

    2、代码如下:

    SessionFactory sf = HibernateUtils.getSessionFactory();

    Session session = sessionFactory.openSession();

    Transaction tx = session beginTransaction();

    User user = session.get(User.class,id值);

    tx.commit();

    session.close();

    sf.close();

    修改操作:

    1、首先查询;

    User user = session.get(User.class,2);

    2、修改;

    user.setUsername(“李连杰”);

    session.update(user); 底层是到对象中找到id 然后根据id进行修改

    删除操作

    1调用delete方法实现一;

    User user = session.get(User.class,1);

    session.delete(user);

    2、调用delete方式实现二:

    User user = new User();

    user.setUid(1);    session.delete(user);

    八、实体类对象状态(概念)

    1瞬时态:对象里面没有id值,跟session没有关联

    2持久态:对象里面有di值并且与session有关联

    3托管态:对象里面有id值但是对象跟session没有关联

    saveOrUpdate方法:

    可以实现添加也能实现修改;瞬时态进行添加,托管态进行修改;持久态进行修改;(有id值就行修改,没id就执行添加)

    User user = new User();

    user.setUsername(“jack”);

    user.setUid(4);

    session.saveOrUpdate(user);

    九、hibernate的一级缓存

    什么是缓存?

    数据存到数据库里面,数据库本身就是文件系统,java中使用流来操作文件,效率不高。

    (1)把数据存到内存里面,不需要使用流方式,可以直接读取内存中数据

    (2)把数据放到内存中,提高读取效率;

    hibernate缓存

    1hibernate框架中提供很多优化方式,hibernate的缓存就是一个优化方式

    2hibernate缓存特点:

    (1)hibernate的一级缓存

    hibernate的一级缓存默认打开的

    hibernate的一级缓存使用范围,是session范围

    (2)hibernate的二级缓存

    目前不使用,替代技术redis;

    默认不打开

    范围sessionFactory

    验证一级缓存存在

    1验证方式

    (1)首先根据uid=1查询,返回对象,发送sql语句;

    (2)再次根据uid查询,直接返回对象,不执行sql语句;

    一级缓存特性:

    持久态自动更新数据库,

    User user = session.get(User.class,1);

    user.setUsername(“hansan”);   不调用update方法也会修改数据库

    十、hibernate事物代码规范

    事物概念:

    1什么是事物?一组操作有一个失败都失败

    2事物特性:原子性、一致性、隔离性、持久性

    3不考虑隔离性的问题?脏读、不可重复读、虚读 

    解决办法: 设置事物隔离级别  repeatable read(mysql默认)

    事物代码结构:

    Transaction tx=null;

    try{

    tx.beginTransaction();

    ….操作数据库代码

    tx.commit();

    }catch(Exception e){

    tx.rollBack();

    }

    十一、Hibernate绑定Session

    获取与本地线程绑定的session

    1、在hibernate核心配置文件中进行配置:

    <property name=”hibernate.current_session_context_class”>thread</property>

    2、调用SessionFactory.getCurrentSession();得到与当前线程绑定的session(底层依然是threadlocal)。

    3、获取本地线程绑定session,关闭session报错,不需要手动关闭;

    十二、查询(所有内容)

    api:

    Query 对象:

    Query q = session.createQuery(“from User”); from+实体类名

    List<User> users = q.list();

    for(User u:users)(syout(u));

    Criteria 对象:              

    Criteria c =session.createCriteria(User.class);

    List<User>users = c.list();

    SQLQuery 对象:

    1使用hibernate时候,也可以来调用底层sql来实现,而SQLQuery就能编写sql语句;

    SQLQuery sql = session.createSQLQuery(“select * from user”);

    List<Object[]> users = sql.list();返回的list每个元素是一个数组;

    for(Object[] array : users){Arrays.toString(array)}

    修改返回数据中每部分是对象而不是数组;

    sql.addEntity(User.class);

    List<User> users = sql.list();

    for(User user : users){sysout(user)}

    十三、Hibernate 一对多操作

    一对多映射配置:

    第一步 创建实体类(例如 商品与分类就是一对多关系)

    第二步 让两个实体类之间互相关联  (分类是一的一方,商品是多的一方)

    在分类中创建一个set集合,无序、可重复;(Hibernate规定set)

    Set<Book> books = new HashSet<Book>();

    在商品实体类中 添加

    private Category category; 属性以及get /set方法;

    第三步 配置映射文件

    1、配置好两张表基本的映射关系;

    2、映射文件中,配置一对多关系

    分类实体类的配置:(分类中表示商品)

    <set name=”books”>

           <key column=”外键”></key>

           <one-to-many class=”被关联实体类的全路径”/>

    </set>

    商品实体类的配置:(商品中表示所属分类)

    <many-to-one name=”category” class=”被关联实体类全路径” column=”外键”></ many-to-one>

    第四步 创建核心配置文件,把映射文件引入到核心配置文件

    要将两个映射文件都引入到核心配置文件中;

    一对多级联操作:

    简化写法:

    第一步

    在映射文件中的set标签中 添加cascade=”save-update”

    <set name=”set集合名称” cascade=”save-update”>

    示例代码:

    一个公司有多个联系人, 一个联系人只属于一个公司 

    实现方式一:没有配置映射文件cascade=”save-update”

    Company comp = new Company();

    comp.setCname(“百度”);

    comp.setCphone(“13314445555”);

    LinkedMan lman = new LinkedMan();

    lman.setLname(“李彦宏”);

    lman.setLphone(“18845888888”);

    comp.getLinkedManSet().add(lman);

    lman.setCompany(comp);

    session.save(comp);

    session.save(lman);

    实现方式二:配置完映射文件

    Company comp = new Company();

    comp.setCname(“百度”);

    comp.setCphone(“13314445555”);

    LinkedMan lman = new LinkedMan();

    lman.setLname(“李彦宏”);

    lman.setLphone(“18845888888”);

    comp.getLinkedManSet().add(lman);

    session.save(comp);

    一对多修改外键操作:

    Company comp =session.get(Compant.class,1);  //id查询

    LinkedMan lm = session.get(LinkedMan.class,1);

    comp.getLinkedManSet().add(lm);

    lm.setCompany(comp);

    因为是持久态对象,所以不用保存,也会执行;

    inverse属性:因为hibernate双向维护外键,所以会update两次外键,降低了效率,解决办法,让其中的一方(多方维护外键)不维护外键;

    在一方的映射文件中添加inverse=”true” ,表示放弃关系维护;

    <set name=”set集合名称” inverse=”true” cascade=”save-update”>

    十四、Hibernate多对多操作

    多对多映射配置

    第一步 创建实体类(Role /user)

    第二步  让两个实体类互相表示(在实体类中分别创建一个set集合表示多对多关系)

    Role{Set<User> setUser = new HashSet<User>();}

    User{Set<Role> setRole=new hashSet<Role>();}

    第三步  配置映射文件

    (1)基本配置()

    cn.wyx.User   实体类的配置文件

    <class name=”实体类全路径” table=”数据库中表名”>

        <id  name=”id值” colum=”表中列名与实体类属性名必须相同”>

              <generator class=”native”></generator>

    </id>

    <property name=”username” colum=”username”></property>

    ……

    <set cascade=”save-update” name=”setRole” table=”user-role” >第三张表的名字

             <key colum=”userid”></key>当前实体类在第三张表中的外键

             <many-to-many  class=”cn.wyx.Role” colum=”roleid”></many-yo-many>关联的哪个实体类,以及该类在第三张表中的外键

    </set>

    </class>

    cn.wyx.Role   实体类的配置文件

    <class name=”cn.wyx.Role” table=”role”>

        <id  name=”rid” colum=”rid”>

              <generator class=”native”></generator>

    </id>

    <property name=”rname” colum=”rname”></property>

    ……

    <set name=”setUser” table=”user-role”>第三张表的名字

             <key colum=”rid”></key>当前实体类在第三张表中的外键

             <many-to-many  class=”cn.wyx.User” colum=”uid”></many-yo-many>关联的哪个实体类,以及该类在第三张表中的外键

    </set>

    </class>

    (2)配置多对多映射(创建第三张表)

    第四步 配置核心配置文件

    <mapping resource=””></mapping>

    级联添加、删除(操作第三张表)

    根据用户保存角色

    第一步 在用户配置文件中set标签进行配置,cascade = “save-update”

    第二步 代码实现

    User user1 = new User();

    user1.setUserName(“lucy”);

    user1.setPassword(“123”);

    User user2 = new User();

    user2.setUserName(“lucy”);

    user2.setPassword(“123”);

    Role r1 = new Role();

    r1.setRname(“总经理”);

    Role r2 = new Role();

    r2.setRname(“CEO”);

    Role r3 = new Role();

    r3.setRname(“技术总监”);

    user1.getSetRole().add(r1);

    user1.getSetRole().add(r2);

    user2.getSetRole().add(r1);

    user2.getSetRole().add(r3);

    session.save(user1);

    session.save(user2);

    级联删除配置:(不参考使用)

    set   标签中添加cascade=”delete”

    User user=session.get(User.class,1);

    session.delete(user);

    维护第三张表:(重点)

    1、让某个用户有某个角色

    第一步:根据id查询出用户和角色

    User user = session.get(User.class,1);

    Role role = session.get(Role.class,1);

    第二步:把角色放到用户里面

    user.getSetRole().add(role);

    2、让用户没有某个角色

    第一步:根据id查询角色和用户

    User user = session.get(User.class,1);

    Role role = session.get(Role.class,1);

    第二步:从setRole集合中删除这个角色

    user.getSetRole().remove(role);

    十五、查询

    对象导航查询:

    public void test(){

          SessionFactory sf=null;

          Session session=null;

          Transaction tx=null;

          try{

               sf = HibernateUtils.getSessionFactory();

               session = sf.openSessioin();

               tx = session.beginTransaction();

               Category category = session.get(Category.class,1);

               Category <Book> cset = category.getSetCategory();

               sysout(cset.size());

               tx.commit();

    }catch(Exception e){

               tx.rollback();

    }

    }

    OID查询

    Category category = session.get(Category.class,1); //就是根据id查询

    HQL查询

    第一步:使用query对象,写hql语句;

    第二步:调用query方法得到结果;

    例1:查询客户表中所有数据?(查询所有)

    Query query = session.createQuery(“from  实体类名称”);

    List<Customer> list = query.list();

    for(Customer cut : list){sysout(cut.getName()+cut.getPassword())}

    例2:从customer表中查询 cid=1 cusName=”百度”的数据?(where条件查询)

    hql语句格式:

    from 实体类名 where 实体类属性名 =? and 实体类属性名=?;

    from 实体类名 where 实体类属性名 like? and 实体类属性名  like?;(用法同上传递参数可以加%参数名%)

    Query query = session.createQuery(“from Customer where cid=? and custName=?”);

    query.setParameter(0,1); //参数位置从0开始,第0个参数的cid值为1;

    query.setParameter(1,”百度”);

    Set<Customer> set = query.llist();

    例3:根据cid排序?(排序查询)

    hql格式:from  类名 order by  实体类属性名  desc/asc

    例4:查询所有数据,从0开始显示3行?(分页查询)

    在hql中没有limit,而是用Hibernate中的方法来代替;

    Query query = session.createQuery(“from Customer”);

    query.setFirstResult(0);//设置开始位置

    query.setMaxResult(3);//设置每页记录数

    list<Customer>list=query.list();

    例5:查询表中指定某一列的值?(投影查询)

    hql格式:select 实体类属性名 from 实体类名

    Query query = session.createQuery(“select custName  from  Customer”);

    List<Object> list = query.lislt();

    例6:查询表中指定某一列的值?(聚合函数查询)

    1、常用聚合函数:count/sum/avg/max/min

    hql格式:select count(*) from 实体类名

    Query  query = session.createQuery(“select count(*) from Customer”);

    Object obj = query.uniqueResult();

    //注意不能直接把obj强转成int,要先转换成Long类型,再转成int;

    obj = (Long)obj.intValue();

     sysout(obj);

    例7:客户与联系人为例(多表查询)

    1、内连接

    hql格式: from 实体类名  别名  inner join  别名.实体类set集合名

    Query query = session.createQuery(“from Customer c inner join c.ManLinkedSet”);

    List<Customer> list = query.list();  //集合中每个元素都是一个数组

    2、左外连接

    hql格式:from Customer c left outer join c.LinkedManSet(返回list元素数组)

    3、右外连接

    hql格式:from  Customer c inner join c.ManLinkedSet(没有迫切连接只能返回数组元素)

    4、迫切内连接

    与内连接的实现一样,区别在于返回list的每部分是对象;

    hql格式: from  Customer c inner join fetch c.ManLinkedSet

    5、迫切左外连接

    hql格式:from Customer c left outer join fetch  c.LinkedManSet(返回list元素对象)

    QBC查询

    第一步:创建Criteria;

    第二步:调用方法得到结果;

    1、查询所有

    Criteria criteria = session.createCriteria(Customer.class);

    List<Customer>list = criteria.list();

    2、条件查询

    Criteria criteria = session.createCriteria(Customer.class);

    criteria.add(Restrictions.eq(“类中属性名”,值));//添加条件

    criteria.add(Restrictions.eq(“cid”,1));

    criteria.add(Restrictions.eq(“custName”,”百度”));

    List<Customer> list = criteria.list();

    3、排序查询

    Criteria criteria = session.createCriteria(Customer.class);

    //设置对哪个属性进行排序,以及排序规则

    criteria.addOrder(Order.asc(“cid”));  升序

    List<Customer> list = criteria.list();

    4、分页查询

    Criteria criteria = session.createCriteria(Customer.class);

    criteria.setFirstResult(0);

    criteria.setMaxResult(10);

    List<Customer> list = criteria.list();

    5、统计查询

    Criteria criteria = session.createCriteria(Customer.class);

    criteria.setProjection(Projections.rowCount());//设置操作

    Object obj = criteria.uniqueResult();//调用方法得到结果

    int count = (Long)obj.intValue();

    6、离线查询

    //离线:不用session也可以创建Criteria对象,以及基本操作;

    //创建离线对象

    DetachedCriteria detachedCriteria = DetachedCriteria.forClass(实体类.class);

    //最终执行时候才需要得到session

    Criteria criteria = detachedCriteria.getExecutableCriteria(session);

    List<Customer> list = criteria.list();

    用处:在dao里面使用hibernate框架时候,最终需要调用session里面的方法实现功能,但是查询条件,可以写在servlet中,来传给dao,而servlet 用离线对象维护;

    十六、Hibernate 检索策略

    第一类   立即查询:根据id查询,调用get()方法立即去查询;

    第二类     延迟查询:根据id查询,当调用load方法,不会马上发送语句查询数据,只有得到对象里面的值时候才会发送语句查询数据库;

    Customer customer = session.load(Customer.class,1);

    调用方法之后,不会发送语句,返回对象里面只有id值,当后面语句得到不是id值的时候才会发送语句;

    例如:customer.getCustName();  就会发送语句

    延迟查询中又分两类:

    (1)类级别延迟:根据id查询返回实体类对象,load方法就是类级别延迟;

    (2)关联级别延迟:查询出某个客户,在查询出这个客户的联系人,查询客户所有联系人的过程是否需要延迟,这个过程称为关联级别延迟;(Hibernate默认使用)

    关联级别延迟修改:

    1、在映射文件中进行配置

    2、在set标签上使用属性

    (1)fetch:select(默认)

    (2)lazy:

    true 延迟(默认)

    false立即

    extra 最延迟(要什么值发送什么语句,效率更好,但是需要发送多次语句效率就会变低)

    批量抓取:

    1、查询所有的客户,返回list集合,遍历list集合,得到每个用户,得到每个用户联系人;

    通常我们操作会发送大量sql语句,采用批量抓取就会优化性能;

    在映射文件的set标签中进行配置

    添加属性 batch-size=”10”  数值自己定,但是越大发送sql语句越少;


     

  • 相关阅读:
    不容易系列之(4)——考新郎
    阿牛的EOF牛肉串
    一只小蜜蜂
    C#设计模式——简单工厂模式
    C#设计模式总结
    [设计模式]单例模式
    Jquery真的不难~第一回 编程基础知识
    大树底下不长草,微软底下?
    下一站 java
    如果电磁不能永久保存,那最终会留下什么?
  • 原文地址:https://www.cnblogs.com/wangyinxu/p/8665836.html
Copyright © 2011-2022 走看看