hibernate基础

  在学习ORM框架之前,我们都是使用jdbc对数据库进行操作,使用Statement、PreparedStatement进行操作。然后封装了DbUtil操作数据库。

 

1.搭建开发环境

1.1 jar包 【5.1.16】

https://sourceforge.net/projects/hibernate/

>equired目录下的

>数据库驱动

>c3p0

 

 

2.2 创建POJO

必须实现Serializable接口

package cn.getword.domain;

import java.io.Serializable;

/**
 * 必须可序列号 db_hibernate
 */
public class User implements Serializable {
    private Integer id;
    private String username;
    private Integer age;
    private Integer deleted;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getDeleted() {
        return deleted;
    }

    public void setDeleted(Integer deleted) {
        this.deleted = deleted;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", age=" + age +
                ", deleted=" + deleted +
                '}';
    }
}
View Code

 

 

2.3 在domain目录下创建hibernate配置文件,表与实体类的关系

  类名.hbm.xml

模板在核心包中:

<?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE hibernate-mapping PUBLIC
                "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
                "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.getword.domain">
    <class name="User" table="tb_user">
        <!--建立字段关系-->
        <!--指定主键id-->
        <id name="id" column="id" type="int">
            <!--自增长策略
                native:本地生成策略
                assigned:
            -->
            <generator class="native"></generator>
        </id>
        <!--配置属性-->
        <property name="username" column="username" />
        <property name="age" column="age" />
        <property name="deleted" column="deleted" />
    </class>
</hibernate-mapping>
View Code

 

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <!-- ORM元数据  表对象关系映射文件 
        package : 配置该配置文件中类所在的包.  -->
 <hibernate-mapping package="com.itheima.a_hello" >
     <!-- class: 配置实体与表的关系
         name : 填写实体的完整类名
         table: 与实体对应表的名称
         dynamic-insert:动态插入 默认值是false
                         true=>如果字段值为null,不参与insert语句
          dynamic-update:动态更新  默认值"false"
                          true=> 没改动过的属性,将不会生成到update语句中
      -->
     <class name="User" table="t_user"  >
         <!-- id: 配置实体与表中 id对应
             name: user对象中标识主键的属性名称
             column: 主键在表中的列名
             length: 列的数据长度
             unsaved-value(不常用): 指定主键为什么值时,当做null来处理.
            access(强烈推荐不要用):field 那么在操作属性时,会直接操作对应的字段而不是get/set方法
          -->
        <id name="id" column="id" length="255"   >
            <!-- generator:主键生成策略
                     1.increment  数据库自己生成主键. 先从数据库中查询最大的ID值,将ID值加1作为新的主键
                    2.identity  依赖于数据的主键自增功能
                    3.sequence    序列,依赖于数据中的序列功能(Oracle).
                    4.hilo(纯了解,永远用不到) : Hibernate自己实现序列的算法,自己生成主键. (hilo算法 )
                    5.native 自动根据数据库判断,三选一. identity|sequence|hilo
                    6.uuid  生成32位的不重复随机字符串当做主键
                    7.assigned 自己指定主键值. 表的主键是自然主键时使用.
                 
             -->
            <generator class="uuid"></generator>
        </id>     
        <!-- property : 实体中属性与表中列的对应
             name : 实体中属性名称
             column : 表中列的名称
             length : 数据长度
             precision: 小数点后的精度
             scale:    有效位数
             insert(一般不用): 该属性是否加入insert语句.
             update(一般不用): 该属性是否加入update语句.
             not-null : 指定属性的约束是否使用 非空
             unique : 指定属性的约束是否使用 唯一
         -->
         <!-- 
             type: 表达该属性的类型
             可以用三种方式指定属性
             java类型                  数据库类型指定            Hibernate类型指定
             java.lang.String    varchar                string
          -->
        <property name="name" column="name" update="true" type="string" ></property>
        <property name="password" column="password"></property>
         <property name="sal" column="sal" precision="2" scale="3" ></property>
     </class>
 </hibernate-mapping>
View Code

 

 

 2.4 在src目录下创建hibernate.cfg.xml主配置文件

  属性参考:源码包下的project目录下的etc目录下的文件

