木心

毕竟几人真得鹿,不知终日梦为鱼

导航

hibernate(一)helloworld、api、事务、配置文件、映射文件

hibernate 系列
  hibernate(一)helloworld、api、事务、配置文件、映射文件
  hibernate(二)对象的三种状态、一级缓存、多对一、inverse、cascade
  hibernate(三)多对多、加载策略、懒加载、HQL查询、整合c3p0、乐观锁悲观锁
  hibernate(四)整合log4j、一对一、二级缓存

 

本篇目录:

1、hibernate 介绍
2、ORM 介绍
3、Java 种常用的 ORM 技术
4、hibernate hello world 程序
5、Hibernate-api详解
    5.1、Configuration对象
    5.2、SessionFactory对象
    5.3、Session-增删改
    5.4、Session-HQL查询
    5.5、Session-Criteria&Sql查询
    5.6、session.load()
    5.7、Transaction详解
    5.8、Query详解
    5.9、Criteria详解(了解,开发中用得不多)
    5.10、封装Hibernate工具类
6、Hibernate-配置文件
7、Hibernate-实体配置详解-实体规则
8、映射文件详解

1、hibernate 介绍    <--返回目录

  hibernate 在 javaEE 三层架构的位置

 

2、ORM 介绍    <--返回目录

  ORM:对象关系映射(Object Relational Mapping,简称ORM)是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。本质上就是将数据从一种形式转换到另外一种形式。

  对象 Object:java 对象,此处特指 JavaBean

  关系 Relational:二维表,数据库的表

  映射 Mapping:对象的属性 与表字段 存在对应关系

 

3、Java 种常用的 ORM 技术    <--返回目录

  1)JPA(Java Persistence API):JPA 通过 JDK5 注解或 XML 描述对象-关系表的映射关系(只有接口规范)

  2)Hibernate:ORM 框架,通过对象-关系映射配置,可以完全脱离底层 sql

  3)mybatis:apache 开源项目 ibatis,支持普通 sql 查询,存储过程和高级映射的优秀持久层框架

  4)apache DBUtils、Spring JDBCTemplate

 

4、hibernate hello world 程序    <--返回目录

  demo 最终结构

  新建一个 Java Project

   依赖

 链接:https://pan.baidu.com/s/12nwIyodOhVCEemaAyPVPtQ 提取码:tp9w

   依赖 Add to Build Path

 

  创建实体类

public class User {
    private Integer id;
    private String username;
    private String password;
    //getter和setter省略
}

  mysql 创建表

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(100) DEFAULT NULL,
  `password` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

  hibernate 配置文件 hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!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/test?useUnicode=true&amp;characterEncoding=UTF-8</property>
        <!-- 连接数据库的用户名 -->
        <property name="hibernate.connection.username">root</property>
        <!-- 连接数据库的密码 -->
        <property name="hibernate.connection.password">123456</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: 事务自动提交,默认false  -->
        <property name="hibernate.connection.autocommit">true</property>

        <!-- 引入ORM 映射文件 填写src之后的路径 -->
        <mapping resource="com/oy/helloworld/User.hbm.xml" />
    </session-factory>
</hibernate-configuration>

  映射文件 User.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">
    
 <!-- ORM元数据  表对象关系映射文件 
     package: 配置该配置文件 实体类 所在的包 -->
 <hibernate-mapping package="com.oy.helloworld">
     <!--class: 配置实体与表的关系
         name : 填写实体的完整类名
         table: 与实体对应表的名称
         dynamic-insert:动态插入,默认值是false
                        true => 如果字段值为null,不参与 insert 语句
         dynamic-update:动态更新,默认值"false"
                         true => 没改动过的属性,将不会生成到 update 语句中 -->
     <class name="User" table="user">
         <!--id: 配置实体与表中 id对应
             name: user对象中标识主键的属性名称
             column: 主键在表中的列名
             length: 列的数据长度
             unsaved-value(不常用): 指定主键为什么值时,当做null来处理.
            access(强烈推荐不要用): field 那么在操作属性时,会直接操作对应的字段而不是get/set方法
          -->
        <id name="id" column="id" length="100">
            <!-- 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="identity"></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="username" column="username" update="true" type="string" ></property>
        <property name="password" column="password"></property>
        <!-- <property name="sal" column="sal" precision="2" scale="3" ></property> -->
     </class>
 </hibernate-mapping>

  测试类

