hibernate配置和使用

hibernate

hibernate常用配置以及简单使用
整理了网上的一些资料和自己对于hibernate的理解,供自己或者刚接触这个框架的朋友参考使用
hibernate有两个配置文件
1.核心配置文件hibernate.cfg.xml
2.映射文件(ORM元数据)XXX.hbm.xml
下面来分别介绍两个配置文件中的元素和配置文件的作用

1.核心配置文件

核心配置文件放在src目录下
核心配置文件中配置了数据库驱动,数据库地址,数据库方言等信息
下面介绍几个常用元素

数据库连接的相关配置

<!-- 数据库驱动 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 数据库url -->
<property name="hibernate.connection.url">jdbc:mysql:///test</property>
<!-- 数据库连接用户名 -->
<property name="hibernate.connection.username">admin</property>
<!-- 数据库连接密码 -->
<property name="hibernate.connection.password">1111</property>

数据库方言

<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

打印和格式化sql

<!-- 将hibernate生成的sql语句打印到控制台 -->
<property name="hibernate.show_sql">true</property>
<!-- 将hibernate生成的sql语句格式化(语法缩进) -->
<property name="hibernate.format_sql">true</property>

自动建表

<!-- 
#hibernate.hbm2ddl.auto create      自动建表.每次框架运行都会创建新的表.以前表将会被覆盖,表数据会丢失.(开发环境中测试使用)
#hibernate.hbm2ddl.auto create-drop     自动建表.每次框架运行结束都会将所有表删除.(开发环境中测试使用)
#hibernate.hbm2ddl.auto update      (推荐使用) 自动生成表.如果已经存在不会再生成.如果表有变动.自动更新表(不会删除任何数据).
#hibernate.hbm2ddl.auto validate    校验.不自动生成表.每次启动会校验数据库中表是否正确.校验失败.
 -->
<property name="hibernate.hbm2ddl.auto">update</property>

引入映射文件

<!-- 引入orm元数据
路径书写: 填写src下的路径
-->
<mapping resource="cn/test/pojo/Customer.hbm.xml" />

2.映射文件

映射文件可以和实体类放在同一个包下,配置表与实体对象的关系映射

<!-- package属性:填写一个包名.在元素内部凡是需要书写完整类名的属性,可以直接写简答类名了. -->
<hibernate-mapping package="cn.test.pojo" >
    <!-- 
        class元素: 配置实体与表的对应关系的
        name: 完整类名
        table:数据库表名
     -->
    <class name="Person" table="test_person" >
        <!-- id元素:配置主键映射的属性
            name: 填写主键对应属性名
            column(可选): 填写表中的主键列名.默认值:列名会默认使用属性名
            type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
                每个类型有三种填法: java类型|hibernate类型|数据库类型
            not-null(可选):配置该属性(列)是否不能为空. 默认值:false
            length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
         -->
        <id name="person_name"  >
            <!-- generator:主键生成策略
                identity : 主键自增.由数据库来维护主键值.录入时不需要指定主键.
                increment:hibernate维护主键,这个不使用,有线程安全问题.
                sequence: Oracle中的主键生成策略.
                hilo: 高低位算法.主键自增.由hibernate来维护.开发时不使用.
                native:hilo+sequence+identity 自动三选一策略.
                uuid: 产生随机字符串作为主键. 主键类型必须为string 类型.
                assigned:自然主键生成策略. hibernate不会管理主键值.由开发人员自己录入.
            -->
            <generator class="native"></generator>
        </id>
        <!-- property元素:除id之外的普通属性映射
            name: 填写属性名
            column(可选): 填写列名
            type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
                每个类型有三种填法: java类型|hibernate类型|数据库类型
            not-null(可选):配置该属性(列)是否不能为空. 默认值:false
            length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
         -->
        <property name="person_sex" column="person_sex" >
            <!--  <column name="person_sex" sql-type="varchar" ></column> -->
        </property>
        <property name="person_age" column="person_age" ></property>
        <property name="person_tel" column="person_tel" ></property>
    </class>
</hibernate-mapping>

hibernate核心API
configuration 配置加载类.用于加载主配置,orm元数据加载
SessionFactory功能: 用于创建操作数据库核心对象session对象的工厂. 简单说功能就一个—创建session对象
sessionfactory 负责保存和使用所有配置信息.消耗内存资源非常大,所以在web项目中只创建一个