<!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 元素用于配置Hibernate中的属性
          -->
        <!-- hibernate.connection.driver_class : 连接数据库的驱动  -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <!-- hibernate.connection.username : 连接数据库的用户名 -->
        <property name="hibernate.connection.username">root</property>
        <!-- hibernate.connection.password : 连接数据库的密码 -->
        <property name="hibernate.connection.password">123</property>
        <!-- hibernate.connection.url : 连接数据库的地址,路径 -->
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/db_hibernate</property>

        <!-- show_sql: 操作数据库时,会 向控制台打印sql语句 -->
        <property name="show_sql">true</property>
        <!-- format_sql: 打印sql语句前,会将sql语句先格式化  -->
        <property name="format_sql">true</property>
        <!-- hbm2ddl.auto: 生成表结构的策略配置
             update(最常用的取值): 如果当前数据库中不存在表结构,那么自动创建表结构.
                     如果存在表结构,并且表结构与实体一致,那么不做修改
                     如果存在表结构,并且表结构与实体不一致,那么会修改表结构.会保留原有列.
             create(很少):无论是否存在表结构.每次启动Hibernate都会重新创建表结构.(数据会丢失)
             create-drop(极少): 无论是否存在表结构.每次启动Hibernate都会重新创建表结构.每次Hibernate运行结束时,删除表结构.
             validate(很少):不会自动创建表结构.也不会自动维护表结构.Hibernate只校验表结构. 如果表结构不一致将会抛出异常.
          -->
        <property name="hbm2ddl.auto">update</property>

        <!-- 数据库方言配置
         org.hibernate.dialect.MySQLDialect (选择最短的)
         -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

        <!-- hibernate.connection.autocommit: 事务自动提交  -->
        <property name="hibernate.connection.autocommit">true</property>
        <!-- 将Session与线程绑定=> 只有配置了该配置,才能使用getCurrentSession -->
        <property name="hibernate.current_session_context_class">thread</property>
        <!-- 引入ORM 映射文件
            填写src之后的路径
         -->
        <mapping resource="cn/getword/domain/User.hbm.xml" />
    </session-factory>
</hibernate-configuration>
View Code

 

 

2.5 入门案例

插入一条数据:

(1)解析hibernate.cfg配置文件

(2)获取sessionFactory

(3)获取session

(4)开启事务

(5)执行操作

(6)提交事务

(7)释放资源

package cn.getword.test;

import cn.getword.domain.User;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

public class TestUser {
    @Test
    public void test1(){
        //解析配置文件
        Configuration configuration = new Configuration().configure();  //创建配置对象,加载朱配置文件,路径默认
        //获取SessionFactory
        SessionFactory sessionFactory = configuration.buildSessionFactory();
        //获取一个新的session对象
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();//开启事务

        //执行保存操作
        User user = new User();
        user.setUsername("张三");
        user.setAge(21);
        user.setDeleted(0);
        session.save(user);

        //提交事务
        transaction.commit();
        session.close();
    }
}
View Code

 

 注意:不能使用new User(){{}}进行初始化。

 

 

2. hibernate中常用的对象

Configuration

SessionFactory 

  使用原则:一个应用中只能有一个,应用创建时创建,结束时销毁。由于它维护的东西比较多,创建和销毁很消耗资源。

Session

Query

 

2.1 使用HibernateUtil创建单例的SessionFactory,并创建session

package cn.getword.utils;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.Session;

public class HibernateUtils {
    private static SessionFactory sf;
    
    static{
        //hibernate将所有异常都帮我们转成运行时异常
        Configuration  conf = new Configuration().configure();
        sf = conf.buildSessionFactory();
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            
            public void run() {
                System.out.println("打开数据库连接");
                sf.close();
            }
        }));
        
    }
    
    public static Session  getOpenSession(){
                
        Session session = (Session) sf.openSession();

        return session;
    }
    
    public static Session  getCurrentSession(){
        Session session = (Session) sf.getCurrentSession();
        
        return session;
    }
    
}
View Code

 

 

 

3.hibernate的基本增删改查

1.添加

session.save(user);

  默认值:数据库表中的字段有默认值

  

 

2.查询

  • 根据OID:get/load
  • SQL查询:SQLQuery
  • HQL【hibernate query language】查询:Query

    HQL语法:表名换成对应的类名,字段替换成属性

  • QBC查询:query by Criteria, 官方推荐使用HQL。QBC将查询语句封装到方法中,效率相对低
  • 对象导航查询:表的关系:如一对多

 

 

(1)【OID查询】

session.get(User.class, Serilizable ) 必须写id的类型【Integer、Long..】 类型必须一致   :如果查询不到,返回null

session.load(User.class, Serilizable )  :如果查询不到,则跑出异常。

  get和load的区别:

load:根据id查询单个实体,返回的是代理对象,默认使用lazy【懒加载】模式-即当真正使用查询结果时,可以对加载模式进行修改。才进行查询。如果查询不到,抛出异常

      

get:根据id查询,返回POJO对象,是一执行立即查询。加载模式固定

 

 

 

 (2)SQLQuery或者Query对象操作

public void get(){
        Session session = HibernateUtils.getOpenSession();
        Transaction ts = session.beginTransaction();
        SQLQuery query = session.createSQLQuery("SELECT * FROM tb_user where id=?");
        query.setParameter(0, 1);
        List<Object[]> list = query.list();
        for (Object[] os :
                list) {
            System.out.println("----");;
            for (Object o :
                    os) {
                System.out.println(o);
            }
        }
        ts.commit();
        session.close();
    }
View Code

 

(3)HQL查询 

  • 基本查询:使用Query对象
    public void test1(){
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        Query query = session.createQuery("from User");
        List<User> users = query.list();
        for (User u :
                users) {
            System.out.println(u);
        }
        transaction.commit();
    }