package com.oy.helloworld;

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

public class TestHelloWorld {
    @Test
    public void fun1() {
        // 读取配置文件
        Configuration conf = new Configuration().configure();
        // 根据配置 创建Factory
        SessionFactory sessionFactory = conf.buildSessionFactory();
        // 通过获得操作数据库的session对象
        Session session = sessionFactory.openSession();
        // 操作数据库
        User u = new User();
        u.setUsername("tom");
        u.setPassword("222");
        session.save(u);
        // 关闭资源
        session.close();
        sessionFactory.close();
    }
}

  测试结果:控制台打印

Hibernate: 
    insert 
    into
        user
        (username, password) 
    values
        (?, ?)

  数据库记录插入成功

 

  需要注意的地方:

  1)hibernate 默认需要手动开启提交事务,也可以配置自动提交事务

<!-- hibernate.connection.autocommit: 事务自动提交,默认false  -->
<property name="hibernate.connection.autocommit">true</property>

  2)mysql 引擎 MyISAM 不支持事务,所以如果使用 MyISAM  引擎,事务失效,插入总是成功(不会回滚),也即

<property name="hibernate.connection.autocommit">false</property> 配置成 false,也会插入成功。

 

  测试 事务

<property name="hibernate.connection.autocommit">false</property>

  hibernate.connection.autocommit 配置成 false,事务不会自动提交,插入记录被回滚了

 

5、Hibernate-api详解    <--返回目录

5.1、Configuration对象    <--返回目录

  加载src下名为hibernate.cfg.xml

Configuration conf = new Configuration().configure();

  如果配置文件不符合默认加载规则,调用

Configuration conf = new Configuration().configure(File file);//通过file加载
Configuration conf = new Configuration().configure(String path);//通过路径加载

  可以通过Configuration对象加载映射文件(不推荐)。conf.addClass(User.class);之所以可以这样实现加载,因为有下面规范
    规范1:ORM映射文件名称与实体名称一致;
         规范2:ORM映射文件需要与实体类放在同一包下
        
  推荐使用hibernate.cfg.xml 使用mapping属性引入映射文件

<mapping resource="com/oy/domain/User.hbm.xml"/>

 

5.2、SessionFactory对象    <--返回目录

  创建 Factory

Configuration conf = new Configuration().configure(); // 读取配置文件
SessionFactory sessionFactory = conf.buildSessionFactory();

  获取一个全新的 session 对象

Session session = sessionFactory.openSession();

  获得与当前线程绑定的 session 对象,如果没有,获取一个新的 session

先配置:<property name="hibernate.current_session_context_class">thread</property>  
将session与线程绑定,只有配置了该参数,才能使用getCurrentSession()
Session session = sessionFactory.getCurrentSession();

 

5.3、Session-增删改    <--返回目录

  增

User user = new User();
user.setUname("李四");
user.setPassword("123");
session.save(user);

  改

//先查
//开启事务
Transaction ts= session.beginTransaction();
//
User _user = (User) session.get(User.class, 1);//取一个User对象,id=1
System.out.println(_user);
//
_user.setPassword("abc"); //修改密码
_user.setUname("张三");  //修改密码
session.update(_user);  //执行修改
//关闭事务
ts.commit();

  或者

User user1 = new User();
user1.setUid(1);  //指定id
user1.setPassword("def");  //修改密码
user1.setUname("zhangsan"); //修改用户名

Transaction ts= session.beginTransaction(); //修改操作必须先开启事务
session.update(user1); //执行修改
ts.commit();  //提交事务

  删(根据id删除,只有对象有id就行)

//User _user = (User) session.get(User.class, 1);//取一个User对象,id=1
User user2 = new User();
user2.setUid(1);  //指定id
Transaction ts= session.beginTransaction(); //删除操作必须先开启事务
session.delete(user2);
ts.commit();  //提交事务

 

5.4、Session-HQL查询    <--返回目录

  HQL语言:Hibernate Query Language
          session.createQuery("HQL语句");


  查询所有
          Query query = session.createQuery("from com.oy.domain.User");
          List<User> userList = query.list();//list()将语句执行,并返回结果

 

5.5、Session-Criteria&Sql查询    <--返回目录

  Criteria查询==>Hibernate独创的面向对象的查询==>无语句