//1 读取指定主配置文件 => 空参加载方法,加载src下的hibernate.cfg.xml文件
Configuration conf = new Configuration().configure();
//2 根据配置信息,创建 SessionFactory对象
SessionFactory sf = conf.buildSessionFactory();
//3 获得session
//打开一个新的session对象
sf.openSession();
//4 session获得操作事务的Transaction对象
//开启事务并获得操作事务的tx对象
Transaction tx2 = session.beginTransaction();

也可以用sf.getCurrentSession() 获得一个与当前线程绑定的session
tx.commit();//提交事务
tx.rollback();//回滚事务
session.close();//释放资源
sf.close();//释放资源

如果用的是getCurrentSession 那么提交事务之后,session会自动关闭,不需要再手动关闭了.
获取与当前线程绑定的session需要在配置文件里面配置一下

<!-- 指定session与当前线程绑定 -->
         <property name="hibernate.current_session_context_class">thread</property>

简单的增删该查

1.增

Person person = new Person();
person.setPerson_name("aa");

session.save(person);

2.删(删除的话首先要获得删除的对象)

Person person = session.get(Person.class,3);

session.delete(person);

3.改(也需要首先获取要修改的对象)

Person person = session.get(Person.class,3);
person.setPerson_name("bb");

session.update(person);

4.查

Person person = session.get(Person.class,3);

3.创建hibernate实体类的注意事项

1.持久化类提供无参数构造,(因为hibernate是用反射来创建对象的,反射默认的是使用类中的空参构造)
2.成员变量私有,提供共有get/set方法访问.需提供属性
3.持久化类中的属性,应尽量使用包装类型(因为使用包装类型可以接受数据库中的null)
4.持久化类需要提供oid.与数据库中的主键列对应(没有主键的话无法映射到hibernate)
5.不要用final修饰class

4.hibernate一级缓存cache

hibernate对象有三种状态(瞬时,持久,托管)
实际上save,update,delete是对三种状态的转换

持久化状态的对象会自动同步到数据库中
操作的核心是将对象转为持久化状态

hibernate缓存和快照
java中是通过对象的地址来比较对象是否相同,而hibernate是通过oid来比较对象是否相同
程序调用get获取对象,hibernate会去缓存中通过oid查找对象,如果没有则会发送sql语句,然后将查询结果分装成两个resultSet
一个放在缓存中,一个放在快照中,然后将缓存中的对象返回给程序,提交事务时去和快照中的对比,如果有变化,
则会更新到数据库中.
1:提高查询效率
2:减少不必要的修改语句发送
提高效率手段

hibernate中的事务

事务的特性
acid(原子性,一致性,隔离性,持久性)
事务并发存在的问题
1.脏读
2.幻读
3.不可重复读
事务隔离级别
1.读未提交(存在以上三个问题)
2.读已提交(可解决脏读问题)
4.可重复度(可解决脏读和不可重复读问题)
8.串行化(效率低,不推荐)
配置事务隔离级别

 <property name="hibernate.connection.isolation">4</property>

HQL语句(适合用于简单多表查询)

hibernate query language

1.书写hql
String hql = " from Person"; // 查询所有Person对象
2.//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//3> 根据查询对象获得查询结果
List<Customer> list = query.list(); // 返回list结果
//如果接收唯一的查询结果用query.uniqueResult()

条件查询

//1> 书写HQL语句
String hql = " from Person where person_name = 1 "; 
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//3> 根据查询对象获得查询结果
Person p = (Person) query.uniqueResult();

占位符

//1> 书写HQL语句
String hql = " from Person where person_name = ? "; 
//2> 根据HQL语句创建查询对象
Query query = session.createQuery(hql);
//设置参数
//query.setLong(0, 1l);
query.setParameter(0, 1l);
//3> 根据查询对象获得查询结果
Person p = (Person) query.uniqueResult();

命名占位符

//1> 书写HQL语句
        String hql = " from Person where person_name = :person_name"; 
        //2> 根据HQL语句创建查询对象
        Query query = session.createQuery(hql);
        //设置参数
        query.setParameter("person_name", 1);
        //3> 根据查询对象获得查询结果
        Person p = (Person) query.uniqueResult();