View Code

 

 

  • 条件查询:占位符角标从0开始,
        public void test1(){
            Session session = HibernateUtils.getCurrentSession();
            Transaction transaction = session.beginTransaction();
            Query query = session.createQuery("from User where id>? and username like ?");
            query.setInteger(0,3);
            query.setString(1, "%admin%");
            List<User> users = query.list();
            for (User u :
                    users) {
                System.out.println(u);
            }
            transaction.commit();
        }
    View Code

或者:

Query query = session.createQuery("from User where id>:id and username like :username");
query.setParameter("id", 3);
query.setParameter("username", "%admin%");

 

 

  • 排序查询

from User order by age desc

 

  • 分页查询

mysql 通过limit m, n进行分页查询  在HQL中不能使用【不支持limit关键字】

query.setFirstResult(2); //通用性
query.setMaxResults(3);

 

 

  • 统计查询

在mysql中,sum,count,avg,max ,min

select count(*) from User

query.uniqueResult() :该方法只能用于只有一条查询结果

Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
Query query = session.createQuery("select count(*) from User");
Object o = query.uniqueResult();
long rs = (long) o; //Long类型
System.out.println(rs);
transaction.commit();

 

 

  • 投影查询

只需要用到部分字段:需要在实体类中创建对应的构造方法

select new User(id, username) from User;

 

(3)QBC查询

  • 基本查询
Criteria criteria = session.createCriteria(User.class);
List list = criteria.list();

 

  • 条件查询
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.gt("id", 2));
List list = criteria.list();

 

 

  • 离线查询

从前台获取的请求参数比较多,为了更好地向dao层传递参数,将参数封装起来,可以拼接成SQL语句向后台传递。

    @Test
    public void controller(){
        //离线对象
        DetachedCriteria dc = DetachedCriteria.forClass(User.class);
        dc.add(Restrictions.gt("id", 2));
        List<User> users = service(dc);
        for (User u :
                users) {
            System.out.println(u);
        }

    }
    public List<User> service(DetachedCriteria dc){
        List<User> list = null;
        Session session = HibernateUtils.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        try{
            list = dao(dc);
            transaction.commit();
        }catch (Exception e){
            e.printStackTrace();
            transaction.rollback();
        }
        return list;
    }
    public List<User> dao(DetachedCriteria dc){
        Criteria c = dc.getExecutableCriteria(HibernateUtils.getCurrentSession());
        return c.list();
    }
View Code

 

  service层的事务管理可以使用AOP思想进行改装。

 (4)对象导航查询

 

 

3. 更新

session.update(user)

Session session = factory.openSession();
        try {
            Transaction ts = session.beginTransaction();
            String sql = "update student set name=?, age=?, password=? where id=?";
            SQLQuery query = session.createSQLQuery(sql);
            query.setParameter(0, user.getName());
            query.setParameter(1, user.getAge());
            query.setParameter(2, user.getPassword());
            query.setParameter(3, user.getId());
            int rs = query.executeUpdate();

            ts.commit();
            session.close();
            return 1;
        } catch (Exception e) {
            return 0;
        }
View Code

 

 

4. 删除

session.delete(user)

4.事务提交和回滚

  一般事务管理是放在业务逻辑层的。

ts.rollback()

   public void add(){
        Session session = HibernateUtils.getOpenSession();
        Transaction ts = session.beginTransaction();
        try{
            User user = new User();
            user.setUsername("王五");
            user.setAge(23);
            Serializable rs = session.save(user);
            System.out.println(user);
            ts.commit();
        }catch (Exception e){
            ts.rollback();
        }finally {
            session.close();
        }
        
    }
View Code

 

 

5.c3p0连接池配置

1.导入c3p0jar包

2.在主配置文件中配置c0p3连接池

<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>

 

6.实体类的编写规范

  遵循JavaBean规则

  bean:开发中可重用的组件

  JavaBean:在java开发中可重用的组件,例如:service、dao、实体类等。

 

规范:

  都是public

  一般都实现序列化接口

  成员变量都是被private修饰的

  提供set、get方法

  都有默认的无参构造

7.OID以及hibernate主键生成 策略

1.OID  object identifier

  用于标识对象的唯一性。 OID就是映射文件的主键对应的属性。

  hibernate把OID一致的对象认为是同一个对象。在同一session中,不允许出现相同OID的对象。

  因此,主键一般不由自己管理,交个hibernate管理。

 

2.hibernate主键生成策略

native :适用于代理主键

identity:自增长。适用于代理主键

increment:先查询出最大id,然后加一作为id,在高并发环境中容易出问题。基本不使用

sequence:根据数据库序列生成标识符,例如Oracle。 适用于代理主键。

uuid:

assigned:id有java代码指定,适用于自然主键。例如学号:201509001  一般都是有规律的

 

代理主键和自然主键的区别;

  代理主键:只是用来区分数据库记录,不涉及业务信息,没特殊意义。例如:1,2,3,4,5.......

  自然主键:不仅要用来区分数据库记录,还设计业务信息,例如学号、员工编号、订单编号。一般自然主键都是有规律的。

 

 

 

 

 

 

end

 

posted @ 2018-10-08 11:30  fight139  阅读(167)  评论(0编辑  收藏  举报