//查询所有
Criteria criteria = session.createCriteria(User.class);
List<User> userList = criteria.list();

  原生的sql查询,查询所有

SQLQuery query = session.createSQLQuery("select * from t_user ");
query.addEntity(User.class);
List<User> userList = query.list();

 

5.6、session.load()    <--返回目录

 

  问题1:load()方法,返回一个代理对象,获得其内容时,会查询数据库,是每次访问属性都会查询数据库吗?
        答:不是每次都查。代理对象中有一个表识是否被初始化的boolean型变量,记录是否被初始化过。


  问题2:代理都是要基于接口的,用load()方法返回的代理,就没有实现任何接口?
        答:java中的动态代理是基于接口;而Hibernate是使用javassist-3.12.0.GA.jar产生代理对象,
        该代理与被代理对象之间的关系是继承关系。代理对象是被代理对象的子类。

 

5.7、Transaction详解    <--返回目录

    * 开启事务 Transaction ts= session.beginTransaction();
    * 提交事务 ts.commit();
      回滚事务 ts.rollback();
    * 获得已经打开的事务对象(很少用)
        session.getTransaction();
    * 事务关闭时,会自动把与当前线程关联的session关闭,并删除

 

  事务代码规范写法

Session session = null;
Transaction tx = null;
try {
    session = HibernateUtils.openSession();
    tx = session.beginTransaction(); // 开启事务
    // ==============================================
    
    // ==============================================
    tx.commit(); // 提交事务
} catch (Exception e) {
    tx.rollback(); // 回滚事务
} finally {
    session.close(); // 关闭操作
}

 

5.8、Query详解    <--返回目录

    * Query对象:封装HQL语句的对象
    * 查询所有
        Query query = session.createQuery("from com.oy.domain.User");
        List<User> userList = query.list();//list()方法将hql句执行,并返回List<User>
    * 查询一条记录
        Query query = session.createQuery("from com.oy.domain.User where uname='张三'");
        User u = (User)query.uniqueResult();//执行hql语句,返回一个User对象
    * 分页 limit Index,count;
        query.setFirstResult(index);//指定结果从第index个取
        query.setMaxResults(count);//指定取几条记录

 

5.9、Criteria详解(了解,开发中用得不多)    <--返回目录

    * Criteria查询==>Hibernate独创的面向对象的查询==>无语句
    * 查询所有
        Criteria criteria = session.createCriteria(User.class);
        List<User> userList = criteria.list();
    * 查询一条记录
        Criteria criteria = session.createCriteria(User.class);
        criteria.add(Restrictions.eq("uname","张三"));//查询name=张三的记录
        User u = (User)criteria.uniqueResult();
    * 查询uname字段中包含"三"的记录
        criteria.add(Restrictions.like("uname","%三%"));
        List<User> userList = criteria.list();
    * 查询uid>1的记录
        criteria.add(Restrictions.gt("uid",1));
        List<User> userList = criteria.list();
    * > gt   < lt    = eq    >=ge    <=le    like      between

 

5.10、封装Hibernate工具类    <--返回目录

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
    // 会话工厂,整个程序只有一份。
    private static SessionFactory sf;

    static {
        // 1 加载配置
        Configuration config = new Configuration().configure();

        // 2 获得工厂
        sf = config.buildSessionFactory();
        // 3 关闭虚拟机时,释放SessionFactory
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            public void run() {
                System.out.println("虚拟机关闭!释放资源");
                sf.close();
            }
        }));
    }

    // 获得一个新的session
    public static Session openSession() {
        return sf.openSession();
    }

    // 获得当前线程中绑定session
    public static Session getCurrentSession() {
        return sf.getCurrentSession();
    }
}
View Code

 

6、Hibernate-配置文件    <--返回目录

       <property name="hbm2ddl.auto">create</property>

update:最常用,如果当前数据库中不存在表结构,自动创建表结构;如果存在表结构,并且表结构与实体一致,那么不做修改;
    如果存在表结构,并且表结构与实体不一致,那么会修改表结构,会保留原有列。
create(很少用):无论是否存在表结构,每次启动Hibernate都会重新创建表结构(数据会丢失)。
create-drop(很少用):无论是否存在表结构,每次启动Hibernate都会重新创建表结构;运行结束时删除表。
validate(很少用):不会自动创建表结构,也不会自动维护表结构,只会校验表结构。如果表结构不一致,抛出异常。

  方言: <property name="hibernate.dialect">org.hibernate.dialect.MySqlDialect</property>

 