分页查询

//1> 书写HQL语句
        String hql = " from Person "; // 查询所有Customer对象
        //2> 根据HQL语句创建查询对象
        Query query = session.createQuery(hql);
        //设置分页信息 limit ?,?
        query.setFirstResult(1);
        query.setMaxResults(1);
        //3> 根据查询对象获得查询结果
        List<Person> list =  query.list();

排序

String hql = " from  test.demo.Person order by person_id desc ";//完整写法

        Query query = session.createQuery(hql);

        List list = query.list();

聚合函数

String hql1 = " select count(*) from  test.demo.Person  ";//完整写法
        String hql2 = " select sum(person_age) from  test.demo.Person  ";//完整写法
        String hql3 = " select avg(person_age) from  test.demo.Person  ";//完整写法
        String hql4 = " select max(person_id) from  test.demo.Person  ";//完整写法
        String hql5 = " select min(person_age) from  test.demo.Person  ";//完整写法

        Query query = session.createQuery(hql5);

        Number number  = (Number) query.uniqueResult();

投影查询

String hql1 = " select person_name from  cn.itcast.domain.Customer  ";
        String hql2 = " select person_name,person_id from  test.demo.Person  ";
        String hql3 = " select new Person(person_name,person_id) from  test.demo.Person  ";

        Query query = session.createQuery(hql3);

        List list = query.list();

多表查询
以客户和联系人关系为例
客户下对应多个联系人

内连接

//HQL 内连接 => 将连接的两端对象分别返回.放到数组中.
String hql = " from Customer c inner join c.linkMens ";

        Query query = session.createQuery(hql);

        List<Object[]> list = query.list();
//HQL 迫切内连接 => 帮我们进行封装.返回值就是一个对象
String hql = " from Customer c inner join fetch c.linkMens ";

        Query query = session.createQuery(hql);

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

左连接

//HQL 左外连接 => 将连接的两端对象分别返回.放到数组中.
//一个对象放在一个数组中
String hql = " from Customer c left join c.linkMens ";

        Query query = session.createQuery(hql);

        List<Object[]> list = query.list();

Criteria(QBC)

hibernate的无语句面向对象查询

基本查询

//查询所有的Person对象
        Criteria criteria = session.createCriteria(Person.class);

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

        System.out.println(list);

条件查询

//创建criteria查询对象
        Criteria criteria = session.createCriteria(Person.class);
        //添加查询参数 => 查询person_id为1的Person对象
        criteria.add(Restrictions.eq("person_id", 1));
        //执行查询获得结果
        Person p = (Person) criteria.uniqueResult();

分页查询

//创建criteria查询对象
        Criteria criteria = session.createCriteria(Person.class);
        //设置分页信息 limit ?,?
        criteria.setFirstResult(1);
        criteria.setMaxResults(2);
        //执行查询
        List<Person> list = criteria.list();

查询总条数

//创建criteria查询对象
        Criteria criteria = session.createCriteria(Person.class);
        //设置查询的聚合函数 => 总行数
        criteria.setProjection(Projections.rowCount());
        //执行查询
        Long count = (Long) criteria.uniqueResult();

排序

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

        c.addOrder(Order.asc("person_id"));
        //c.addOrder(Order.desc("person_id"));

        List<Person> list = c.list();

Criteria离线查询,可以在web层创建不依赖session的Criteria,绑定条件,然后传到dao层再关联session

//Service/web层
        DetachedCriteria dc  = DetachedCriteria.forClass(Person.class);

        dc.add(Restrictions.idEq(6));//拼装条件(全部与普通Criteria一致)
//dao
Configuration conf = new Configuration().configure();

        SessionFactory sessionFactory = conf.buildSessionFactory();

        Session session = sessionFactory.openSession();

        Transaction tx = session.beginTransaction();

        //关联session
        Criteria c = dc.getExecutableCriteria(session);

        List list = c.list();

        tx.commit();
        session.close();

SQL查询

基本查询
返回的是一个object数组集合,要是想将结果放到对象中,需要指定将结果集封装到哪个对象中
query.addEntity(Customer.class);

