HIBERNATE
hibernate常用类
sessionFactory(会话工厂)
是一个线程安全,终态的,代理对象,表示持久化对象和数据库的映射。作为建立session
(会话实例)的工厂。会话工厂建立的代价很大(内存,cpu占用大)所以一个程序只能
有一个会话工厂。会话工厂维护所以的 session,二级缓存,连接池,事务。
Session(会话)
单线程,短生命周期的对象,封装了JDBC连接对象java.sql.Connection
作为实例事务的对象,维护持久化对象可复读的持久化内容(一级缓存)。
Transaction(事务)
单线程,短生命周期的对象,用于界定物理事务的具体范围。
context session(上下文会话)
需要一个特定的session(会话)会影响整体特定的上下文范围。
Hibernate3以前使用session有两种方式:
- 利用TheadLocal(本地线程)加辅助类HibernateUtil建立session会话。
- 使用第三方框架如spring,框架提供上下文的session的代理或拦截。
从3版本开始通过sessionFactory.getCurrentSession()方法进行JTA事务处理。
跟踪当前会话的上下文
JTASessionContext:由JTA 事务界定当前会话范围与跟踪当前会话。
ThreadLocalSessionContext:由执行的线程跟踪当前会话。
ManagedSessionContext:由执行的线程跟踪当前会话。自己负责绑定与解绑
会话实例,通常在静态方法中处理,这时session不能打开,关闭,刷新。
前两种提供一次会话,一次事务。
持久化对象(域模型)
实现无参构造
提供标识(identifier)属性:在持久化对象中声明唯一标识列
使用非final类:运行时可以懒加载实体对象数据,这个功能依赖于实体类是非final类
为持久化属性声明get,set方法:遵守JavaBean实体规范
实现equals()与hashCode():数据库有实例相同的值,通过对象比较得到唯一的实例。
session和持久化实体对象关系
通过org.hibernate.Session API和javax.peristence.EntityManager API 处理持久化数据
环境,这个概念称为持久化上下文。
manged(托管态)原来叫Persistent 持久态
实体已经有了ID 并且与持久化上下文关联。在物理数据库中可能存在也可能不存在。
transient(瞬时态、临时态)
实体刚刚被实例化并且没有与持久化上下文关联。
detached(脱管态、游离态)
实体已经有了关联的ID,但是不再与持久化上下文关联。
removed(删除态)
实体已有了ID 并且与持久化上下文有了关联,然而数据库已经计划删除数据。
关系图
hibernate配置
hibernate-cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <!--Hibernate的配置信息 --> <hibernate-configuration> <!--配置工厂信息 --> <session-factory> <!--数据库连接配置--> <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property> <property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property> <property name="hibernate.connection.username">user</property> <property name="hibernate.connection.password">pwd</property> <!--c3p0连接池--> <property name="hibernate.c3p0.min_size">5</property> <property name="hibernate.c3p0.max_size">10</property> <!--最小连接数超出取3个连接--> <property name="hibernate.c3p0.acquire_increment">3</property> <!--2秒超时--> <property name="hibernate.c3p0.timeout">2000</property> <!--活跃连接测试2秒检测一次当大于超时时间清空--> <property name="hibernate.c3p0.idle_test_period">2000</property> <!--hibernate配置--> <!--设置方言 指定为Oracle其它数据库执行sql无效例:mysql limit分页--> <property name="dialect">org.hibernate.dialect.OracleDialect</property> <!--hibernate mapper DDL 自动 --> <!--create执行SQL每次创建表,update有就刷新表数据,没有先创建表在执行SQL,其它省略:不会使用--> <property name="hbm2ddl.auto">update</property> <!--控制台输出执行SQL--> <property name="show_sql">true</property> <!--格式化SQL输出换行--> <property name="format_sql">true</property> <!--批量增删改100条提交一次(100最佳性能)--> <property name="hibernate.jdbc.batch_size">100</property> <!--批量查询读取记录50条查一次(50以上,性能提升的非常微弱)--> <property name="hibernate.jdbc.fetch_size">50</property> <!--数据库和持久化对象映射--> <mapping resource="MyTest.hbm.xml"/> </session-factory> </hibernate-configuration>
myTest.hbm.xml
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <!--表和对象的映射--> <!--对象所在entity包--> <hibernate-mapping package="com.cn.hibernate4.entity"> <!--name为对象名 table数据库表名--> <!--动态处理数据有的数据处理NULL不进行操作--> <class name="MyTest" table="MY_TEST" dynamic-update="true" dynamic-insert="true"> <!--id 主键 name对象字段 column为数据库列 数据类型长度 默认字符类型--> <id name="id" column="ID" length="32"> <!--generator:主键生成策略 1、native:自动增长,会根据当前的数据库自动切换 2、identity:DB2,MySQL, MS SQL Server, Sybase的自增 3、sequence:Oracle的自增序列 4、uuid:32位字符串 5、assigned:自定义字符串 6、foreign:外键 7、increment:自增 多线程会出现异常--> <generator class="assigned"/> </id> <property name="name" column="NAME"/> </class> </hibernate-mapping>
Test
import com.cn.hibernate5.entity.MyTest;
import com.cn.hibernate5.entity.MyTest; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; public class Test { public static void main(String[] args) { //hibernate3.x和hibernate5.x使用方式 // 1、加载配置文件(在根目录下自动获取配置文件) // //Configuration config = new Configuration().configure(); Configuration config = new Configuration().configure("hibernate.cfg.xml"); // 2、创建Session工厂 SessionFactory sessionFactory = config.buildSessionFactory(); // 3、创建Session对象 Session session = sessionFactory.openSession(); // 4、开启事务` Transaction transaction = session.beginTransaction(); MyTest test = new MyTest("123", "失了智"); // 5、添加 // session.save(test); // //更新 通过MyTest.hbm.xml识别 id 进行name更新 // session.update(test); // //删除 通过MyTest.hbm.xml识别 id 进行删除 // session.delete(test); // // 查询 不需要事务 session.load(MyTest.class, "123"); // 6、提交事务 transaction.commit(); // 7、关闭会 session.close(); // 8、关闭session工厂 sessionFactory.close(); } //hibernate4获取session对象 // Configuration config = new Configuration().configure(); // ServiceRegistry service = new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry(); // SessionFactory sessionFactory = config.buildSessionFactory(service); // final Session session = sessionFactory.openSession();
对象和对象的关系
多对一
多个学生对一个班级
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.cn.hibernate5.entity">
<!--动态处理数据对象属性为null不进行赋值为空字符操作-->
<class name="Student" table="my_student" dynamic-update="true" dynamic-insert="true">
<id name="stuId" column="stu_id" length="32">
<generator class="assigned"/>
</id>
<property name="stuName" column="stu_name" not-null="true"/>
<!--设置外键-->
<many-to-one name="grade" column="g_id" class="Grade"/>
</class>
</hibernate-mapping>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.cn.hibernate5.entity">
<class name="Grade" table="my_grade" dynamic-insert="true" dynamic-update="true">
<id name="gradeId" column="grade_id" length="32">
<generator class="assigned"/>
</id>
<property name="gradeName" column="grade_name"/>
<!--一对多 -->
<!--inverse指由学生表去维护关系(有set的一方不去维护关系)-->
<!--cascade级联操作主表进行插入更新影响子表-->
<set name="students" table="my_student" inverse="true" cascade="save-update">
<key column="g_id"/>
<one-to-many class="Student"/>
</set>
</class>
</hibernate-mapping>
一对一
新增列设置外键
一个人对应一个身份证
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.cn.hibernate5.entity">
<class name="Person" table="my_person" dynamic-insert="true" dynamic-update="true">
<id name="pId" column="person_id" length="32">
<generator class="assigned"/>
</id>
<property name="pName" column="person_name"/>
<!--生成外键(并不是多对一通过unique指定关联的外键唯一不容许重复)-->
<!--使用many-to-one一定会设置数据库的对应的列-->
<!--unique-key多列设置才起效多列中不容许重复-->
<many-to-one name="Card" column="p_card" cascade="save-update" class="Card" unique="true"/>
</class>
</hibernate-mapping>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.cn.hibernate5.entity"> <class name="Card" table="my_card" dynamic-insert="true" dynamic-update="true"> <id name="iId" column="card_id" length="32"> <generator class="assigned"/> </id> <property name="iName" column="card_name"/> <!--配置人的身份证一对一的参考(关系参考[property-ref="Card"]
可以不进行配置,不建议使用)自动识别 --> <one-to-one name="person" cascade="save-update" class="Person" property-ref="Card"/> </class> </hibernate-mapping>
主键关联外键
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.cn.hibernate4.entity">
<class name="Person" table="my_person" dynamic-insert="true" dynamic-update="true">
<id name="pId" column="person_id" length="32">
<!—声明主键作为外键进行关联-->
<generator class="foreign">
<!—声明当前表外键值参考card表主键-->
<param name="property">card</param>
</generator>
</id>
<property name="pName" column="person_name"/>
<!--配置人的身份证一对一的参考-->
<!--constrained="true"添加当前表外键的外键约束关联card表-->
<one-to-one name="card" class="Card" constrained="true"/>
</class>
</hibernate-mapping>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.cn.hibernate4.entity">
<class name="IDCard" table="my_card" dynamic-insert="true" dynamic-update="true">
<id name="iId" column="card_id" length="32">
<generator class="assigned"/>
</id>
<property name="iName" column="card_name"/>
<one-to-one name="person" cascade="save-update" class="Person"/>
</class>
</hibernate-mapping>
多对多
多对多是将多对多拆分为2个多对一
3张表
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.cn.hibernate4.entity">
<!--动态处理数据对象属性为null不进行赋值为空字符操作-->
<class name="Stu" table="my_stu" dynamic-update="true" dynamic-insert="true">
<id name="stuId" column="stu_id" length="32">
<generator class="uuid"/>
</id>
<property name="stuName" column="stu_name" not-null="true"/>
<!--新建关系表(inverse="true"不可使用双方关系都需要维护)-->
<set name="courseSet" table="stu_course" >
<!--建立当前表外键关联当前表ID(stu) s_id为stu_course列-->
<key column="s_id"/>
<!--多对多关联关系表课程表id(通过关系表c_id关联课程表)-->
<many-to-many class="Course" column="c_id"/>
</set>
</class>
</hibernate-mapping>
<!DOCTYPE hibernate-mapping PUBLIC
<hibernate-mapping package="com.cn.hibernate4.entity">
<!--动态处理数据对象属性为null不进行赋值为空字符操作-->
<class name="Course" table="my_course" dynamic-update="true" dynamic-insert="true">
<id name="cId" column="c_id" length="32">
<generator class="uuid"/>
</id>
<property name="cName" column="c_name" not-null="true"/>
<!--将多对多拆分为2个多对一-->
<set name="stuSet" table="stu_course">
<!--设置外键关联学生表-->
<key column="c_id"/>
<!--多对多关联课程表-->
<many-to-many class="Stu" column="s_id"/>
</set>
</class>
</hibernate-mapping>
对象和对象的关系
多对一
多个学生对一个班级
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.cn.hibernate5.entity">
<!--动态处理数据对象属性为null不进行赋值为空字符操作-->
<class name="Student" table="my_student" dynamic-update="true" dynamic-insert="true">
<id name="stuId" column="stu_id" length="32">
<generator class="assigned"/>
</id>
<property name="stuName" column="stu_name" not-null="true"/>
<!--设置外键-->
<many-to-one name="grade" column="g_id" class="Grade"/>
</class>
</hibernate-mapping>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.cn.hibernate5.entity">
<class name="Grade" table="my_grade" dynamic-insert="true" dynamic-update="true">
<id name="gradeId" column="grade_id" length="32">
<generator class="assigned"/>
</id>
<property name="gradeName" column="grade_name"/>
<!--一对多 -->
<!--inverse指由学生表去维护关系(有set的一方不去维护关系)-->
<!--cascade级联操作主表进行插入更新影响子表-->
<set name="students" table="my_student" inverse="true" cascade="save-update">
<key column="g_id"/>
<one-to-many class="Student"/>
</set>
</class>
</hibernate-mapping>
一对一
新增列设置外键
一个人对应一个身份证
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.cn.hibernate5.entity">
<class name="Person" table="my_person" dynamic-insert="true" dynamic-update="true">
<id name="pId" column="person_id" length="32">
<generator class="assigned"/>
</id>
<property name="pName" column="person_name"/>
<!--生成外键(并不是多对一通过unique指定关联的外键唯一不容许重复)-->
<!--使用many-to-one一定会设置数据库的对应的列-->
<!--unique-key多列设置才起效多列中不容许重复-->
<many-to-one name="Card" column="p_card" cascade="save-update" class="Card" unique="true"/>
</class>
</hibernate-mapping>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.cn.hibernate5.entity"> <class name="Card" table="my_card" dynamic-insert="true" dynamic-update="true"> <id name="iId" column="card_id" length="32"> <generator class="assigned"/> </id> <property name="iName" column="card_name"/> <!--配置人的身份证一对一的参考(关系参考[property-ref="Card"]
可以不进行配置,不建议使用)自动识别 --> <one-to-one name="person" cascade="save-update" class="Person" property-ref="Card"/> </class> </hibernate-mapping>
主键关联外键
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.cn.hibernate4.entity">
<class name="Person" table="my_person" dynamic-insert="true" dynamic-update="true">
<id name="pId" column="person_id" length="32">
<!—声明主键作为外键进行关联-->
<generator class="foreign">
<!—声明当前表外键值参考card表主键-->
<param name="property">card</param>
</generator>
</id>
<property name="pName" column="person_name"/>
<!--配置人的身份证一对一的参考-->
<!--constrained="true"添加当前表外键的外键约束关联card表-->
<one-to-one name="card" class="Card" constrained="true"/>
</class>
</hibernate-mapping>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.cn.hibernate4.entity">
<class name="IDCard" table="my_card" dynamic-insert="true" dynamic-update="true">
<id name="iId" column="card_id" length="32">
<generator class="assigned"/>
</id>
<property name="iName" column="card_name"/>
<one-to-one name="person" cascade="save-update" class="Person"/>
</class>
</hibernate-mapping>
多对多
多对多是将多对多拆分为2个多对一
3张表
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.cn.hibernate4.entity">
<!--动态处理数据对象属性为null不进行赋值为空字符操作-->
<class name="Stu" table="my_stu" dynamic-update="true" dynamic-insert="true">
<id name="stuId" column="stu_id" length="32">
<generator class="uuid"/>
</id>
<property name="stuName" column="stu_name" not-null="true"/>
<!--新建关系表(inverse="true"不可使用双方关系都需要维护)-->
<set name="courseSet" table="stu_course" >
<!--建立当前表外键关联当前表ID(stu) s_id为stu_course列-->
<key column="s_id"/>
<!--多对多关联关系表课程表id(通过关系表c_id关联课程表)-->
<many-to-many class="Course" column="c_id"/>
</set>
</class>
</hibernate-mapping>
<!DOCTYPE hibernate-mapping PUBLIC
<hibernate-mapping package="com.cn.hibernate4.entity">
<!--动态处理数据对象属性为null不进行赋值为空字符操作-->
<class name="Course" table="my_course" dynamic-update="true" dynamic-insert="true">
<id name="cId" column="c_id" length="32">
<generator class="uuid"/>
</id>
<property name="cName" column="c_name" not-null="true"/>
<!--将多对多拆分为2个多对一-->
<set name="stuSet" table="stu_course">
<!--设置外键关联学生表-->
<key column="c_id"/>
<!--多对多关联课程表-->
<many-to-many class="Stu" column="s_id"/>
</set>
</class>
</hibernate-mapping>
检索策
类级别
立即检索
get()
延时检索
load()
get()和load()区别
Get:hibernate会确认该对象id对应的数据是否存在,先去缓存中查询没有查询数据库,数据库没有返回为null。(get查询的结果直接赋值给对象,session关闭对象不为空)。
Load:hibernate认为该id有对用的数据库记录,先去缓存中查询没有创建代理,所以可以放心使用使用代理延时加载该对象。没有对应数据库记录抛出ObjectNotFound异常。(使用的代理对象,session关闭,对象再获取值为null)。
级联级别
默认:fetch=”select”
另外发送一条select语句抓取当前对象关联实体或集合。(两条SQL)
fetch=”join”
hibernate会通过select语句使用外连接来加载其关联实体或集合(一条SQL,SQL关键字left outer join)
此时lazy会失效
fetch=”subselect”
嵌套子查询 SQL关键字in