7、Hibernate-实体配置详解-实体规则    <--返回目录

    * 实体编写规则
        - 提供一个无参数 public访问控制符的构造器
        - 提供一个标识属性,映射数据表主键字段
        - 所有属性提供public访问控制符的 set  get 方法(javaBean)
        - 标识属性应尽量使用基本数据类型的包装类型
            ** 基本数据类型和包装类型对应hibernate的映射类型相同
            ** 基本类型无法表达null、数字类型的默认值为0。
            ** 包装类默认值是null。当对于默认值有业务意义的时候需要使用包装类。
        - 不要用final修饰实体 (将无法生成代理对象进行优化)
            ** 生成代理对象,代理对象是被代理对象的子类,final类不能被继承
    * 持久化对象的唯一标识-oid&主键
        - 关系数据库用主键区分同一条记录
        - Hibernate使用OID来建立内存中的对象和数据库中记录的对应关系
        - 结论: 对象的OID和数据库的表的主键对应。为保证OID的唯一性,应该让Hibernate来为OID赋值
    * 区分自然主键和代理主键
        - 主键需要具备: 不为空/不能重复/不能改变
        - 自然主键:    在业务中,某个属性符合主键的三个要求。那么该属性可以作为主键列。
        - 代理主键: 在业务中,不存符合以上3个条件的属性,那么就增加一个没有意义的列作为主键。

 

8、映射文件详解    <--返回目录

    * <hibernate-mapping package="com.oy.d_hbm">
      <class name="User" table="t_user"> 
      配置了package属性,则User前面无需加包名
   
    * <class name="com.oy.d_hbm.User" table="t_user">
        - 属性dynamic-insert:动态插入,默认为false,true=>如果字段为null,不参与insert语句
        - 属性dynamic-update:动态修改,默认为false,true=>如果字段为null,不参与update语句
   
    * <id name="uid" column="uid">
        - 属性length:修改表uid的数据长度,演示不成功
        - unsaved-value(不常用):指定主键为什么值时,当做null来处理
            ** 我们建实体类的规则,主键使用包装类
        - access(不推荐使用):field,那么在操作属性时,直接操作对应的字段,而不是get/set方法
    * 主键生成策略
        <id name="uid" column="uid">
            <!-- 主键生成策略:native表示由数据库维护主键(数据库中主键设置为自增) -->
            <generator class="native"></generator>
        </id>
       
        - <generator class="">主键生成策略
        - 1)increment:数据库自己生成。先从数据库总查询最大的ID值,将ID值加1
            ** 当主键生成策略为increment,save()方法会使用语句select max(uid) from t_user来给user设置uid;
            ** save()方法不会使用insert语句;
            ** 此时,需要使用事务提交,才会使用insert语句,把数据持久化到数据库中;
        - 2)identity:依赖数据的主键自增功能
            ** 当主键生成策略是identity,save()方法使用insert语句获取uid;
            ** 由于使用了insert语句,save()方法后数据已经持久化到数据库中了;
        - 3)sequence:序列,依赖于数据中的序列功能(Oracle)
        - 4)hilo(了解,永远用不到):Hibernate自己实现序列的算法,自己生成主键,hilo算法
        - 5)native:自动根据数据库判断,identity, sequence, hilo三选一
        - 6)uuid:生成不重复的32位随机字符串当做主键
        - 7)assigned:自己设置主键值。一般在表的主键是自然主键时使用该策略。
       
    * 实体其他属性<property name="" column=""></property>
        - length:数据长度
        - precision:小数点后的精度,(字段为double类型时使用)
        - scale:有效位数,(字段为double类型时使用)
        - insert(一般不用):false表示该属性是否加入inset语句
        - update(一般不用):false表示该属性是否加入update语句
        - not-null:知道属性的约束是否使用非空
        - unique:指定属性的约束是否使用唯一
        - type:表达该属性的类型,可以使用三种方式来指定属性
            java类型             数据库类型             Hibernate类型
        java.lang.String      varchar                   string

posted on 2020-06-13 09:01  wenbin_ouyang  阅读(307)  评论(0编辑  收藏  举报