持久化类的概述
什么是持久化类
持久化:将内存中的一个对象持久化到数据库中的过程。 Hibernate框架就是用来进行持久化的框架
持久化的类:一个java对象与数据库的表建立了映射关系, 那么这个类在Hibernate中就称之为持久化类。
持久化类 = java 类+ 映射文件
持久化类的编写规则:
对持久化类提供一个无参数的构造器。 Hibernate当中底层要通过反射生成实例。
属性私有,对私有的属性提供publci的set/get方法 Hibernate中获得, 设置对象的值。
对持久化类提供一个唯一的标识OID 和 数据库表主键对应。 java当中通过对象的地址区分是否是同一个对象, 数据库中通过主键确定是否是同一个记录。 在Hibernate当中通过持久化类的OID的属性区分是否是同一个对象。
持久化类当中的属性尽量使用包装类的类型。 因为基本数据类型默认值是0,会产生很多的歧义。 包装类的默认类型是NULL。
持久化的类不要使用final进行修饰 Hibernate当中的延迟加载, 是Hibernate当中的一个优化手段, 返回的是一个代理对象(CGLIB-使用了字节码的增强技术,继承了这个类进行代理)如果不能被继承, 就不能产生代理对象,*延迟加载就会失效 *,get方法和load方法就会产生一样的效果(演示)。
1.3.主键的生成策略
1.3.1:主键的分类
自然主键:
(一般不推荐使用)
主键的本身就是表中的一个字段。(可以是实体当中的一个具体的属性)
创建一个人员表,人员表当中都会一个身份证号(唯一不可重复),使用了身份证号作为主键,这样的主键就是自然主键。
代理主键:
主键的本身不是表当中必须的一个字段, (不是实体当中的具体的某个属性)
创建一个人员表,没有使用人员中的身份证号, 使用了和这个表当中不相关的字段,ID。这样的主键就是代理主键 。
总结:
**在实际开发当中, 尽量使用代理主键。
1:一旦自然主键参与到了业务逻辑当中, 后期可能需要需要源代码。
2:好的程序设计满足的原则是ocp原则, 对程序的扩展open的, 对修改源代码是close的。
1.3.2:主键的主键生成策略
Hibernate当中的主键生成策略
在实际的开发过程当中一般不允许用户手动设置主键, 一般将主键交给数据库, 手动编写进行配置, 在Hibernate当中为了程序的编写, 提供了很多的主键的生成策略。
Increment :
Hibernate当中提供的自动增长机制, 使用short , int , long类型的主键, 在单线程当中使用。
首先会发送一条sql 语句: select max(id) from tableName ,然后id+1, 作为下一条记录的主键。 (*)
identity :
使用short int long 类型的主键, 使用的是数据库底层的自动增长机制。有自动增长的的数据库。 Mysql MSSQL ,但是Oracle 没有自动增长。
squence :
使用short int long 类型的主键, 采用序列的方式。 oracle 就支持序列。 Mysql 就不能使用序列。
uuid :
使用于字符串类型的主键。 会使用Hibernate当中的随机方式生成字符串。
native (用的最多的) :
本地策略, 可以是indentify 和 Sequence 之间自动切换。
assigned :
Hibernate放弃主键的管理, 通过手动现写程序或者用户自己设置。
foreign :
外部的, 在一对一的关联映射的情况下会使用。 (主键对应)一个表的主键在另外一个表当中还充当主键字段。 很少使用。
1.3.2.2代码的测试:
/*
- 测试主键的生成策略:
*/
在hibernate.hbm.xml中配置:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- class : 标签:
name : 实体bean的全路径名称:
table: 实体类对应的底层数据库表: 当实体类的名称和表的名称一致的情况下, 可以省略的。
catalog: 对应数据库的名称: 可以省略
-->
<class name="com.yidongxueyuan.domain.Customer" table="cst_customer" >
<!-- 配置主键字段:
单独的标签: id :
name: 实体当中的属性:
column: 对应表当中的字段。
制定主键的生成策略:
-->
<id name="cust_id" column="cust_id" >
<!-- 主键的生成策略
genderator: 明确主键字段是来维护: 维护的具体的方式:
主键字段: 可以有底层具体的数据库来维护: 还可以通过程序员编写代码维护, 可以交给Hibernate来维护。
increment: short int long : Hibernate以自增的方式维护。 只能在单线程使用:
原理: select max(id) from table;
insert into table (id) vlaues(id+1);
不能应用在集群环境或者是多线程环境当中:
多线程: select max(id) from table;
两个线程: 获得了同一个 max(id) 值:
当第一个线程获得了cpu的执行权: 执行插入, 能够将数据正常的插入:
第二个线程, 获得cpu的执行权, 不能插入, 主键重复。
identity : 适应于short int long类型的主键字段: 底层是使用数据库的主键自增机制:
前提: 数据库必须支持主键自增: Mysql DB2 Sybase
Oracle: 不支持主键自增:
Sequence :适应于short int long类型的主键字段 适合数据库支持序列:
Mysql: 不支持序列:
ORACLE: 可以使用Sequence:
uuid: 主键字段是varchar 或者是varchar2类型: Hibernate能够自动生成uuid 值 做主键。
native: 本地策略: 能够根据配置的方言自动选择主键的类型:
Mysql: identity:
Oracle: Sequence:
Assigned : Hibernate放弃维护主键: 此时必须由程序员自己管理:
-->
<generator class="native"/>
</id>
<!-- 普通的字段:
property:表示这是普通的字段:
name: 实体bean的属性。
column: 表的字段;
-->
<property name="cust_name" column="cust_name" length="21" type="string" not-null="true" unique="false"/>
<property name="cust_source" column="cust_source"/>
<property name="cust_industry" column="cust_industry"/>
<property name="cust_level" column="cust_level"/>
<property name="cust_phone" column="cust_phone"/>
<property name="cust_mobile" column="cust_mobile"/>
</class>
</hibernate-mapping>
public class TestDemo {
/*测试increment : 多条线程会发生问题:
* 当第一条线程: 发生一个sql 语句: select max(id) from tableName;查询到一个值。
* 再次启动一天线程: 发送一个sql 语句。 select max(id) from tableName; 和上次查询到相同的值。
* 当一条sql 语句执行操作的时候, 添加成功。
* 当另外一条sql 执行添加操作的时候, 添加失败。
*
* 测试: identity :
* 创建的Mysql 数据库当中的表: 主键具备自增的功能:
*
* Sequence: 应用于oracle数据库。
* native: 在Sequence和native之间进行切换。 根据不同的数据库进行选择:
*
* uuid: 适用于主键字段是String类, 需要修改表主键的类型, 然后的主键字段是uuid的值。
* assigned: 放弃维护主键字段, 把主键字段交给了用户自己设定。