• 三、hibernate中持久化类的使用


    hibernate的持久化类

    • 持久化:将内存中的一个对象持久化到数据库中的过程,hibernate就是一个用来进行持久化的框架
    • 持久化类:一个Java对象与数据库中表建立了关系映射,那么这个类在hibernate中就可以称之为持久化类
      • Java实体类
      • 该Java类的映射文件 

    持久化类的使用 

    提供无参构造

    从之前测试类中查询的使用来看:

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

    说明hibernate内部是使用反射技术实现生成对象实例,所以持久化类中的Java实体类必须提供一个无参构造

    定义私有属性,公有的getter/setter方法

    hibernate生成对象实例时,需要获取、设置属性值

    定义唯一标识属性OID(对应数据库表中的主键)

    • hibernate缓存是一个map,他会根据OID作为缓存对象的key,我们的映射文件中<id>标签指定的属性值会作为OID
    • Java对象通过地址来定位一个对象,数据库的表中通过主键来定位到一条数据记录
    • hibernate中通过持久化类的唯一标识属性来定位一个对象

    例如User中的id

    public class User {
    
    	private Integer id;
    	private String name;
    	private String password;
    	......
    } 

    映射文件配置id属性

    <hibernate-mapping>
    	<!-- 配置表与实体的映射关系 -->
    	<class name="com.qf.entity.User" table="user">
    		<id name="id" column="id">
    			<generator class="native"></generator>
    		</id>
    		......
    	</class>
    </hibernate-mapping>

    属性定义最好使用包装类

    因为基本数据类型默认值是0,容易出现很多问题

    例如:

    • 保存数据时,id属性如果没有设置具体值,默认使用0,保存两次就会出现异常
    • 表中某些字段值是0,无法区分是没存值还是存的值就是0

    最好不要使用final修饰持久化类

    • 主要原因是影响延迟加载的使用,延迟加载是用于优化hibernate的
    • 延迟加载返回的是一个代理对象,hibernate延迟加载是使用javassist技术来实现的
    • javassist可以对没有实现接口的类产生代理,使用字节码增强技术继承这个类并进行代理
    • final修饰的类无法被继承,那么就无法产生代理对象,也就不能做延迟加载了(get方法和load方法的查询完全一致)

    主键

    主键分类

    • 自然主键:就是充当主键的字段本身具有一定的含义,是构成记录的组成部分,比如学生的学号,除了充当主键之外,同时也是学生记录的重要组成部分
    • 代理主键:就是充当主键的字段本身不具有业务意义,只具有主键作用,比如自动增长的ID
    • 实际开发中推荐使用代理主键,因为不涉及业务逻辑,后期不会发生修改源代码的情况(OCP原则)

    主键生成策略

    <hibernate-mapping>
    	<!-- 配置表与实体的映射关系 -->
    	<class name="com.qf.entity.User" table="user">
    		<id name="id" column="id">
    			<!-- 主键生成策略 -->
    			<generator class="native"></generator>
    		</id>
    		<property name="name" column="name"/>
    		<property name="password" column="password"/>
    	</class>
    </hibernate-mapping>

    increment

    • 由Hibernate从数据库中取出主键的最大值(每个session只取1次),以该值为基础,每次增量为1
    • 适用于int、short、long类型的主键
    • 线程不安全,适用于单线程程序

    identity

    • identity由底层数据库生成标识符
      • identity是由数据库自己生成的,但这个主键必须设置为自增长,使用identity的前提条件是底层数据库支持自动增长字段类型
      • 适用DB2、SQL Server、MySQL、Sybase和HypersonicSQL,不适用Oracle
    • 适用于int、short、long类型的主键
    • 线程安全

    sequence

    • 采用数据库提供的sequence机制生成主键,需要数据库支持sequence
    • oralce、DB、SAP DB、PostgerSQL、McKoi中的sequence适用,Mysql不适用 
    • 适用于int、short、long类型的主键

    uuid

    • Hibernate在保存对象时,生成一个UUID字符串作为主键,保证了唯一性,但其并无任何业务逻辑意义,只能作为主键
    • 唯一缺点长度较大,32位(Hibernate将UUID中间的“-”删除了)的字符串,占用存储空间大
    • Hibernate在维护主键时,不用去数据库查询,从而提高效率,而且它是跨数据库的,以后切换数据库极其方便

    native(常用)

    • native由hibernate根据使用的数据库自行判断采用identity、hilo、sequence其中一种作为主键生成方式,灵活性很强

    assigned

    • Hibernate不负责维护主键生成
    • 人为控制主键生成,存储对象前,必须要使用主键的setter方法给主键赋值

    foreign

    • 使用另外一个相关联的对象的主键作为该对象主键
    • 主要用于一对一关系中

    持久化类的状态

    状态

    • 瞬时态:没有唯一标识OID(映射到数据库表的主键上具体的值),也不被session管理
    • 持久态:有唯一标识OID,被session管理
    • 脱管态:有唯一标识OID,不被session管理
            @Test
    	public void save(){
    		Session session = SessionFactoryUtil.getSession();
    		
    		Transaction ts = session.beginTransaction();
    		//瞬时态对象:新建对象,还没有唯一标识OID,也没有被session对象管理
    		User user = new User("hz", "0");
    		
    		//持久态对象:有唯一标识OID,并且被session对象管理
    		Serializable save = session.save(user);
    		System.out.println("user:"+user);
    		
    		ts.commit();
    		session.close();
    		
    		//脱管态对象:session销毁了,不被session对象管理,但是还有唯一标识OID
    		System.out.println("user:"+user);
    	}

    几种状态的转换

    瞬时态对象

    获取:User user = new User();

    转换

    • 转换成持久态对象:save()、saveOrUpdate()
    • 转换成脱管态对象:user.setId(2);

    持久态对象

    获取:get()、load()、find()、iterate()

    转换

    • 转换成瞬时态对象:delete()
    • 转换成脱管态对象:
      • session.close():销毁session对象
      • session.clear():清空所有对象
      • session.evict(obj):清空某一个对象

    脱管态对象

    获取:User user = new User(3,"","");或者User user = new User(); user.setId(3);

    转换

    • 转换成瞬时态对象:user.setId(null);
    • 转换成持久态对象:update()、saveOrUpdate()、lock()

    持久态对象可以自动更新数据库

            @Test
    	public void test(){
    		Session session = SessionFactoryUtil.getSession();
    		Transaction ts = session.beginTransaction();
    		
    		//获得持久化对象
    		User user = session.get(User.class, 1);
    		System.out.println("name:"+user.getName());
    		user.setName("test");
    		
    		ts.commit();
    		session.close();
    	}        
    

      控制台输出

    Hibernate: 
        select
            user0_.id as id1_0_0_,
            user0_.name as name2_0_0_,
            user0_.password as password3_0_0_ 
        from
            user user0_ 
        where
            user0_.id=?
    name:wxf
    Hibernate: 
        update
            user 
        set
            name=?,
            password=? 
        where
            id=?

    再次执行test()方法,console输出

    Hibernate: 
        select
            user0_.id as id1_0_0_,
            user0_.name as name2_0_0_,
            user0_.password as password3_0_0_ 
        from
            user user0_ 
        where
            user0_.id=?
    name:test
    • 测试方法中并没有做update操作,但是执行了update操作,是因为get方法获取的user是持久化对象,可以自动更新数据库
    • 如果setName方法设置的值和数据库里的name一样,也不会执行update操作
  • 相关阅读:
    C#中,表达式的计算遵循一个规律:从左到右依次计算。
    C#关闭显示屏,使显示屏处于待机状态
    一些值得关注的网站
    BackgroundWorker用法
    Servlet生命周期与工作原理
    Java中ArrayList和LinkedList区别
    JAVA中的权限修饰符
    JAVA中Action层, Service层 ,modle层 和 Dao层的功能区分
    Blob和Clob在JDBC中的简介
    ACID数据库事务正确执行的四个基本要素的缩写
  • 原文地址:https://www.cnblogs.com/qf123/p/10150561.html
Copyright © 2020-2023  润新知