目录
9.2 批处理解决方案 – Cache缓存控制.... 43
Hibernate
1.1何谓框架
框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种定义认为,框架是可被应用开发者定制的应用骨架。前者是从应用方面而后者是从目的方面给出的定义
1.2框架的通俗解释
- 用代码写死某个代码流程
- 用代码实现流程中可以实现的环节
- 最后将流程中那些不能实现的环节交给调用者去实现
- 具体方法在编写Hibernate内核源码时大家就能体会到
1.3 ORM介绍
ORM视图
1.4 何谓ORM
对象关系映射(Object Relational Mapping,简称ORM)是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将java程序中的对象自动持久化到关系数据库中。本质上就是将数据从一种形式转换到另外一种形式
1.5 hibernate所需要的包
Hibernate基本包:(
antlr-*.jar,
dom4j-*.jar,
hibernate-commons-annotations-*.Final.jar,
hibernate-core-*.Final*.jar,
hibernate-jpa-*-api-*.Final.jar,
javassist-*-GA.jar,
jboss-logging-*.GA.jar,
jboss-transaction-api_*_spec-*.Final.jar,
)
- hibernate 是一个O/R mapping框架,它使得与关系数据库打交道变得十分轻松,就像您的数据库中包含每天使用的普通Java对象一样,同时不必考虑如何把它们从神秘的数据库表中取出(或放回到数据库表中)。
2.2使用了Hibernate的程序
有数据库中的各张表
有程序里的各个对象
当然需要一个“翻译”来告诉程序里的各个对象“各张表在程序里分别对应那个对象”
2.3Hibernate配置文件
Hibernate配置文件:hibernate.cfg.xml
数据库的表
与数据库的表对应的对象: JavaBean
JavaBean与库表的映射配置:*.hbm.xml
2.4hibernate.cfg.xml样例
<!—步骤:
一.hibernate.cfg配置:hibernate-configuration
二.session会话工厂配置:session-factory
1.数据库连接配置 connection
驱动方式:name="connection.driver_class"
数据库地址:name="connection.url"
用户名:name="connection.username"
密码:name="connection.password"
连接池配置:name="connection.pool_size"
2.数据库方言:name="dialect"
3.产生session的方式:name="current_session_context_class"
4.是否在控制台上打印SQL:name="show_sql"
5.是否自动创建表:name="hbm2ddl.auto"
6.关联表的映射文件:resource="映射文件路径"
-->
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEhibernate-configurationPUBLIC"-//Hibernate/Hibernate Configuration DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 数据库连接配置 -->
<propertyname="connection.driver_class">org.gjt.mm.mysql.Driver</property>
<propertyname="connection.url">jdbc:mysql://localhost:3306/hibernate_demo</property>
<propertyname="connection.username">root</property>
<propertyname="connection.password"></property>
<!-- 连接池配置 -->
<propertyname="connection.pool_size">1</property>
<!-- 不同数据库使用的SQL选择 -->
<propertyname="dialect">org.hibernate.dialect.MySQLDialect</property>
<!--决定是采用thread或jta或自定义的方式来产生session -->
<propertyname="current_session_context_class">thread</property>
<!-- 是否在控制台上打印SQL -->
<propertyname="show_sql">true</property>
<!-- 是否根据配置自动创建库表,无论表是否存在都会覆盖创建表。此功能小心使用,生产环境中不能使用 -->
<!-- create:创建,updata:更新,none:不做任何操作 -->
<propertyname="hbm2ddl.auto">updata</property>
<mappingresource="com/gist/entity/Student.hbm.xml"></mapping>
</session-factory>
</hibernate-configuration>
2.5Javabean
package com.gist.entity;
publicclass Student {
privatelongid; //主键,id
private String username; //名字
private String email; //电子邮箱
private String password; //密码
private Integer age; //年龄
public Student(){
}
public Student(String username,Integer age){
this.username=username;
this.age=age;
}
public Student(long id,String username,String email,String password,Integer age){
this.id=id;
this.username=username;
this.email=email;
this.password=password;
this.age=age;
}
@Override
public String toString() {
return"Student [id=" + id + ", username=" + username + ", email="
+ email + ", password=" + password + ", age=" + age + "]";
}
public Integer getAge() {
returnage;
}
publicvoid setAge(Integer age) {
this.age = age;
}
publiclong getId() {
returnid;
}
publicvoid setId(long id) {
this.id = id;
}
public String getUsername() {
returnusername;
}
publicvoid setUsername(String username) {
this.username = username;
}
public String getEmail() {
returnemail;
}
publicvoid setEmail(String email) {
this.email = email;
}
public String getPassword() {
returnpassword;
}
publicvoid setPassword(String password) {
this.password = password;
}
}
2.6*.hbm.xml
<!--
JavaBean映射文件
一.hibernate映射配置:hibernate-mapping
JavaBean类与属性---对应的表与字段
二.class name="JavaBean类路径" table="表(类的小写javabean)"
name类属性---column表字段
1.id
是否自动生成id:generator class="uuid.hex"
2.属性
-->
<?xmlversion="1.0"encoding="utf-8"?>
<!DOCTYPEhibernate-mappingSYSTEM"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.gist.entity.Student" table="student"lazy="false">
<!-- 绑定类的属性跟表的字段对应关系 -->
<!-- id为表的主键,id是用来定义主键property定义属性 -->
<idname="id"column="id"></id>
<!-- property定义属性,column是表中列的名称,entity属性name是对应映射关系 -->
<propertyname="username"column="username"></property>
<propertyname="email"column="email"></property>
<propertyname="password"column="password"></property>
<propertyname="age"column="age"></property>
</class>
</hibernate-mapping>
2.7Hibernate使用流程
- 建立库表(找发言人)
- 编写hibernate.cfg.xml(总体配置)
- 编写POJO(找各国代表)
- 配置POJO与库表的映射(请翻译)
- 编写数据库操作代码(开始开会)
3.初始化Hibernate
3.1初始化流程
初始化流程
加载配置文件
创建会话工厂
开启会话
启动事务
执行各种数据库操作
提交或回滚事务
关闭会话
关闭会话工厂
3.2 Hibernate流程代码
//1.加载配置文件
Configuration configuration = new Configuration();
//输入总配置文件路径,相对路径,加载配置文件的数据还没建表
configuration.configure("./hibernate.cfg.xml");
//2.通过configuration获取会话工厂
SessionFactory buildSessionFactory = configuration.buildSessionFactory();
//3.创建会话,此刻开始创建数据数据库表
Session session = buildSessionFactory.openSession();
//4.开启事务
Transaction transaction = session.beginTransaction();
//5.操作数据库/操作数据库需要处理异常,因为数据可能有误,这样有利于处理事务
try{
//添加对象
session.save(entity);
//提交事务
transaction.commit();
}catch(Exception e){
//回滚事务
transaction.rollback();
}finally{
session.close();
buildSessionFactory.close();
}
3.3 插入数据
//操作数据库
Student student = new Student();
student.setId(1003L);
student.setUsername("小曹");
student.setPassword("123456");
student.setEmail("xiaocao@qq.com");
student.setAge(18);
//插入数据
session.save(student);
3.4 删除数据
Student student = new Student();
student.setId(1003L);
session.delete(student);
3.5根据主键查询数据
第一种方式:
session.get
Student student = ( Student )session.get( Student.class, “3” );
System.out.println( student.getStudentPassword() );
第二种方式:
session.load
Student student = ( Student )session.load( Student.class, “3” );
System.out.println( student.getStudentPassword() );
Get方法与load方法的区别:
session.get方法获取;如果ID不存在,返回null对象,因为在get方法采用立即加载机制
session.load方法获取;如果ID不存在,会抛ObjectNotFoundException异常 ,load方法采用懒加载机制。
3.6 更新数据1
//5.操作数据库
Student student = new Student();
student.setId(1003L);
student.setUsername("小郑");
student.setPassword("123456");
student.setEmail("xiaozheng@qq.com");
student.setAge(18);
session.uqdate(student);
3.7更新数据2
-
Student s2 = ( Student )session.load( Student.class, “3” ); S2.setStudentName( “Jason” );
方法一:session.update方法,如果对象的属性没有值,hibernate依然会设置一个null值。所以在执行更新操作之前
先根据ID把数据库的对象查询出来,然后再修改对象的属性值,最后在执行update方法
方法二:先根据session.load方法加载一个对象,然后直接修改对象的属性,此对象对应的数据库表就自动更新;
但是事物不提交的时候,不会自动更新
注意:如果用session.get方法加载一个对象,无论怎么修改对象属性,不会持久化到数据库里面
3.8对象状态
持久化:把数据(如内存中的对象)保存到可永久保存的存储设备(如数据库、磁盘)。
- 临时状态(transient)
- 刚刚用new语句创建,还没有被持久化,不处于Session的缓存中面处于临时状态的java对象被称为临时对象。
- 例:刚创建被没有被hibernate处理过,或被delete()。’
- 持久化状态(persistent)
- 已经被持久化,加入到session的缓存中,处于持久化状态的java对象被成为持久化对象。
- 例:被save()/saveOrUpdate/lock()。
- 被Hibernate处理过,与数据库里的某条记录建立了同步关系的对象的状态
- 被load方法查询返回的对象属于持久化对象
- 修改持久化对象的某些属性后,事务一旦提交,Hibernate会自动将这些数据的变化同步到数据库
- 游离状态(detached)
- 已经被持久化过,但不再处于session的缓存中,处于游离状态的java对象被称为游离对象。
- 例:被close()/clear()/evict()过的对象不处于session。
4.1 POJO映射文件
POJO映射文件---类映射
<class
name="POJO的类全路径"
table="对应的库表名"
discriminator-value="discriminator_value"
dynamic-update="true | false"
dynamic-insert="true | false"
select-before-update="true | false"
polymorphism="implicit | explicit"
where="查询时使用的SQL的条件子句"
lazy="true | false"
/>
POJO映射文件实例---类映射
<class
name="com.gist.entity.Student"
table="student"
discriminator-value="com.gist.entity.Student"
dynamic-update="true"
dynamic-insert="true"
select-before-update="true"
polymorphism="implicit"
where="age<18"
lazy="true"
/>
4.2 POJO映射文件---详解
- Name:POJO的类的全路径。本项一定要配置。
- Table:POJO对应的库表名。本项一定要配置。
- select-before-update:是否在执行update时发送一条select语句查询对象是否被修改过,只有修改过时,update语句才会真的被执行。本项可以不配置。默认为false。
- dynamic-update:更新SQL是否动态生成。为false时,每次更新都会将POJO的所有属性更新到DB;为true时,只更新POJO中修改过的属性。本项可以不配置。如果select-before-update=“false”,则dynamic-update 失效,变成静态update。
- dynamic-insert:插入SQL是否动态生成。为false时,每次插入都会将POJO的所有属性插入到DB;为true时,只插入POJO中非空的属性。本项可以不配置。默认为false。
- Lazy:设置延迟加载策略。本项可以不配置。
4.3 dynamic-insert效果演示
创造一个POJO实例,将它的部分属性设为null,然后用session的save方法将它插入到数据库(数据库的表结构中必须设置各个字段可以为null)
-
- Hibernate控制台上打印的insert语句(是否插入了所有属性对应的字段)
将dynamic-insert设为true,再次执行上述插入
-
- Hibernate控制台上打印的insert语句(是否没有插入值为null的属性对应的字段)
将dynamic-insert设为false,再看看效果
4.4 dynamic-update效果演示
创造一个POJO实例,将它的部分属性设为和数据库里对应字段的值相同,然后用session的update方法将它插入到数据库
-
- Hibernate控制台上打印的update语句(是否更新了所有属性对应的字段)
将dynamic-update设为true,再次执行上述插入
-
- Hibernate控制台上打印的update语句(是否没有更新值和数据库里对应字段相同的属性对应的字段)
将dynamic-update设为false,再看看效果
4.5 POJO映射文件 – 属性映射
5.1 Hibernate主键配置策略
- <id>
<generator class=“主键赋值策略” />
</id>
5.2 Hibernate对主键赋值
Generator节点中class属性的值:
assigned:主键由程序生成,无需Hibernate或数据库参与。
hilo:通过hi/lo算法生成主键,需要额外的数据库保存主键生成的历史状态。
seqhilo:通过hi/lo算法生成主键,但是主键生成的历史状态保存在Sequence中。使用于Oracle等支持Sequence的数据库。
increment:主键按数值顺序递增。
indentity:采用数据库提供的主键生成机制。
sequence:采用数据库提供的Sequence机制。
native:由Hibernate根据底层数据库自行判断采用indentity, hilo或sequence中的一种。
uuid.hex:由Hibernate基于128位唯一值产生算法生成十六进制数(长度为32的字符串)。
uuid.string:与uuid.hex一样,但是生成16位未编码的字符串,在PostgreSQL等数据库中会出错。
foreign:由其他表的某字段作为主键。
5.3 主键赋值策略演示
- 使用uuid.hex
- 不为对象的主键属性赋值,有什么效果?
- 会直接生成一段字符串
- 如果又设置了主键赋值策略,又为对象的主键赋值,插入后,以哪个为准?
<id name="clientId" column="client_id">
<generatorclass="uuid.hex"></generator>
</id>
HQL方案
- 普通查询
- 查询部分字段
- 查询一个字段
- 查询多个字段
- 实例化多字段查询结果
6.1普通查询
- 在HQL中,使用的是对象,而不是库表。
- 返回的是保存着要查询的数据的对象。
Query query = session.createQuery("select stu from Student stu WHERE stu.age<19");
Object obj = query.uniqueResult();
System.out.println(obj);
- 思索和验证:查询到的结果是否是持久状态?是
6.2查询一个字段
- 在HQL中指定要查询的对象的属性。
- 取得查询结果时,查询到的属性的值不在以所属对象的形式保存在List中,而是以自身类型的形式保存在List中。
Query query = session.createQuery("select stu.username from Student stu WHERE stu.age<19");
/*//方式一
List<String> list = query.list();
for (String stu : list) {
System.out.println(stu);
}*/
//方式二
List list = query.list();
for ( int i = 0 ; i < list.size() ; i ++ ) {
String username = ( String )list.get(i);
System.out.println(username);
}
6.3查询多个字段
- 在HQL中指定要查询的对象的各个属性。
- 取得查询结果时,查询到的属性的值不在以所属对象的形式保存在List中,而是以Object数组的形式保存在List中。
Query query = session.createQuery("select stu.username,stu.age from Student stu where stu.age<20");
//方式一
List<Object []> list = query.list();
for (Object [] stu : list) {
System.out.println(Arrays.asList(stu));
}
/*//方式二
List list = query.list();
for ( int i = 0 ; i < list.size() ; i ++ ) {
Object [] res = ( Object[] )list.get(i);
String username = ( String )res[0];
Integer age = ( Integer )res[1];
System.out.println(username);
System.out.println(age);
} */
6.4实例化多个字段查询结果
将多字段查询的结果保存在对应的实例中,让查询结果以对象的形式被程序使用。
在HQL中要显示实例化结果。
对应的POJO要拥有实例化自身的构造函数
Query query = session.createQuery("select new Student(stu.username,stu.age) from Student stu where stu.age<20");
//方式一
List list = query.list();
for ( int i = 0 ; i < list.size() ; i ++ ) {
Student stu = ( Student )list.get(i);
System.out.println(stu);
}
/*//方式二
List students=query.list();
for (Iterator iterator = students.iterator(); iterator.hasNext();) {
Student student = (Student) iterator.next();
System.out.println(student.getUsername());
System.out.println(student.getAge());
}*/
Student类要拥有Student( String, int )的构造函数。
6.5统计函数调用方案
- COUNT():统计记录条数。
- MIN():求最小值。
- MAX():求最大值。
- SUM():求和。
- AVG():求平均值。
- 当查询结果中有且仅有1条记录的时候,可以方便使用:long count = ( Long )query.uniqueResult();
- Query q = session.createQuery( “SELECT COUNT(s) FROM Student s);
- Query q = session.createQuery( “SELECT MIN(s.age) FROM Student s);
- Query q = session.createQuery( “SELECT MAX(s.age) FROM Student s);
- Query q = session.createQuery( “SELECT SUM(s.age) FROM Student s);
- Query q = session.createQuery( “SELECT AVG(s.age) FROM Student s);
6.6 嵌套子查询方案
- All:所有记录。
- Any:记录中的任意一条。
- Some:与Any一样。
- In:与“=Any”一样。
- Exists:查询至少要返回一条记录。
6.6.1平均值实例
- 求平均年龄以上的学生姓名:
-
Query q = session.createQuery( “SELECT s.name FROM Student s WHERE s.age > ( SELECT AVG(s.age) FROM Student s ));
6.6.2 本地SQL检索方案
- 基本查询
- 命名查询
- 不带参数
- 带参数
6.6.3 基本查询
- 使用session的createSQLQuery方法。
- 获取查询结果以前要将别名与实体类关联起来。
String sql = “SELECT {s.*} FROM Student s”;
SQLQuery q = session.createSQLQuery( sql );
q.addEntity( “s”, Student.class );
List list = q.list();
6.6.4 命名查询
- 在POJO映射文件中对查询命名和设定。
- 在代码中用session的getNamedQuery方法来执行某命名查询。
6.6.5 命名查询---不带参数
//映射文件代码
<!-- 不带参数 -->
<sql-queryname="QueryStudentNull">
<![CDATA[
select {s.*} from Student s
]]>
<returnalias="s"class="com.gist.entity.Student"/>
</sql-query>
//hibernate操作数据库代码
Query query = session.getNamedQuery("QueryStudentNull");
List<Student> list = query.list();
for(Student stu : list){
System.out.println(stu);
}
6.6.6 命名查询---带参数
//映射文件代码
<!-- 带参数 -->
<sql-queryname="QueryStudents">
<![CDATA[
select {s.*} from Student s where s.age >:age
]]>
<returnalias="s"class="com.gist.entity.Student"/>
</sql-query>
//hibernate操作数据库代码
Query query = session.getNamedQuery("QueryStudents");
query.setInteger("age", 18);
List<Student> list = query.list();
for(Student stu : list){
System.out.println(stu);
}
6.6.7 使用UUID生成一个32位的随机数
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
System.out.println(uuid);
关联表的操作:
一对一
一对多 与 多对一
多对多
关联的高级设置
7.1一对一(关联表)
- 以主键关联
- 以外键关联
7.1.1主键关联---一对一
需求:
有两张表,如右图。
要求:对数据库进
行操作,一个劳改犯
一定有一张身份证,
而一张身份证一定属于一个劳改犯。
要求:
增删改查。
7.1.1.1 POJO
//User持久类
package com.gist.entity;
/**
* IdCard表联结的User表
* 一对一以主键关联
* @author Administrator
*/
publicclass User {
private String userId; //用户ID
private String userName;//用户名字
private IdCard idCard; //用户卡号
public String getUserId() {
returnuserId;
}
publicvoid setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
returnuserName;
}
publicvoid setUserName(String userName) {
this.userName = userName;
}
public IdCard getIdCard() {
returnidCard;
}
publicvoid setIdCard(IdCard idCard) {
this.idCard = idCard;
}
@Override
public String toString() {
return"User [UserId=" + userId + ", UserName=" + userName
+ ", idCard=" + idCard + "]";
}
}
// IdCard持久类
package com.gist.entity;
/**
* User表联结的IdCard表
* 一对一以主键关联
* @author Administrator
*/
publicclass IdCard {
private String cardId; //卡号ID
private String cardNumber; //卡号编码
private User user; //用户
public String getCardId() {
returncardId;
}
publicvoid setCardId(String cardId) {
this.cardId = cardId;
}
public String getCardNumber() {
returncardNumber;
}
publicvoid setCardNumber(String cardNumber) {
this.cardNumber = cardNumber;
}
public User getUser() {
returnuser;
}
publicvoid setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return"IdCard [cardId=" + cardId + ", cardNumber=" + cardNumber
+ ", user=" + user + "]";
}
}
7.1.1.2 映射文件
//user映射文件
<?xmlversion="1.0"encoding="utf-8"?>
<!DOCTYPEhibernate-mappingSYSTEM"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
<classname="com.gist.entity.User"table="user"lazy="false">
<!-- 绑定类的属性跟表的字段对应关系 -->
<!-- id为表的主键,id是用来定义主键property定义属性 -->
<idname="userId"column="user_id">
<generatorclass="uuid.hex"/>
</id>
<!-- property定义属性,column是表中列的名称,entity属性name是对应映射关系 -->
<propertyname="userName"column="user_name"></property>
<one-to-onename="idCard"class="com.gist.entity.IdCard"cascade="all"></one-to-one>
</class>
</hibernate-mapping>
//IdCard映射文件
<?xmlversion="1.0"encoding="utf-8"?>
<!DOCTYPEhibernate-mappingSYSTEM"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.gist.entity.IdCard"table="idCard"lazy="false">
<!-- 绑定类的属性跟表的字段对应关系 -->
<!-- id为表的主键,id是用来定义主键property定义属性 -->
<idname="cardId" column="card_id">
<generatorclass="foreign">
<paramname="property">user</param>
</generator>
</id>
<!-- property定义属性,column是表中列的名称,entity属性name是对应映射关系 -->
<propertyname="cardNumber"column="card_number"></property>
<one-to-onename="user"class="com.gist.entity.User"cascade="all"/>
</class>
</hibernate-mapping>
7.1.1.3 插入数据
User u = new User();
u.setUserName("小曹");
IdCard ic = new IdCard();
ic.setCardNumber("6666");
//建造关联关系
u.setIdCard(ic);
ic.setUser(u);
//添加数据
session.save(ic);
7.1.1.4 删除数据
String hql = "SELECT u FROM User u WHERE u.userName = 'kevin'";
Query query = session.createQuery(hql);
List<User> list = query.list();
for(User t : list){
session.delete(t);
}
7.1.1.5 级联查询数据
String hql = "select u from User u where u.userName = 'Kevin'";
Query query = session.createQuery(hql);
List<User> list = query.list();
for(User u : list){
IdCard card = u.getIdCard();
System.out.println("卡号:"+card.getCardNumber());
}
7.1.1.6 跨对象查询数据
String hql = "select i from IdCard i where i.user.userName = 'Kevin'";
Query query = session.createQuery(hql);
List<IdCard> list = query.list();
for(IdCard card : list){
System.out.println("卡号:"+card.getCardNumber());
}
7.1.2外键关联---一对一
需求:
有两张表,如右图。
要求:对数据库进
行操作,一个学生
一定有一张证书,
而一张证书一定属于一个学生。
7.1.2.1 POJO
//Teacher持久类
package com.gist.entity;
/**
* FkCard表联结的FkTeacher教师表
* 一对一以外键关联
* @author Administrator
*
*/
publicclass FkTeacher {
private String FkTeacherId; //教师id
private String FkTeacherName;//教师姓名
privateintFkTeacherAge;//教师年龄
private FkCard FkTeacherCard;//外键所属
public String getFkTeacherId() {
returnFkTeacherId;
}
publicvoid setFkTeacherId(String fkTeacherId) {
FkTeacherId = fkTeacherId;
}
public String getFkTeacherName() {
returnFkTeacherName;
}
publicvoid setFkTeacherName(String fkTeacherName) {
FkTeacherName = fkTeacherName;
}
publicint getFkTeacherAge() {
returnFkTeacherAge;
}
publicvoid setFkTeacherAge(int fkTeacherAge) {
FkTeacherAge = fkTeacherAge;
}
public FkCard getFkTeacherCard() {
returnFkTeacherCard;
}
publicvoid setFkTeacherCard(FkCard fkTeacherCard) {
FkTeacherCard = fkTeacherCard;
}
}
//Card持久类
package com.gist.entity;
/**
* FkTeacher表联结的FkCard卡号表
* 一对一以外键关联
* @author Administrator
*
*/
publicclass FkCard {
private String FkCardId;//卡号id
private String FkCardNumber;//卡号编码
private FkTeacher FkCardOwner;//所属
public String getFkCardId() {
returnFkCardId;
}
publicvoid setFkCardId(String fkCardId) {
FkCardId = fkCardId;
}
public String getFkCardNumber() {
returnFkCardNumber;
}
publicvoid setFkCardNumber(String fkCardNumber) {
FkCardNumber = fkCardNumber;
}
public FkTeacher getFkCardOwner() {
returnFkCardOwner;
}
publicvoid setFkCardOwner(FkTeacher fkCardOwner) {
FkCardOwner = fkCardOwner;
}
}
7.1.2.2 映射文件
//Teacher映射文件
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEhibernate-mappingSYSTEM"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.gist.entity.FkTeacher"table="worker_fkTeacher"lazy="false">
<idname="FkTeacherId"column="fkTeacher_id">
<generatorclass="uuid.hex"/>
</id>
<propertyname="FkTeacherName"column="fkTeacher_name"/>
<propertyname="FkTeacherAge"column="fkTeacher_age"/>
<one-to-onename="FkTeacherCard"class="com.gist.entity.FkCard"property-ref="FkCardOwner"cascade="all"></one-to-one>
</class>
</hibernate-mapping>
//Card映射文件
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEhibernate-mappingSYSTEM"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.gist.entity.FkCard"table="worker_fkCard"lazy="false">
<idname="FkCardId"column="fkCard_id">
<generatorclass="uuid.hex"/>
</id>
<propertyname="FkCardNumber"column="fkCard_number"/>
<many-to-oneunique="true"column="fkTeacher_id"name="FkCardOwner"
class="com.gist.entity.FkTeacher"cascade="all">
</many-to-one>
</class>
</hibernate-mapping>
7.1.2.3 插入数据
FkTeacher fkt = new FkTeacher();
fkt.setFkTeacherName("小郑");
fkt.setFkTeacherAge(18);
FkCard fkc = new FkCard();
fkc.setFkCardNumber("960314");
//建造关联关系
fkt.setFkTeacherCard(fkc);
fkc.setFkCardOwner(fkt);
session.save(fkc);
7.1.2.4 删除数据
//方式一
String hql = "SELECT t FROM FkTeacher t WHERE t.FkTeacherName = 'kevin'";
Query query = session.createQuery(hql);
List<FkTeacher>list = query.list();
for(FkTeacher t : list){
session.delete(t);
}
//方式二
Card card = ( Card )session.load( Card.class, "402882481eecaaa8011eecaaa9ab0001" );
session.delete( card );
7.1.2.5 级联查询数据
String hql = "SELECT t FROM FkTeacher t WHERE t.FkTeacherName = 'kevin'";
Query query = session.createQuery(hql);
List<FkCard> list = query.list();
for(FkCard t : list){
FkTeacher fkt = t.getFkCardOwner();
System.out.println("教师:"+fkt.getFkTeacherName());
}
7.1.2.6 跨对象查询数据
Stringhql = "SELECT c FROM FkCard c WHERE c.FkCardOwner.FkTeacherAge>16";
Query query = session.createQuery(hql);
List<FkCard> list = query.list();
for(FkCard fkc : list){
System.out.println("卡号:"+fkc.getFkCardNumber());
}
7.2一对多,多对一(关联表)
7.2.1 POJO
//Member持久类
package com.gist.entity;
/**
* 会员
* 多对一membet对Team
* @author Administrator
*
*/
publicclass Member {
private String memberId;//会员id
private String memberName;//会员名字
privateintmemberAge;//会员年龄
private Team memberTeam;//所属
public String getMemberId() {
returnmemberId;
}
publicvoid setMemberId(String memberId) {
this.memberId = memberId;
}
public String getMemberName() {
returnmemberName;
}
publicvoid setMemberName(String memberName) {
this.memberName = memberName;
}
publicint getMemberAge() {
returnmemberAge;
}
publicvoid setMemberAge(int memberAge) {
this.memberAge = memberAge;
}
public Team getMemberTeam() {
returnmemberTeam;
}
publicvoid setMemberTeam(Team memberTeam) {
this.memberTeam = memberTeam;
}
}
//Team持久类
package com.gist.entity;
import java.util.HashSet;
import java.util.Set;
/**
* 组
* 一对多Team对member
* @author Administrator
*
*/
public class Team {
private String teamId;//组id
private String teamName;//组名称
private int teamAge;//组年龄
//组里面有很多会员,将会员名单保存到memberList中
private Set<Member> memberList = new HashSet<Member>();//将member保存到hashSet中
public String getTeamId() {
return teamId;
}
public void setTeamId(String teamId) {
this.teamId = teamId;
}
public String getTeamName() {
return teamName;
}
public void setTeamName(String teamName) {
this.teamName = teamName;
}
public int getTeamAge() {
return teamAge;
}
public void setTeamAge(int teamAge) {
this.teamAge = teamAge;
}
public Set<Member> getMemberList() {
return memberList;
}
public void setMemberList(Set<Member> memberList) {
this.memberList = memberList;
}
}
7.2.2映射文件
//Team映射文件
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEhibernate-mappingSYSTEM"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.gist.many2one.entity.Team"table="team_list"lazy="false">
<idname="teamId"column="team_id">
<generatorclass="uuid.hex"/>
</id>
<propertyname="teamName"column="team_name"/>
<propertyname="teamAge"column="team_age"/>
<setname="memberList"inverse="false"cascade="all">
<keycolumn="member_team"></key>
<one-to-manyclass="com.gist.many2one.entity.Member" />
</set>
</class>
</hibernate-mapping>
//Menber映射文件
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEhibernate-mappingSYSTEM"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.gist.many2one.entity.Member"table="member_list"lazy="false">
<idname="memberId"column="member_id">
<generatorclass="uuid.hex"/>
</id>
<propertyname="memberName"column="member_name"/>
<propertyname="memberAge"column="member_age"/>
<many-to-onename="memberTeam"column="member_team"
class="com.gist.many2one.entity.Team"cascade="all"></many-to-one>
</class>
</hibernate-mapping>
7.2.3 插入数据
Team team = new Team();
team.setTeamName("腾讯QQ");
team.setTeamAge(2);
Member member = new Member();
member.setMemberName("小马");
member.setMemberAge(18);
member.setMemberTeam(team);
7.2.4 分配关联关系
Team team = (Team)session.load(Team.class, "8e93db245c3fdedf015c3fdee0160000");
Member member = (Member)session.load(Member.class, "8e93db245c3fdedf015c3fdee10c0001");
// 分配关联关系,事务提交,外键的值自动update
team.getMemberList().add(member);
member.setMemberTeam(team);
transaction.commit();
7.2.5 取消关联关系
Team team = (Team) session.load(Team.class, "8e93db245c3fdedf015c3fdee0160000");
Set < Member > memberList = team.getMemberList();
for ( Member member: memberList ) {
if ( true == "kevin".equals( member.getMemberName() ) ) {
// 取消关联关系,事务提交,外键的值自动update为null
memberList.remove( member );
break;
}
}
transaction.commit();
7.2.6 删除数据(同时自动删除关联对象)
//删除数据(同时自动删除关联对象)
Class<Team> str01 = Team.class;
String str1 = "8e93db245c3fdedf015c3fdee0160000";
Team team = (Team) session.load(str01, str1);
session.delete(team);
transaction.commit();
7.2.7 删除数据(只删除主对象)
Team team = new Team();
team.setTeamId("8e93db245c3fdedf015c3fdee0160000");
session.delete(team);
transaction.commit();
7.3多对多
7.3.1 POJO
// Client客户
package com.gist.many2many.entity;
import java.util.HashSet;
import java.util.Set;
/**
* Client客户
* 多对多,Client对product
* @author Administrator
*
*/
public class Client {
private String clientId;//客户id
private String clientName;//客户名称
//客户有多个产品,将产品保存到productList中
private Set<Product> productList = new HashSet<Product>();
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
public String getClientName() {
return clientName;
}
public void setClientName(String clientName) {
this.clientName = clientName;
}
public Set<Product> getProductList() {
return productList;
}
public void setProductList(Set<Product> productList) {
this.productList = productList;
}
}
// product产品
package com.gist.many2many.entity;
import java.util.HashSet;
import java.util.Set;
/**
* product产品
* 多对多,product对client
* @author Administrator
*
*/
public class Product {
private String productId;//产品id
private String productName;//产品名称
//不同的产品有不同的客户
private Set<Client> clientList = new HashSet<Client>();
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public Set<Client> getClientList() {
return clientList;
}
public void setClientList(Set<Client> clientList) {
this.clientList = clientList;
}
}
7.3.2 映射文件
//Client.hbm.xml
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEhibernate-mappingSYSTEM"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.gist.many2many.entity.Client"table="client_list">
<idname="clientId"column="client_id">
<generatorclass="uuid.hex"></generator>
</id>
<propertyname="clientName"column="client_name"/>
<setname="productList"table="client_product">
<keycolumn="client_id"/>
<many-to-manyclass="com.gist.many2many.entity.Product"column="product_id"/>
</set>
</class>
</hibernate-mapping>
//Product.hbm.xml
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEhibernate-mappingSYSTEM"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.gist.many2many.entity.Product"table="product_list">
<idname="productId"column="product_id">
<generatorclass="uuid.hex"></generator>
</id>
<propertyname="productName"column="product_name"/>
<setname="clientList"table="client_product"inverse="true">
<keycolumn="product_id"/>
<many-to-manyclass="com.gist.many2many.entity.Client"column="client_id"/>
</set>
</class>
</hibernate-mapping>
7.3.3 插入数据
Client client = new Client();
client.setClientName("小郭");
Product product = new Product();
product.setProductName("郭冰箱");
//插入数据
hibernateutil.save(client);
hibernateutil.save(product);
7.3.4 分配关联关系
//分配关联关系,分配的关系为单向
Class str01 = Client.class;
String str1 = "402880f25c458a86015c458a87d10000";
Class str02 = Product.class;
String str2 = "402880f25c458a86015c458a89180001";
Client client = (Client) session.get(str01,str1);
Product product = (Product) session.get(str02, str2);
//关联关系不要互给,单向就行
client.getProductList().add(product);
transaction.commit();
7.3.5 取消关联关系
Classstr01 = Client.class;
String str1 = "402880f25c447a42015c447a431b0000";
Classstr02 = Product.class;
String str2 = "402880f25c447a42015c447a43dc0001";
Client client = (Client) session.get(str01,str1);
Product product = (Product) session.get(str02, str2);
Set<Product> productList = client.getProductList();
for(Product p:productList){
if(product.getProductName().equals(p.getProductName())){
//取消单向的关联关系即可,不用双向
productList.remove(p);
break;
}
transaction.commit();
}
7.3.6 删除数据(级联删除)
Client client = (Client) session.get(Client.class,"402880f25c447a42015c447a431b0000");
session.delete(client);
transaction.commit();
7.3.7 删除数据(两层删除)
Client client = (Client) session.get(Client.class,"402880f25c447a42015c447a431b0000");
Set<Product> productList = client.getProductList();
for(Product p:productList){
p.getClientList().clear();
session.delete(p);
}
session.delete(client);
transaction.commit();
7.3.8 删除数据(单一删除)
//注意:只有Client被删除了,Product并没被删除
Client client = (Client) session.get(Client.class,"402880f25c447a42015c447a431b0000");
client.getProductList().clear();
transaction.commit();
8.1inverse-关联的高级属性
inverse是hibernate双向关系中的基本概念。inverse的真正作用就是指定由哪一方来维护之间的关联关系。当一方中指定了“inverse=false”(默认),那么那一方就有责任负责之间的关联关系,说白了就是hibernate如何生成Sql来维护关联的记录!
Hibernate仅仅按照主控方对象的状态的变化来同步更新数据库。按照原来的映射文件,people.getAddresses().add(address),即主控方对象的状态发生了改变,因此数据库会跟着对象状态的变化来同步更新数据库;而address.setPeople(people),即被控方对象的状态发生了改变,它是不能触发对象和数据库的同步更新的。
当inverse=false时,hibernate将对set的改动反映到数据库中
8.2cascade-关联的高级属性
- cascade属性的可选值:
- all : 所有情况下均进行关联操作。
- none:所有情况下均不进行关联操作。这是默认值。
- save-update:在执行save/update/saveOrUpdate时进行关联操作。
- delete:在执行delete时进行关联操作。
8.3 unique-关联的高级属性
many-to-one元素增加unique=“true”属性,用于表示N的一端也必须是唯一的,在N的一端增加了唯一的约束,即成为一对一。
8.4 延迟加载
- 不会将查询到的数据所关联的数据(包含n层关联表的数据)一起加载到对象中。
- 配置样例:
- <class name="Student“
table="student_extends"lazy=“true">
//案例:
<?xml version="1.0" encoding="GB2312"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
<hibernate-mapping>
<class name="third.pojos.Product" table="product_list">
<id name="productId" column="product_id">
<generator class="uuid.hex"/>
</id>
<property name="productName" column="product_name"/>
<set name="clientList" table="client_product" cascade="all" lazy="false">
<key column="product_client_id"/>
<many-to-many class="third.pojos.Client" column="client_product_id"/>
</set>
</class>
</hibernate-mapping>
- 控制通过Product的set获取其关联对象的情况
分页策略
批处理解决方案 – Cache缓存控制
Clob与Blob数据处理方案
9.1 分页策略
Query query = session.createQuery("select p from Product p order by p.productId");
//从第几条记录开始取数据
query.setFirstResult(4);
//当前最多取几条
query.setMaxResults(2);
List<Product> list = query.list();
for (Product c : list) {
System.out.println(c.getProductId());
}
transaction.commit();
9.2 批处理解决方案 – Cache缓存控制
- Hibernate的两级缓存
- 一级缓存:Session
- 二级缓存:SessionFactory
- 一级缓存策略
- 控制一级缓存的大小,适当的时候将数据从一级缓存送往二级,然后送到数据库。
- 及时清空缓存
案例:
//看看这个恐怖的操作(挤爆缓存):
Configuration config = new Configuration().configure("cache/conf/hibernate.cfg.xml");
SessionFactory sf = config.buildSessionFactory();
Session session = sf.openSession();
Transaction t = session.beginTransaction();
// 一般大约插入30万条就会挤爆缓存
for (int i = 0; i <1000000; i++) {
CacheTable ct = new CacheTable();
ct.setId(i);
session.save(ct);
System.out.println(i);
}
t.commit();
session.close();
- 恐怖操作的结果:
程序抛出OutOfMemoryException的异常。
- 看看如何解决:
- 确定缓存大小(一般为20-30):
Configuration configuration = new Configuration();
configuration.configure("hibernate.cfg.xml");
SessionFactory buildSessionFactory = configuration.buildSessionFactory();
Session session = buildSessionFactory.openSession();
Transaction transaction = session.beginTransaction();
try{
for(int i=0;i<100;i++){
CacheTable ct = new CacheTable();
ct.setId(i);
ct.setAge("18");
ct.setName("kevin"+i);
session.save(ct);
System.out.println(i);
if ( 0 == ( i % 20 ) ) {
session.flush();// 将一级缓存中的数据送往二级缓存
session.clear();// 清空一级缓存
}
}
transaction.commit();
}catch(Exception e){
transaction.rollback();
}finally{
session.close();
buildSessionFactory.close();
}
9.3 Clob与Blob数据处理方案
9.3.1 Blob-pojo
package com.gist.blob.entity;
import java.sql.Blob;
publicclass User {
private String id;
private String name;
private Blob blob;
public String getId() {
returnid;
}
publicvoid setId(String id) {
this.id = id;
}
public String getName() {
returnname;
}
publicvoid setName(String name) {
this.name = name;
}
public Blob getBlob() {
returnblob;
}
publicvoid setBlob(Blob blob) {
this.blob = blob;
}
}
9.3.2Blob-配置文件(User.hbm.xml)
<?xmlversion="1.0"encoding="utf-8"?>
<!DOCTYPEhibernate-mappingSYSTEM"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.gist.blob.entity.User"table="userblob">
<!-- 绑定类的属性跟表的字段对应关系 -->
<!-- id为表的主键,id是用来定义主键property定义属性 -->
<idname="id"column="id">
<generatorclass="uuid.hex"/>
</id>
<!-- property定义属性,column是表中列的名称,entity属性name是对应映射关系 -->
<propertyname="name"column="name"></property>
<propertyname="blob"column="blob"type="blob"></property>
</class>
</hibernate-mapping>
9.3.3 Blob-测试类
package com.gist.blob.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
import com.gist.blob.entity.User;
import com.gist.util.constants;
import com.gist.util.hibernateutil;
public class UesrTest extends hibernateutil{
@Test
public void saveObject() throws IOException {
//1.加载配置文件
Configuration configuration = new Configuration();
//输入总配置文件路径,相对路径,加载配置文件的数据还没建表
configuration.configure(constants.STUDENT_HIBERNATE_CFG);
//2.通过configuration获取会话工厂
SessionFactory buildSessionFactory = configuration.buildSessionFactory();
//3.创建会话,此刻开始创建数据数据库表
Session session = buildSessionFactory.openSession();
//4.开启事务
Transaction transaction = session.beginTransaction();
//5.操作数据库
try{
User user = new User();
user.setName("图片");
File file = new File("C:\\Users\\Administrator\\Desktop\\1.png");
FileInputStream fis = new FileInputStream(file);
//Hibernate.getLobCreator(session.get(arg0, arg1));
session.save(user);
//提交事务*
transaction.commit();
}catch(Exception e){
//回滚事务
transaction.rollback();
}finally{
session.close();
buildSessionFactory.close();
}
}
}
9.3.4 Clob-pojo
package com.gist.clob.entity;
import java.sql.Clob;
publicclass ClobBean {
private String id;
private String name;
private Clob clob;
public Clob getClob() {
returnclob;
}
publicvoid setClob(Clob clob) {
this.clob = clob;
}
public String getId() {
returnid;
}
publicvoid setId(String id) {
this.id = id;
}
public String getName() {
returnname;
}
publicvoid setName(String name) {
this.name = name;
}
}
9.3.5Clob-配置文件(ClobBean.hbm.xml)
<?xmlversion="1.0"encoding="utf-8"?>
<!DOCTYPEhibernate-mappingSYSTEM"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<classname="com.gist.clob.entity.ClobBean" table="clobBean">
<!-- 绑定类的属性跟表的字段对应关系 -->
<!-- id为表的主键,id是用来定义主键property定义属性 -->
<idname="id"column="id">
<generatorclass="uuid.hex"/>
</id>
<!-- property定义属性,column是表中列的名称,entity属性name是对应映射关系 -->
<propertyname="name"column="name"></property>
<propertyname="clob"column="clob"type="clob"></property>
</class>
</hibernate-mapping>
9.3.6 Clob-测试类
@Test
publicvoid saveObject() throws IOException {
//1.加载配置文件
Configuration configuration = new Configuration();
//输入总配置文件路径,相对路径,加载配置文件的数据还没建表
configuration.configure(constants.STUDENT_HIBERNATE_CFG);
//2.通过configuration获取会话工厂
SessionFactory buildSessionFactory = configuration.buildSessionFactory();
//3.创建会话,此刻开始创建数据数据库表
Session session = buildSessionFactory.openSession();
//4.开启事务
Transaction transaction = session.beginTransaction();
//5.操作数据库
try{
ClobBean clobBean = new ClobBean();
clobBean.setName("图片");
File file = new File("C:\\Users\\Administrator\\Desktop\\1.jpg");
FileInputStream fis = new FileInputStream(file);
//Hibernate.getLobCreator(session.get(arg0, arg1));
session.save(clobBean);
//提交事务*
transaction.commit();
}catch(Exception e){
//回滚事务
transaction.rollback();
}finally{
session.close();
buildSessionFactory.close();
}
}