//1 书写sql语句
        String sql = "select * from cst_customer";

        //2 创建sql查询对象
        SQLQuery query = session.createSQLQuery(sql);

        //3 调用方法查询结果
        List<Object[]> list = query.list();
        //query.uniqueResult();

条件查询

//1 书写sql语句
        String sql = "select * from cst_customer where cust_id = ? ";

        //2 创建sql查询对象
        SQLQuery query = session.createSQLQuery(sql);

        query.setParameter(0, 1l);
        //指定将结果集封装到哪个对象中
        query.addEntity(Customer.class);

        //3 调用方法查询结果
        List<Customer> list = query.list();

分页查询

//1 书写sql语句
        String sql = "select * from cst_customer  limit ?,? ";

        //2 创建sql查询对象
        SQLQuery query = session.createSQLQuery(sql);

        query.setParameter(0, 0);
        query.setParameter(1, 1);
        //指定将结果集封装到哪个对象中
        query.addEntity(Customer.class);

        //3 调用方法查询结果
        List<Customer> list = query.list();

查询优化

延迟加载
使用session.load()方法,可以应用类级别的加载策略
在orm元数据中配置
lazy属性默认是true,当设置为false时,load和get没有区别

<class name="Person" table="test_person" lazy="true">

关联级别查询
lazy设置为true,fetch使用select

延迟加载存在no-session问题
解决办法:扩大session作用范围
可使用过滤器filter
前处理打开session,开启事务
放行
后处理关闭session,提交事务

hibernate关系表达(一对多|多对一)

在表中,多的一方使用外键引用一的一方的主键
在对象中,一的一方使用集合表达持有多个多的一方,多的一方使用对象引用一的一方,表达多的一方属于哪个一的一方

ORM元数据中表达
一的一方
Custonmer.hbm.xml

<!-- 集合,一对多关系,在配置文件中配置 -->
        <!-- 
            name属性:集合属性名
            column属性: 外键列名
            class属性: 与我关联的对象完整类名
         -->
         <!-- 
            级联操作:   cascade
                save-update: 级联保存更新
                delete:级联删除
                all:save-update+delete
            级联操作: 简化操作.目的就是为了少些两行代码.
          -->
          <!-- inverse属性: 配置关系是否维护. 
                true: customer不维护关系
                false(默认值): customer维护关系

            inverse属性: 性能优化.提高关系维护的性能.
            原则: 无论怎么放弃,总有一方必须要维护关系.
            一对多关系中: 一的一方放弃.也只能一的一方放弃.多的一方不能放弃.
          -->
        <set name="linkMens" inverse="true" cascade="save-update"  >
            <key column="lkm_cust_id" ></key>
            <one-to-many class="LinkMan" />
        </set>

一的一方

<!-- 多对一 -->
        <!-- 
            name属性:引用属性名
            column属性: 外键列名
            class属性: 与我关联的对象完整类名
         -->
          <!-- 
            级联操作:   cascade
                save-update: 级联保存更新
                delete:级联删除
                all:save-update+delete
            级联操作: 简化操作.目的就是为了少些两行代码.
          -->
          <!-- 多的一方: 不能放弃维护关系的.外键字段就在多的一方.  -->
        <many-to-one name="customer" column="lkm_cust_id" class="Customer"  >
        </many-to-one>

多对多关系

在表中使用一张中间表,引用两方主键作为两个外键.
在对象中,两方都用集合来表达拥有多个对方

<!-- 多对多关系表达 -->
        <!-- 
            name: 集合属性名
            table: 配置中间表名
            key
             |-column:外键,别人引用"我"的外键列名
             class: 我与哪个类是多对多关系
             column:外键.我引用比人的外键列名
         -->
         <!-- cascade级联操作:
                    save-update: 级联保存更新
                    delete:级联删除
                    all:级联保存更新+级联删除
            结论: cascade简化代码书写.该属性使不使用无所谓. 建议要用只用save-update.
                 如果使用delete操作太过危险.尤其在多对多中.不建议使用.
                     -->
        <set name="roles" table="sys_user_role" cascade="save-update" >
            <key column="user_id" ></key>
            <many-to-many class="Role" column="role_id" ></many-to-many>
        </set>

多对多关系中,一定要有一方放弃维护关系,否则会因为主键冲突报错

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值