Hibernate (ORM)

框架体系布局

 MyBatis 1

hibernate入门

2.1 ORM框架

 MyBatis 2

 

Hibernate是一个数码持久化层的ORM框架.

Object:对象,java对象,此处特指JavaBean

Relational:关系,二维表,数据库中之阐明。

辉映|映射元数据:对象吃性能,与发明的字段,存在对应关系。

 

 MyBatis 3

 

2.2 什么是hibernate

 MyBatis 4

 

l Hibernate是轻量级JavaEE应用之持久层解决方案,是一个关系数据库ORM框架

  • ORM
    就是经过以Java对象映射到数库表,通过操作Java对象,就得得对数据表的操作

l Hibernate提供了针对性涉项目数据库增删改化操作

 

2.3 主流的ORM框架

n JPA Java Persistence API.JPA通过JDK
5.0诠释或XML描述对象-关系表底投射关系(只有接口规范)

n Hibernate 最流行ORM框架,通过对象-关系映射配置,可以了脱离底层SQL

n MyBatis  本是apache的一个开源项目 iBatis,支持一般 SQL查询,存储过程及高级映射的可观持久层框架

n Apache DBUtils 、Spring JDBCTemplate

 

2.4 优点

l Hibernate对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码

l Hibernate是一个基于jdbc的主流持久化框架,是一个优秀的orm实现,它很大程度的简化了dao层编码工作  session.save(User);

l Hibernate使用java的反射机制

l Hibernate的性能非常好,因为它是一个轻量级框架。映射的灵活性很出色。它支持很多关系型数据库,从一对一到多对多的各种复杂关系

 

 

 

 

入门案例【掌握】

3.1 编写流程

l 1. 导入jar包

l 2. 创办数据库暨发明

l 3. 编核心配置文件(hibernate.cfg.xml)–> 配置获得链接等参数

l 4. 编纂映射文件 hibernate
mapping(*.hbm.xml)

l 5 使用api测试

 

3.2 数据库和阐明

create database h_day01_db;

use h_day01_db;

create table t_user(

  id int auto_increment primary key,

  username varchar(50),

  password varchar(30)

);

 

 

3.3 导入jar包

l 版本:3.6.10   –> hibernate 4 建议注解开发,hibernate 4 对 3 不般配。

l 目录结构

 MyBatis 5

 

l jar介绍

核心:MyBatis 6

 

必须:\lib\required

jpa规范:lib\jpa

mysql驱动:MyBatis 7

 

 

 

 

3.4 编辑JavaBean + 映射文件

l 文件位置:javabean同包

l 文件名称:javabean同名

l 扩展名:*.hbm.xml

l 内容:MyBatis 8

 

累加律MyBatis 9

MyBatis 10

 

 

 

 

 

public class User {

 

/*

 * create table t_user(

  id int auto_increment primary key,

  username varchar(50),

  password varchar(30)

);

 */

private Integer uid;

private String username;

private String password;

 

<!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="com.itheima.a_hello.User" table="t_user">

<!– 主键 –>

<id name="uid">

<!– 固定值:主键生成策略 –>

<generator class="native"></generator>

</id>

 

<!– 普通属性 –>

<property name="username"></property>

<property name="password"></property>

 

</class>

</hibernate-mapping>

 

 

 

3.5 编制核心配置文件

l 位置:类路径(classpath、src)–>WEB-INF/classes

l 名称:hibernate.cfg.xml

l 内容:

添加约

 

<!DOCTYPE hibernate-configuration PUBLIC

"-//Hibernate/Hibernate Configuration DTD 3.0//EN"

"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<!– SessionFactory,相当于之前学习连接池配置 –>

<session-factory>

<!– 1 基本4项 –>

<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>

<property name="hibernate.connection.url">jdbc:mysql:///h_day01_db</property>

<property name="hibernate.connection.username">root</property>

<property name="hibernate.connection.password">1234</property>

 

<!– 添加映射文件 –>

<mapping resource="com/itheima/a_hello/User.hbm.xml"/>

</session-factory>

 

</hibernate-configuration>

 

 

3.6 测试

@Test

public void demo01(){

User user = new User();

user.setUsername("伟哥哥");

user.setPassword("1234");

 

 

//1 加载配置文件获得核心配置对象

Configuration config = new Configuration().configure();

//2 获得工厂 SessionFactory,相当于连接池

SessionFactory factory = config.buildSessionFactory();

//3获得会话session,相当于链接Connection

Session session = factory.openSession();

//4 开启事务

Transaction transaction = session.beginTransaction();

 

//操作

session.save(user);

 

//5 提交事务 | 回滚事务

transaction.commit();

//6 释放资源–关闭session

session.close();

//7 释放资源–关闭工厂factory

factory.close();

}

 

3.7 泛异常

 

缓解方案:

以照文件上加至核心配置文件被  hbm.xml  –>
hibernate.cfg.xml

 MyBatis 11

 

api详解【多练】

4.1 网布局

 MyBatis 12

 

PO:persistent object ,用于与数据库交互数据。–dao层  (JavaBean + hbm )

BO:Business object 业务数据对象。–service层

VO:Value Object 值对象。–web层

出被:直接下JavaBean 描述三独对象。

 MyBatis 13

 

 

4.2 Configuration 配置对象

l hibernate 核心配置文件种类

hibernate.cfg.xml 通常以xml配置文件,可以配备内容还丰富。

hibernate.properties 用于配置key/value 形式之情节,key不可知再次的。配置出众多的局限性。一般不用。

参考文件:hibernate-distribution-3.6.10.Final\project\etc\ hibernate.properties

供了主导配置文件常用的配置起,及挑选参数。

1.供组织  new Configuration()
hibernate将机关加载 hibernate.properties文件

hibernate.properties文件要存放于看似路径(src)下

2.提供方式 configure() 将加载src下的hibernate.cfg.xml

 MyBatis 14

 

3.扩展api

configure(String) 加载指定目录下的 xml文件

4.手动加载配置文件

// 手动加载指定的布置文件

config.addResource(“com/itheima/a_hello/User.hbm.xml”);

 

// 手动加载指定类,对应之投文件 User–> User.hbm.xml

config.addClass(User.class);

 MyBatis 15

 

 

l 常见很:

 MyBatis 16

 

开发中:将hbm.xml映射 配置 hibernate.cfg.xml

读着:可以利用 addClass  或 addResource

 

4.3 SessionFactory工厂

l SessionFactory 相当于java
web连接池,用于管理有session

l 获得艺术:config.buildSessionFactory();

l sessionFactory hibernate缓存配置信息
(数据库配置信息、映射文件,预定义HQL语句 等)

l SessionFactory线程安全,可以是成员变量,多单线程同时做客时,不见面面世线程并发访问问题。

l 提供api:

//打开一个新的对话 session

factory.openSession();

//获得当前线程中绑定的会话session

factory.getCurrentSession();

hibernate支持,将开创的session绑定到当地线程中,底层以ThreadLocal,在次中共享session。

1.必须在hibernate.cfg.xml 配置

<!– 2 与本地线程绑定 –>

<property name="hibernate.current_session_context_class">thread</property>

 

2.要提交或回滚事务,底层以自动关闭session

 

 

 

 

4.4 Session 会话

l Session 相当于 JDBC的 Connection — 会话

 

l 通过session操作PO对象 –增删改查

l session单线程,线程不安全,不可知编成成员变量。

l session api

save 保存

update 更新

delete 删除

get 通过id查询,如果无 null

load 通过id查询,如果没扔大

createQuery(“hql”)  获得Query对象

createCriteria(Class) 获得Criteria对象

 

 

 

4.5 Transaction 事务

打开事务 beginTransaction()

落工作 getTransaction()

 

交给业务:commit()

回滚事务:rollback()

 

try{

   //开启

   //session操作

   //提交

} catch(e){

   //回滚

}

扩展:不需要手动的管理事务,之后所有的事务管理都交予spring。

 

4.6 Query对象

l hibernate执行hql语句

l hql语句:hibernate提供面向对象查询语句,使用对象(类)和性质进行查询。区分轻重缓急写。

l 获得 session.createQuery(“hql”)

l 方法:

list()  查询有

uniqueResult() 获得一个结实。如果无询问及回null,如果查询多长达扔大。

 

setFirstResult(int) 分页,开始索引数startIndex

setMaxResults(int) 分页,每页显示个数 pageSize

 

4.7 Criteria对象(了解)

l QBC(query by criteria),hibernate提供纯面向对象查询语言,提供第一手行使PO对象进行操作。

l 获得方式:Criteria criteria = session.createCriteria(User.class);

l 条件

criteria.add(Restrictions.eq(“username”, “tom”));

// Restrictions.gt(propertyName, value) 大于

// Restrictions.ge(propertyName, value) 大于等于

// Restrictions.lt(propertyName, value) 小于

// Restrictions.le(propertyName, value) 小于等于

// Restrictions.like(propertyName, value) 模糊查询,注意:模糊查询值需要使用 % _

 

4.8 工具类

public class H3Utils {

 

// 会话工厂,整个程序只有一份。

private static SessionFactory factory;

 

static{

//1 加载配置

Configuration config = new Configuration().configure();

 

//2 获得工厂

factory = config.buildSessionFactory();

//3 关闭虚拟机时,释放SessionFactory

Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {

 

@Override

public void run() {

System.out.println("虚拟机关闭!释放资源");

sf.close();

}

}));

}

 

 

/**

 * 获得一个新的session

 * @return

 */

public static Session openSession(){

return factory.openSession();

}

 

/**

 * 获得当前线程中绑定session

 * * 注意:必须配置

 * @return

 */

public static Session getCurrentSession(){

return factory.getCurrentSession();

}

 

 

}

 

 

 

 

中心配置文件详解

 

5.1 详见部署【多读】

<!– SessionFactory,相当于之前学习连接池配置 –>

<session-factory>

<!– 1 基本4项 –>

<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>

<property name="hibernate.connection.url">jdbc:mysql:///h_day01_db</property>

<property name="hibernate.connection.username">root</property>

<property name="hibernate.connection.password">1234</property>

 

<!– 2 与本地线程绑定 –>

<property name="hibernate.current_session_context_class">thread</property>

 

  <!– 3 方言:为不同的数据库,不同的版本,生成sql语句(DQL查询语句)提供依据

  * mysql 字符串 varchar

  * orcale 字符串 varchar2

  –>

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

 

<!– 4 sql语句 –>

<!– 显示sql语句 –>

<property name="hibernate.show_sql">true</property>

<property name="hibernate.format_sql">true</property>

 

<!– 5 自动创建表(了解) ,学习中使用,开发不使用的。

* 开发中DBA 先创建表,之后根据表生产 PO类

* 取值:

update:【】

如果表不存在,将创建表。

如果表已经存在,通过hbm映射文件更新表(添加)。(映射文件必须是数据库对应)

表中的列可以多,不负责删除。

create :如果表存在,先删除,再创建。程序结束时,之前创建的表不删除。【】

create-drop:与create几乎一样。如果factory.close()执行,将在JVM关闭同时,将创建的表删除了。(测试)

validate:校验 hbm映射文件 和 表的列是否对应,如果对应正常执行,如果不对应抛出异常。(测试)

–>

<property name="hibernate.hbm2ddl.auto">create</property>

 

<!– 6 java web 6.0 存放一个问题

* BeanFactory 空指针异常

异常提示:org.hibernate.HibernateException: Unable to get the default Bean Validation factory

* 解决方案:取消bean校验

–>

<property name="javax.persistence.validation.mode">none</property>

 

<!– 添加映射文件

<mapping >添加映射文件

resource 设置 xml配置文件 (addResource(xml))

class 配置类 (addClass(User.class)) 配置的是全限定类名

–>

<mapping  resource="com/itheima/a_hello/User.hbm.xml"/>

</session-factory>

 

Hibernate中持久化类

6.1 编制规则

  • 供一个无论参数 public访问控制符的构造器
  • 供一个标识性,映射数据表主键字段
  • 备属性提供public访问控制符的 set  get 方法(javaBean)
  • 标识性应竭尽以基本数据列的包裹档次
  • 永不为此final修饰实体
    (将无法转移代理对象开展优化)

6.2 持久化对象的唯一标识 OID

l Java按地址区分和一个类的例外对象.

l 关系数据库用主键区分同一长条记下

l Hibernate使用OID来起内存中的靶子以及数据库中记录的呼应关系

结论: 对象的OID和数据库的阐明的主键对应。为保证OID的唯一性,应该受Hibernate来吗OID付值

6.3 区别自然主键和代理主键

l 主键需要有所: 不为空/不能够再/不克改变

当主键: 在业务被,某个属性符合主键的老三单如求.那么该属性可以当做主键列.

代理主键: 在工作被,不存符合上述3只尺码的习性,那么就算添一个无意思之列.作为主键.

6.4 基本数据与包装档次

l 基本数据类及打包档次对应hibernate的照耀类型相同

l 基本类型无法表达null、数字型的默认值为0。

l 包装类默认值是null。当于默认值有业务意义的时刻需要运用包装类。

 

6.5 项目对应

Java数据类型

Hibernate数据类型

标准SQL数据类型
(PS:对于不同的DB可能有所差异)

byte、java.lang.Byte

byte

TINYINT

short、java.lang.Short

short

SMALLINT

int、java.lang.Integer

integer

INGEGER

long、java.lang.Long

long

BIGINT

float、java.lang.Float

float

FLOAT

double、java.lang.Double

double

DOUBLE

java.math.BigDecimal

big_decimal

NUMERIC

char、java.lang.Character

character

CHAR(1)

boolean、java.lang.Boolean

boolean

BIT

java.lang.String

string

VARCHAR

boolean、java.lang.Boolean

yes_no

CHAR(1)(‘Y’或’N’)

boolean、java.lang.Boolean

true_false

CHAR(1)(‘Y’或’N’)

java.util.Date、java.sql.Date

date

DATE

java.util.Date、java.sql.Time

time

TIME

java.util.Date、java.sql.Timestamp

timestamp

TIMESTAMP

java.util.Calendar

calendar

TIMESTAMP

java.util.Calendar

calendar_date

DATE

byte[]

binary

VARBINARY、BLOB

java.lang.String

text

CLOB

java.io.Serializable

serializable

VARBINARY、BLOB

java.sql.Clob

clob

CLOB

java.sql.Blob

blob

BLOB

java.lang.Class

class

VARCHAR

java.util.Locale

locale

VARCHAR

java.util.TimeZone

timezone

VARCHAR

java.util.Currency

currency

VARCHAR

6.6 普普通通属性

<hibernate-mapping>

package 用于配置PO类所在包

例如: package="com.itheima.d_hbm"

<class> 配置 PO类 和 表 之间对应关系

name:PO类全限定类名

例如:name="com.itheima.d_hbm.Person"

如果配置 package,name的取值可以是简单类名 name="Person"

table : 数据库对应的表名

dynamic-insert="false" 是否支持动态生成insert语句

dynamic-update="false" 是否支持动态生成update语句

如果设置true,hibernate底层将判断提供数据是否为null,如果为null,insert或update语句将没有此项。

普通字段

<property>

name : PO类的属性

column : 表中的列名,默认name的值相同

type:表中列的类型。默认hibernate自己通过getter获得类型,一般情况不用设置

取值1: hibernate类型

string 字符串

integer 整形

取值2: java类型 (全限定类名)

java.lang.String 字符串

取值3:数据库类型

varchar(长度) 字符串

int 整形

<property name="birthday">

  <column name="birthday" sql-type="datetime"></column>

  </property>

  javabean 一般使用类型 java.util.Date

  jdbc规范提供3中

  java类型 mysql类型

  java.sql.Date date

  java.sql.time time

  java.sql.timestamp timestamp

  null datetime

 

  以上三个类型都是java.util.Date子类

 

length : 列的长度。默认值:255

not-null : 是否为null

unique : 是否唯一

access:设置映射使用PO类属性或字段

property : 使用PO类属性,必须提供setter、getter方法

field : 使用PO类字段,一般很少使用。

insert 生成insert语句时,是否使用当前字段。

update 生成update语句时,是否使用当前字段。

默认情况:hibernate生成insert或update语句,使用配置文件所有项

注意:配置文件如果使用关键字,列名必须使用重音符

 

 

 

6.7 主键

主键

<id>配置主键

name:属性名称

access="" 设置使用属性还是字段

column=""  表的列名

length=""  长度

type="" 类型

<generator> class属性用于设置主键生成策略

1.increment 由hibernate自己维护自动增长

底层通过先查询max值,再+1策略

不建议使用,存在线程并发问题

2.identity hibernate底层采用数据库本身自动增长列

例如:mysql auto_increment

3.sequence hibernate底层采用数据库序列

例如:oracle 提供序列

4.hilo 

 

         </generator>

5.native 根据底层数据库的能力选择 identity、sequence 或者 hilo 中的一个。【】

##以上策略使用整形,long, short 或者 int 类型

6.uuid 采用字符串唯一值【】

##以上策略 代理主键,有hibernate维护。

7.assigned 自然主键,由程序自己维护。【】

 

 

 

 

 

靶状态及一级缓存

1.1 状态介绍

l hibernate 规定三栽状态:瞬时态、持久态、脱管态

l 状态

瞬时态:transient,session没有缓存对象,数据库也从来不对准承诺记录。

OID特点:没有值

持久态:persistent,session缓存对象,数据库最终见面生记录。(事务没有交)

OID特点:有值

免除管态:detached,session没有缓存对象,数据库有记录。

OID特点:有值

 

1.2 转换

 MyBatis 17

 

1.2.1 瞬时态/临时态

l 获得:一般还只有一直创造(new)

l 瞬时态 转换 持久态

貌似操作:save方法、saveOrUpdate

l 瞬时态 转换 脱管态

诚如操作:通过setId方法设置数据

 

例如:

User user = new User(); //瞬时态

user.setUid(1); //脱管态

 

1.2.2 持久态

l 获得:

询问操作:get、loat、createQuery、createCriteria 等
获得都是持有久态【】

尽save之后持久态

行update之后持久态

l 持久态 转换 瞬时态

官规定实行delete()  –民间:删除态

l 持久态 转换 脱管态

session没有记录

session.close () 关闭

session.clear() 清除所有

session.evict(obj) 清除指定的PO对象

 

1.2.3 脱管态/游离态

l 获得:

创建、并设置OID的

通过api获得

l 脱管态 转换 瞬时态

手动去除OID,设置成默认值

l 脱管态 转换 持久态

貌似操作:update()、saveOrUpdate

 

 

 

 

@Test

public void demo01(){

User user = new User(); //瞬时态

user.setUsername("jack");

user.setPassword("1234"); //瞬时态(与oid没有关系)

 

Session session = factory.openSession();

session.beginTransaction();

 

session.save(user); //持久态

//—- 持久态就应该有持久态的行为(特性)

 

// user.setUsername("rose");  //持久态对象 被修改后,hibernate将自动生成update语句

// session.flush();

 

 

session.getTransaction().commit();

session.close();

 

System.out.println(user);  //脱管态

}

 

 

 

一级缓存

2.1 介绍

l 一级缓存:又称作session级别之苏存。当得到同样次于对话(session),hibernate在session中开创多个聚众(map),用于存放操作数据(PO对象),为次优化服务,如果后用相应的数码,hibernate优先从session缓存中落,如果来就运;如果没重新查询数据库。当session关闭时,一级缓存销毁。

 

2.2 一级缓存操作

2.2.1 说明一级缓存

@Test

public void demo02(){

//证明一级缓存

Session session = factory.openSession();

session.beginTransaction();

 

//1 查询 id = 1

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

System.out.println(user);

//2 再查询 — 不执行select语句,将从一级缓存获得

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

System.out.println(user2);

 

session.getTransaction().commit();

session.close();

}

 

2.2.2 移除

@Test

public void demo03(){

//清除缓存

Session session = factory.openSession();

session.beginTransaction();

 

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

System.out.println(user);

 

//清除

//session.clear();

session.evict(user);

 

// 一级缓存没有缓存对象,从数据库直接查询

User user2 = (User) session.get(User.class, 1);  //–select

System.out.println(user2);

 

session.getTransaction().commit();

session.close();

}

 

2.2.3 一级缓存快照【掌握】

l 快照:与一级缓存一样的寄放位置,对一级缓存数据备份。保证数据库底数与 一级缓存的数目必须同。如果一级缓存修改了,在实施commit提交时,将自行刷新一级缓存,执行update语句,将一级缓存的数据更新到数据库。

 

 MyBatis 18

 

2.2.4 refresh 刷新

l refresh 保证 一级缓存的数据 与 数据库的数据
保持一致。将实施select语句查询数据库,将一级缓存中的多寡覆盖掉。只要实施refresh都以实行select语句。

@Test

public void demo04(){

//刷新

Session session = factory.openSession();

session.beginTransaction();

 

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

System.out.println(user);

 

session.refresh(user);

 

session.getTransaction().commit();

session.close();

}

 

2.2.5 快照演示(一级缓存刷新)

@Test

public void demo05(){

//快照

Session session = factory.openSession();

session.beginTransaction();

 

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

System.out.println(user);

 

//修改持久态对象内容(一级缓存内容)–默认在commit时,将触发update语句。

user.setUsername("rose2");

 

 

session.getTransaction().commit();

session.close();

}

 

l 问题:一级缓存什么时刷新?(了解)

默认情况提交(commit())刷新。

 

 

@Test

public void demo06(){

//设置刷新时机

Session session = factory.openSession();

session.beginTransaction();

 

//1 设置

session.setFlushMode(FlushMode.MANUAL);

 

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

user.setUsername("rose4");

 

//1 查询所有 — AUTO , 查询之前先更新,保存一级缓存和数据库一样的

//List<User> allUser = session.createQuery("from User").list();

 

//2手动刷新 –MANUAL 将执行update,注意:一级缓存必须修改后的

session.flush();

 

// 如果MANUAL 在执行commit 不进行update

session.getTransaction().commit();

session.close();

}

 

2.3 PO对象操作

2.3.1 save & persist

l save方法:瞬时态 转换 持久态 ,会初始化OID

1.实行save方法,立即触发insert语句,从数据库获得主键的值(OID值)

2.执行save方法前,设置OID将忽略。

3.假如执行查询,session缓存移除了,在尽save方法,将实行insert

 

@Test

public void demo01(){

User user = new User();

user.setUid(100);

user.setUsername("jack");

user.setPassword("1234");

 

Session session = factory.openSession();

session.beginTransaction();

 

 

session.save(user);

 

 

session.getTransaction().commit();

session.close();

}

 

@Test

public void demo03(){

//代理  assigned

User user = new User();

//user.setUid(100);

user.setUsername("jack");

user.setPassword("1234");

 

Session session = factory.openSession();

session.beginTransaction();

 

 

session.save(user);

 

 

session.getTransaction().commit();

session.close();

}

 

 

l 注意:持久态对象非克修改OID的值

 MyBatis 19

 

 

@Test

public void demo04(){

 

Session session = factory.openSession();

session.beginTransaction();

 

 

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

user.setUid(101);

 

session.save(user);

 

session.getTransaction().commit();

session.close();

}

l persist方法:瞬时态 转换 持久态 ,不见面立刻初始化OID

 

只顾: persist方法不见面马上收获ID,所以实行sql语句的机会而凭借后.

 

2.3.2 update

l update:脱管态 转换 持久态

比方OID在多少存放的,将执行update语句

若OID不设有用摒弃大

@Test

public void demo01(){

//自然 assigned

User user = new User();

user.setUid(101);

user.setUsername("jack1");

user.setPassword("12345");

 

Session session = factory.openSession();

session.beginTransaction();

 

 

session.update(user);

 

 

session.getTransaction().commit();

session.close();

}

 

l 注意1:如果数量尚未改动,执行save方法,将触发update语句。

询问速度 比 更新速度快

经过<class select-before-update> 来设置更新前先行查询,如果没有改观就是无创新。

 MyBatis 20

 

 

总结:

update 之后对象 持久态

 

@Test

public void demo03(){

// merge 合并

User user = new User();

user.setUid(1);

user.setUsername("jack3");

user.setPassword("12345");

 

Session session = factory.openSession();

session.beginTransaction();

 

 

// 1 oid =1 持久态对象

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

 

// session.update(user);

session.merge(user);

 

 

session.getTransaction().commit();

session.close();

}

 

2.3.3 saveOrUpdate

l 代理主键:

判定是否生OID

假若无OID,将执行insert语句

如果有OID,将执行update语句。

@Test

public void demo02(){

// 代理 native

User user = new User();

// user.setUid(2);

user.setUsername("jack2");

user.setPassword("12345");

 

Session session = factory.openSession();

session.beginTransaction();

 

 

session.saveOrUpdate(user);

 

 

session.getTransaction().commit();

session.close();

}

 

l 自然主键:

优先实施select语句,查询是否存放

假定未有,将实行insert

假使在,将推行update

@Test

public void demo02(){

// 自然 assigned

User user = new User();

user.setUid(2);

user.setUsername("jack2333");

user.setPassword("12345333");

 

Session session = factory.openSession();

session.beginTransaction();

 

 

session.saveOrUpdate(user);

 

 

session.getTransaction().commit();

session.close();

}

 

 

l 注意1:native下,默认OID是否在,使用默认值。例如:Integer 默认null

由此<id  unsaved-value=”1″> 修改以默认值,如果安1开展insert语句。此内容提供hibernate使用的,录入到数据库后,采用电动增长。

 

 MyBatis 21

 

 

2.3.4 delete

 

总结:

PO对象状态:瞬时态、持久态、脱管态

 MyBatis 22

 

 

多表设计

l 以出被,前期进行要求分析,需求分析提供E–R图,根据ER图编写表结构。

l 表之间涉及存在3栽:一对准几近、多对大多、一对一。(回顾)

 MyBatis 23

 

一致针对大多:1表(主表)必须主键 和
多表(从表)必须外键,主表的主键 与 从表外键
形成主外键关系

大抵对准多:提供中间表(从表),提供2个字段(外键)分别对诺有数单主表。

一对一:???

 

 

 

l 面单对象描述 对象与对象 之间关系?【掌握】

一律针对几近:客户和订单

private class Customer{

//一针对性几近:一个客户 拥有 多单订单

private Set<Order> orderSet;

}

private class Order{

//多对相同:多独订单 属于 一个客户

private Customer customer;

}

多对多:Student学生 和 Course课程

private class Student{

//多针对几近:多只学生(当前)学习 【不同科目】

private Set<Course> courseSet …;

}

private class Course{

//多针对几近:多只科目 可以让 【不同学生】学习

private Set<Student> student = …;

}

一对一:公司company 和 地址address

private class Company{

private Address address;

}

private class Address{

private Company company;

}

 

论及关系映射

4.1 一对多实现【掌握】

4.1.1 实现类

public class Customer {

 

private Integer cid;

private String cname;

 

//一对多:一个客户(当前客户) 拥有 【多个订单】

// * 需要容器存放多个值,一般建议Set (不重复、无序)

// * 参考集合:List、Map、Array等

// ** 建议实例化–使用方便

private Set<Order> orderSet = new HashSet<Order>();

 

public class Order {

private Integer xid;

private String price;

 

//多对一:多个订单属于【一个客户】

private Customer customer;

 

 

4.1.2 布文件

l Customer.hbm.xml

<class name="com.itheima.b_onetomany.Customer" table="t_customer">

<id name="cid">

<generator class="native"></generator>

</id>

<property name="cname"></property>

 

<!– 一对多:一个客户(当前客户) 拥有 【多个订单】

1 确定容器  set <set>

2 name确定对象属性名

3 确定从表外键的名称

4 确定关系,及另一个对象的类型

注意:

在hibernate中可以只进行单向配置

每一个配置项都可以完整的描述彼此关系。

一般情况采用双向配置,双方都可以完成描述表与表之间关系。

 –>

<!– 一对多:一个客户(当前客户) 拥有 【多个订单】 –>

<set name="orderSet" cascade="delete-orphan">

<key column="customer_id"></key>

<one-to-many class="com.itheima.b_onetomany.Order"/>

</set>

</class>

 

l Order.hbm.xml

<class name="com.itheima.b_onetomany.Order" table="t_order">

<id name="xid">

<generator class="native"></generator>

</id>

<property name="price"></property>

 

<!– 多对一:多个订单属于【一个客户】

* name 确定属性名称

* class 确定自定义类型

* column 确定从表的外键名称

–>

<many-to-one name="customer" class="com.itheima.b_onetomany.Customer" column="customer_id"></many-to-one>

 

</class>

 

 

 MyBatis 24

 

 

4.2 一对多操作

4.2.1 保留客户

@Test

public void demo01(){

// 1 创建客户,并保存客户–成功

Session session = factory.openSession();

session.beginTransaction();

 

Customer customer = new Customer();

customer.setCname("田志成");

 

session.save(customer);

 

session.getTransaction().commit();

session.close();

}

 

4.2.2 保留订单

@Test

public void demo02(){

// 2 创建订单,保存订单–成功,外键为null

Session session = factory.openSession();

session.beginTransaction();

 

Order order = new Order();

order.setPrice("998");

 

session.save(order);

 

session.getTransaction().commit();

session.close();

}

 

4.2.3 客户关系订单,只保留客户

@Test

public void demo03(){

// 3 创建客户和订单,客户关联订单,保存客户?

Session session = factory.openSession();

session.beginTransaction();

 

//1 客户和订单

Customer customer = new Customer();

customer.setCname("成成");

 

Order order = new Order();

order.setPrice("998");

 

//2 客户关联订单

customer.getOrderSet().add(order);

 

//3 保存客户

session.save(customer);

 

session.getTransaction().commit();

session.close();

}

 

 MyBatis 25

 

 

4.2.4 双向关联,使用inverse

 MyBatis 26

 

 

@Test

public void demo04(){

// 4  创建客户和订单,客户关联订单,订单也关联客户,保存客户和订单?

// * 开发中优化程序 , n + 1 问题?

// ** 解决方案1:客户不关联订单 ,不建议

// ** 解决方案2:客户放弃对订单表外键值的维护。

// **** Customer.hbm.xml <set name="orderSet" inverse="true">

// ** inverse 将维护外键值的权利交予对象。相当于自己放弃。(反转)

Session session = factory.openSession();

session.beginTransaction();

 

//1 客户和订单

Customer customer = new Customer();

customer.setCname("成成");

 

Order order = new Order();

order.setPrice("998");

 

//2 客户关联订单

customer.getOrderSet().add(order);

//3 订单也关联客户

order.setCustomer(customer);

 

//4 保存客户

// * 1 save(order) — insert  –> 1,998 null

// * 2 订单管理客户,此时null –预留update –> 更新所有(正常设置)

// * 3 save(customer) — insert –> 1,成成

// * 4 客户关联订单  –> 预留update –> 更新订单外键 (维护外键)

// * 5 提交commit –> 执行2 和 4

session.save(order);

session.save(customer);

 

session.getTransaction().commit();

session.close();

}

 

l 于同一针对性几近开支被,一在一般都放弃对外键值的保护。及<set
inverse=”true

 

 

 

4.3 级联操作(读、理解)

4.3.1 save-update  级联保存还是更新

 MyBatis 27

 

 

@Test

public void demo032(){

// 32 创建客户和订单,客户关联订单,保存客户? –抛异常

// ** 解决方案2:级联操作–级联保存或更新

// ** Customer.hbm.xml <set cascade="save-update">

// ** 在保存客户的同时,一并保存订单

Session session = factory.openSession();

session.beginTransaction();

 

//1 客户和订单

Customer customer = new Customer(); //瞬时态

customer.setCname("成成");

 

Order order = new Order(); //瞬时态

order.setPrice("998");

 

//2 客户关联订单

customer.getOrderSet().add(order);

 

//3 保存客户

session.save(customer); //持久态

// 关联操作都是持久态的,此时 持久态Customer 引用 一个 瞬时态的Order 抛异常

 

session.getTransaction().commit();

session.close();

}

 

4.3.2 delete 级联删除

 MyBatis 28

 

@Test

public void demo05(){

// 5 查询客户,并删除(持久态)

// 默认:当删除客户,默认将订单外键设置成null。

// 级联删除:删除客户时,并将客户的订单删除。

// ** Customer.hbm.xml <set name="orderSet" cascade="delete">

Session session = factory.openSession();

session.beginTransaction();

 

Customer customer = (Customer) session.get(Customer.class, 10);

 

session.delete(customer);

 

 

session.getTransaction().commit();

session.close();

}

 

4.3.3 孤儿删除

l 一对多干,存在父子关系。1表(主表)可以成为父表,多表(从表)也得以子表。

 MyBatis 29

MyBatis 30

 

 

总结:

主表不可知去除,从表已经引用(关联)的数目

由表不可知加上,主表不设有的数额。

 MyBatis 31

 

 

@Test

public void demo06(){

// 6 查询客户,并查询订单,解除客户和订单订单的关系

// * 默认:客户和订单解除关系后,外键被设置成null,此时订单就是孤儿。客户和订单都存在。

// * 孤儿删除(孤子删除),当订单称为孤儿,一并删除。客户仍存在。

Session session = factory.openSession();

session.beginTransaction();

 

//1 查询客户

Customer customer = (Customer) session.get(Customer.class, 9);

 

//2查询订单

Order order = (Order) session.get(Order.class, 8);

 

//3 解除关系

customer.getOrderSet().remove(order);

 

session.getTransaction().commit();

session.close();

}

 

4.3.4 总结

save-update:A保存,同时保存B

delete:删除A,同时删除B,AB都不存

delete-orphan:孤儿删除,解除关系,同时用B删除,A存在的。

如用配置多项,使用逗号分隔。<set
cascade=”save-update,delete”>

 

all : save-update 和 delete 整合

all-delete-orphan : 三只组成

 

 

 

 

1.1.1 Hibernate的关系关系映射:(多对多)

1.1.1.1 差不多针对性多的布置:

手续一样开立实体和照耀:

Student:

public class Student {

private Integer sid;

private String sname;

// 学生选择多门课程.

private Set<Course> courses = new HashSet<Course>();

}

 

Course:

public class Course {

private Integer cid;

private String cname;

// 课程可以被多只学生选择:

private Set<Student> students = new HashSet<Student>();

}

 

Student.hbm.xml

<hibernate-mapping>

<class name=”cn.itcast.demo3.Student” table=”student”>

<id name=”sid” column=”sid”>

<generator class=”native”/>

</id>

<property name=”sname” column=”sname”/>

<!– 配置多针对性大多涉及关系 –>

<set name=”courses” table=”stu_cour”>

<key column=”sno”/>

<many-to-many class=”cn.itcast. demo3.Course” column=”cno”/>

</set>

</class>

</hibernate-mapping>

 

Course.hbm.xml

<hibernate-mapping>

<class name=”cn.itcast. demo3.Course” table=”course”>

<id name=”cid” column=”cid”>

<generator class=”native”/>

</id>

 

<property name=”cname” column=”cname”/>

 

<!– 配置多对几近干关系映射 –>

<set name=”students” table=”stu_cour”>

<key column=”cno”/>

<many-to-many class=”cn.itcast. demo3.Student” column=”sno”/>

</set>

</class>

</hibernate-mapping>

抓取策略(优化)

2.1 找方式

l 就寻找:立即询问,在执行查询语句时,立即询问有的多少。

l 延迟检索:延迟查询,在尽查询语句之后,在需要时于询问。(懒加载)

 

2.2 自我批评策略

l 类级别检索:当前之类的性能获取是否用延期。

l 关联级别之找:当前类 关联 另一个近似是否需要延期。

 

 

2.3 好像级别检索

l get:立即找。get方法同样履行,立即询问所有字段的多少。

l load:延迟检索。默认情况,load方法执行后,如果仅仅使用OID的价未开展询问,如果如使其他属性值将查询 。 Customer.hbm.xml  <class  lazy=”true |
false”>

lazy 默认值true,表示延迟检索,如果设置false表示即搜索。

 MyBatis 32

 

 

@Test

public void demo02() {

//类级别

Session session = factory.openSession();

session.beginTransaction();

 

//1立即

// Customer customer = (Customer) session.get(Customer.class, 1);

//2延迟

Customer customer = (Customer) session.load(Customer.class, 1);

 

 

 

//打印

System.out.println(customer.getCid());

System.out.println(customer.getCname());

 

session.getTransaction().commit();

session.close();

}

 

 

 

2.4 干级别检索

2.4.1 同一针对性大多要多针对多

2.4.1.1 介绍

l 容器<set> 提供个别独特性:fetch、lazy

fetch:确定下sql格式

lazy:关联对象是否延迟。

l fetch:join、select、subselect

join:底层以迫切左外连接

select:使用多单select语句(默认值)

subselect:使用子查询

l lazy:false、true、extra

false:立即

true:延迟(默认值)

extra:极其懒惰

 

 MyBatis 33

 

2.4.1.2 fetch=”join”

l fetch=”join” ,lazy无效。底层以迫切左外连接,使用同一长select将具备内容全方位询问。

 MyBatis 34

 

@Test

public void demo03() {

//关联级别:一对多,

// * Customer.hbm.xml  <set fetch="join">

// *** select语句使用左外连接,一次性查询所有

Session session = factory.openSession();

session.beginTransaction();

 

//1 查询客户

Customer customer = (Customer) session.get(Customer.class, 1);

System.out.println(customer.getCname());

 

//2 查询客户订单数

Set<Order> orderSet = customer.getOrderSet();

System.out.println(orderSet.size());

 

//3 查询客户订单详情

for (Order order : orderSet) {

System.out.println(order);

}

 

 

session.getTransaction().commit();

session.close();

}

 

2.4.1.3 fetch=”select”

l 当前目标 和 关联对象 使用多条select语句询问。

l lazy=”false” , 立即,先查询客户select,立即询问订单select

l lazy=”true”,延迟,先查询客户select,需要订单时,再查询订单select

l lazy=”extra”,极其懒惰(延迟),先查询客户select,
如果只需要订单数,使用聚合函数(不查询详情)

 

 

 MyBatis 35

MyBatis 36

 

 MyBatis 37

 

 

 

2.4.1.4 fetch=”subselect”

l 将使用子查询。注意:必须利用Query否则看不到效果。

l lazy= 同上

@Test

public void demo04() {

//关联级别:一对多,

// 演示3:* Customer.hbm.xml  <set fetch="subselect">

Session session = factory.openSession();

session.beginTransaction();

 

//1 查询客户

List<Customer> allCustomer = session.createQuery("from Customer").list();

Customer customer = allCustomer.get(0);

System.out.println(customer.getCname());

 

//2 查询客户订单数

Set<Order> orderSet = customer.getOrderSet();

System.out.println(orderSet.size());

 

//3 查询客户订单详情

for (Order order : orderSet) {

System.out.println(order);

}

 

 

session.getTransaction().commit();

session.close();

}

 

 MyBatis 38

 

 MyBatis 39

 

 MyBatis 40

 

 

 

2.4.2 多对一

2.4.2.1 介绍

l <many-to-one fetch=”” lazy=””>  (<one-to-one>)

l fetch取值:join、select

join:底层以迫切左外连接

select:多条select语句

l lazy取值:false、proxy、no-proxy

false:立即

proxy:采用关联对象 类级别检索的国策。

订单 关联 客户 (多对一)

订单 立即得到 客户,需要以客户Customer.hbm.xml <class
lazy=”false”>

订单 延迟拿走 客户,需要在客户Customer.hbm.xml <class
lazy=”true”>

 

no-proxy 不研究

 

 MyBatis 41

 

 

2.4.2.2 fetch=”join”

l fecth=”join” select语句以左外连接,此时lazy无效。

 

 MyBatis 42

 

 

@Test

public void demo05() {

//关联级别:多对一,

// 演示1:* Order.hbm.xml  <set fetch="join">  lazy无效

// * 注意:检查Customer.hbm.xml 和 Order.hbm.xml 没有额外的配置

Session session = factory.openSession();

session.beginTransaction();

 

//1 查询订单

Order order = (Order) session.get(Order.class, 1);

System.out.println(order.getPrice());

 

//2 查询订单客户信息

Customer customer = order.getCustomer();

System.out.println(customer.getCname());

 

 

session.getTransaction().commit();

session.close();

}

2.4.2.3 fetch=”select”

l 将利用多长select语句,lazy=”proxy”是否延迟,取决关联对象
类级别检索策略。

 

l lazy=”false”

 MyBatis 43

 

l lazy=”proxy”

 MyBatis 44

 

 

 

2.5 批量询问

l 当客户 关联查询 订单,给各级一个客户生产一个select语句询问订单。批量询问利用in语句减少查询订单语句个数。

默认:select * from t_order where customer_id =
?

批量:select * from t_order where customer_id in
(?,?,?,?)

l <set batch-size=”5″> 5表示括号中?个数。

 MyBatis 45

 

 

@Test

public void demo06() {

//批量查询

Session session = factory.openSession();

session.beginTransaction();

 

//1 查询所有客户

List<Customer> allCustomer = session.createQuery("from Customer").list();

 

//2遍历

for (Customer customer : allCustomer) {

System.out.println(customer.getCname());

System.out.println(customer.getOrderSet().size());

}

 

 

session.getTransaction().commit();

session.close();

}

2.6 找寻总结

 

检索策略

优点

缺点

优先考虑使用的场合

立即检索

对应用程序完全透明,不管对象处于持久化状态还是游离状态,应用程序都可以从一个对象导航到关联的对象

(1)select语句多

(2)可能会加载应用程序不需要访问的对象,浪费许多内存空间。

(1)类级别

(2)应用程序需要立即访问的对象

(3)使用了二级缓存

延迟检索

由应用程序决定需要加载哪些对象,可以避免执行多余的select语句,以及避免加载应用程序不需要访问的对象。因此能提高检索性能,并节省内存空间。

应用程序如果希望访问游离状态的代理类实例,必须保证她在持久化状态时已经被初始化。

(1)一对多或者多对多关联

(2)应用程序不需要立即访问或者根本不会访问的对象

 

表连接检索

(1)对应用程序完全透明,不管对象处于持久化状态还是游离状态,都可从一个对象导航到另一个对象。

(2)使用了外连接,select语句少

(1)可能会加载应用程序不需要访问的对象,浪费内存。

(2)复杂的数据库表连接也会影响检索性能。

(1)多对一或一对一关联

(2)需要立即访问的对象

(3)数据库有良好的表连接性能。

 

Customer  Get(int id)

Return Session.load(Customer.class,id);

  1. layz=false
  2. 以Service层获得当页面要达标一经为此到之性=> 在Service层中保证数量已

询问艺术总结

1.通过OID检索(查询)

get()立即、如果没数据返回null

load()延迟,如果无数抛大。

2.导航对象图检索方式:关联查询

customer.getOrderSet()

user.getPost().getDepartment().getDepName();

3.原始sql语句

SQLQuery sqlQuery = session.createSQLQuery(“sql 语句”)   —>表,表字段(列)

sqlQuery.list() 查询所有

sqlQuery.uniqueResult() 查询一个

4.HQL,hibernate query language
hibernate 查询语言【1】

Query query = session.createQuery(“hql语句”)  –> 对象,对象属性

5.QBC,query by criteria 纯面对对象查询语言【2】

 

HQL【掌握】

4.1 介绍

 MyBatis 46

 

4.2 询问所有客户

@Test

public void demo01(){

//1 查询所有

Session session = factory.openSession();

session.beginTransaction();

 

//1  使用简单类名 , 存在自动导包

// * Customer.hbm.xml <hibernate-mapping auto-import="true">

// Query query = session.createQuery("from Customer");

//2 使用全限定类名

Query query = session.createQuery("from com.itheima.a_init.Customer");

 

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

for (Customer customer : allCustomer) {

System.out.println(customer);

}

 

session.getTransaction().commit();

session.close();

}

 

4.3 选查询

@Test

public void demo02(){

//2 简单条件查询

Session session = factory.openSession();

session.beginTransaction();

 

 

//1 指定数据,cid OID名称

// Query query = session.createQuery("from Customer where cid = 1");

//2 如果使用id,也可以(了解)

// Query query = session.createQuery("from Customer where id = 1");

//3 对象别名 ,格式: 类 [as] 别名

// Query query = session.createQuery("from Customer as c where c.cid = 1");

//4 查询所有项,mysql–> select * from…

Query query = session.createQuery("select c from Customer as c where c.cid = 1");

 

Customer customer = (Customer) query.uniqueResult();

System.out.println(customer);

 

session.getTransaction().commit();

session.close();

}

4.4 阴影查询(部分)

@Test

public void demo04(){

//4 投影

Session session = factory.openSession();

session.beginTransaction();

 

//1 默认

//如果单列 ,select c.cname from,需要List<Object>

//如果多列,select c.cid,c.cname from ,需要List<Object[]>  ,list存放每行,Object[]多列

// Query query = session.createQuery("select c.cid,c.cname from Customer c");

//2 将查询部分数据,设置Customer对象中

// * 格式:new Customer(c.cid,c.cname)

// * 注意:Customer必须提供相应的构造方法。

// * 如果投影使用oid,结果脱管态对象。

Query query = session.createQuery("select new Customer(c.cid,c.cname) from Customer c");

 

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

for (Customer customer : allCustomer) {

System.out.println(customer.getCid() + " : " + customer.getOrderSet().size());

}

 

session.getTransaction().commit();

session.close();

}

 

4.5 排序

@Test

public void demo03(){

//3排序 ,mysql–> select… order by 字段  [asc]|desc ,….

Session session = factory.openSession();

session.beginTransaction();

 

Query query = session.createQuery("from Customer order by cid desc");

 

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

for (Customer customer : allCustomer) {

System.out.println(customer.getCid());

}

 

session.getTransaction().commit();

session.close();

}

 

 

4.6 分页

@Test

public void demo05(){

//分页

Session session = factory.openSession();

session.beginTransaction();

 

Query query = session.createQuery("from Customer");

// * 开始索引 , startIndex 算法: startIndex = (pageNum – 1) * pageSize;

// *** pageNum 当前页(之前的 pageCode)

query.setFirstResult(0);

// * 每页显示个数 , pageSize

query.setMaxResults(2);

 

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

for (Customer customer : allCustomer) {

System.out.println(customer.getCid());

}

 

session.getTransaction().commit();

session.close();

}

 

4.7 绑定参数

@Test

public void demo06(){

/* 6 绑定参数

 * 方式1:占位符,使用? 在hql语句替换具体参数

 * 设置参数 query.setXxx(int , object)

 * 参数1:?位置,从0开始。

 * 参数2:实际参数

 * 例如:String –> query.setString(int,String)

 * 方式2:别名 , 格式 “属性= :别名 ”

 * 设置参数 query.setXxx(String,object)

 * 参数1:别名

 * 参数2:实际参数

 * 例如:Integer –> query.setInteger(String,Integer)

 * 提供公共设置方法

 * setParameter(int|string , Object)

 */

Session session = factory.openSession();

session.beginTransaction();

 

Integer cid = 1;

 

//方式1

// Query query = session.createQuery("from Customer where cid = ?");

// query.setInteger(0, cid);

//方式2

Query query = session.createQuery("from Customer where cid = :xxx");

// query.setInteger("xxx", cid);

query.setParameter("xxx", cid);

 

Customer customer = (Customer) query.uniqueResult();

System.out.println(customer);

 

session.getTransaction().commit();

session.close();

}

 

4.8 聚合函数和分组

@Test

public void demo07(){

/* 7  聚合函数

 */

Session session = factory.openSession();

session.beginTransaction();

 

//1

// Query query = session.createQuery("select count(*) from Customer");

//2 别名

// Query query = session.createQuery("select count(c) from Customer c");

//3 oid

Query query = session.createQuery("select count(cid) from Customer");

 

Long numLong = (Long) query.uniqueResult();

int num = numLong.intValue();

 

System.out.println(num);

 

 

session.getTransaction().commit();

session.close();

}

 

4.9 连日查询

 MyBatis 47

 

1.接力连接 ,等效 sql 笛卡尔积

2.隐式内接连,等效 sql 隐式内连接

3.内连接,等效sql内连接

4.迫切内连接,hibernate底层使用 内连接。

5.左客接连,等效sql左外接连

6.迫切左外连接,hibernate底层使用 左外连接

7.右客接连,等效sql右外接连

 

外连接和迫切内连续?

左外连接和亟待解决左外连接?

@Test

public void demo08(){

/* 8 链接查询 : 左外连接和迫切左外连接?

 * * 左外连接 , left outer join

 * 底层使用sql的左外连接,hibernate进行数据自动封装,将一条记录,封装给两个对象(Customer,Order)

 * 将两个对象添加到一个对象数组中Object[Customer,Order]

 * * 迫切左外链接 left outer join fetch

 * 底层使用sql的左外连接,hibernate将一条记录封装给Customer,讲order数据封装Order,并将order关联到Customer

 * customer.getOrderSet().add(order)

 * 默认查询的数据重复

 */

Session session = factory.openSession();

session.beginTransaction();

 

//左外连接

// List list = session.createQuery("from Customer c left outer join c.orderSet ").list();

//迫切左外链接 (默认数据重复)

// List list = session.createQuery("from Customer c left outer join fetch c.orderSet ").list();

//迫切左外链接 (去重复)

List list = session.createQuery("select distinct c from Customer c left outer join fetch c.orderSet ").list();

 

 

session.getTransaction().commit();

session.close();

}

 

4.10 命名查询

l 思想:将HQL从java源码中,提取及布置文件被。

l 分类:全局、布局

l 配置

全局:*.hbm.xml
  <class></class><query name=”名称”>HQL语句

 MyBatis 48

 

局部: <class name=””
table=””><id><property> <query
name=””>HQL</class>

 MyBatis 49

 

l 获得

全局:

session.getNamedQuery(“queryName”)

局部:

session.getNamedQuery(“className.queryName”)  需要利用类似的全限定称号

 

 MyBatis 50

 

@Test

public void demo09(){

/* 9 命名查询

 */

Session session = factory.openSession();

session.beginTransaction();

 

//全局

//List list = session.getNamedQuery("findAll").list();

//局部

List list = session.getNamedQuery("com.itheima.a_init.Customer.findAll").list();

 

System.out.println(list.size());

 

session.getTransaction().commit();

session.close();

}

 

 

QBC【了解】

 

5.0.0.1 QBC查询:

QBC:Query By Criteria条件查询.面向对象的查询的方式.

5.0.0.2 QBC简单的询问:

// 简单询问:

List<Customer> list =
session.createCriteria(Customer.class).list();

for (Customer customer : list) {

System.out.println(customer);

}

5.0.0.3 QBC分页的查询:

Criteria criteria = session.createCriteria(Order.class);

criteria.setFirstResult(10);

criteria.setMaxResults(10);

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

5.0.0.4 QBC排序查询:

Criteria criteria = session.createCriteria(Customer.class);

// criteria.addOrder(org.hibernate.criterion.Order.asc(“age”));

criteria.addOrder(org.hibernate.criterion.Order.desc(“age”));

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

5.0.0.5 QBC条件查询:

// 按号查询:

/*Criteria criteria = session.createCriteria(Customer.class);

criteria.add(Restrictions.eq(“cname”, “tom”));

List<Customer> list = criteria.list();*/

 

// 模糊查询;

/*Criteria criteria = session.createCriteria(Customer.class);

criteria.add(Restrictions.like(“cname”, “t%”));

List<Customer> list = criteria.list();*/

 

// 条件并列查询

Criteria criteria = session.createCriteria(Customer.class);

criteria.add(Restrictions.like(“cname”, “t%”));

criteria.add(Restrictions.ge(“age”, 35));

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

 

 

5.0.0.6 离线查询(了解)

l DetachedCriteria 离线查询对象,不需利用Session就好凑合查询条件。一般采用以web层或service层拼凑。将这个目标传递给dao层,此时用同session进行绑定执行查询。

l 离线查询条件以及QBC一样的。

 MyBatis 51

 

 

@Test

public void demo10(){

/* 10 离线查询

 */

 

//web & service

DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Customer.class);

detachedCriteria.add(Restrictions.eq("cid", 1));

 

//—————dao

 

Session session = factory.openSession();

session.beginTransaction();

 

// 离线Criteria 与session绑定

Criteria criteria = detachedCriteria.getExecutableCriteria(session);

List<Customer> allCustomer = criteria.list();

System.out.println(allCustomer.size());

 

session.getTransaction().commit();

session.close();

}

 

 

 

 

周边配置

6.1 整合c3p0(连接池) (了解)

l 整合c3p0

 MyBatis 52

 

步骤一:导入c3p0 jar包

 MyBatis 53

 

步骤二:hibernate.cfg.xml 配置

hibernate.connection.provider_class
org.hibernate.connection.C3P0ConnectionProvider

 MyBatis 54

 

l c3p0切实可行部署参数

###########################

### C3P0 Connection Pool###

###########################

 

#hibernate.c3p0.max_size 2

#hibernate.c3p0.min_size 2

#hibernate.c3p0.timeout 5000

#hibernate.c3p0.max_statements 100

#hibernate.c3p0.idle_test_period 3000

#hibernate.c3p0.acquire_increment 2

#hibernate.c3p0.validate false

 

6.2 事务

6.2.1 回顾

l 事务:一组工作操作,要么全部遂,要么全部休成功。

l 特性:ACID

原子性:整体

一致性:数据

隔离性:并发

持久性:结果

l 隔离问题:

污浊读:一个工作读到任何一个作业未提交的情

不足再读:一个事情读到外一个政工都交给的情(insert)

心虚读(幻读):一个事务读到另外一个事情都交给的始末(update)

l 隔离级别–解决问题

read uncommittd,读不提交。存在3独问题。

read committed,读就提交。解决:脏读。存在2只问题。

repeatable read ,可还读。解决:脏读、不可再读。存在1独问题。

serializable,串行化。单事务。没有问题。

 

 MyBatis 55

 

6.2.2 hibernate设置隔离级别

l 在hibernate.cfg.xml 配置

hibernate.connection.isolation 4

 MyBatis 56

 

 

6.2.3 lost update 丢失更新

 MyBatis 57

 

l 悲观锁:丢失更新得会出。

用数据库锁机制。

读锁:共享锁。

select …. from  … lock in share mode;

写锁:排他锁。(独占)

select … from  ….  for update

 MyBatis 58

 

 

l 乐观锁:丢失更新得不会见产生

于说明中提供一个字段(版本字段),用于标识记录。如果版本不等同,不允许操作。

 

 MyBatis 59

 

6.2.4 hibernate处理掉更新

l 悲观锁:写锁

 MyBatis 60

 

@Test

public void demo01(){

//1 查询所有

Session session = factory.openSession();

session.beginTransaction();

 

Customer customer = (Customer) session.get(Customer.class, 1 ,LockMode.UPGRADE);

System.out.println(customer);

 

session.getTransaction().commit();

session.close();

}

 

 MyBatis 61

 

 

l 乐观锁:

当PO对象(javabean)提供字段,表示版本字段。一般Integer

在*.hbm.xml 文件配置 <version name=”…”>

 

步骤一:

 MyBatis 62

 

步骤二:

 

 MyBatis 63

MyBatis 64

 

步骤三:测试

@Test

public void demo02(){

//1 查询所有

Session session = factory.openSession();

session.beginTransaction();

 

// Order order = new Order();

// order.setPrice(998d);

// session.save(order);

 

Order order = (Order) session.get(Order.class, 32);

order.setPrice(889d);

 

 

session.getTransaction().commit();

session.close();

}

 

 

整合log4j(了解)

l slf4j 核心jar  : slf4j-api-1.6.1.jar 。slf4j是日记框架,将另外可以的日志第三着开展重组。

 MyBatis 65

 

l 整合导入jar包

log4j 核心包:log4j-1.2.17.jar

过渡jar(整合jar):slf4j-log4j12-1.7.5.jar

l 导入配置文件

log4j.properties  ,此安排文件通知log4j 如何输出日志

 

l 配置文件内容:

1.记录器

2.输出源

3.布局

l 记录器

例如: log4j.rootLogger=info, stdout,file

格式:log4j.rootLogger=日志级别, 输出源1,输出源2,。。。。

log4j 日志级别 : fatal 致命错误 error 错误 warn 警告 info 信息 debug 调试信息 trace 堆栈信息
(由高到底顺序)

l 输出源:

例如:log4j.appender.file=org.apache.log4j.FileAppender

格式:log4j.appender.输出源的名=输出源的贯彻类似

名称:自定义

实现类:log4j提供

 

出口源属性例如:log4j.appender.file.File=d\:mylog.log

输出源属性格式:log4j.appender.名称.属性=值

每一个输出源对应一个落实类似,实现类似都属性(setter),底层执行setter方法进行赋值

 

l 常见的输出源实现类

org.apache.log4j.FileAppender  输出文件中

file ,表示文件输出位置

org.apache.log4j.ConsoleAppender 输出到控制台

Target ,表示以啊种输出方式,在控制台打印内容,取值:System.out
/ System.err

l 布局  — 确定输出格式

例如:log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

格式:log4j.appender.数据源.layout=org.apache.log4j.PatternLayout

布局属性:log4j.appender. 数据源.layout.ConversionPattern=值

12:56:30,123  info

 

l 扩展:对点名的目录设置日志级别

例如:log4j.logger.org.hibernate.transaction=debug

格式:log4j.logger.包结构=级别

一对一(了解)

l 情况1:主表的主键,与从表的外键(唯一),形成主外键关系

l 情况2:主表的主键,与从表的主键,形成主外键关系
(从表的主键又是外键)

 

2.1.1 情况1

 MyBatis 66

 

 MyBatis 67

 

 

2.1.2 情况2

 MyBatis 68

 

 MyBatis 69

 

 

 

二级缓存【掌握】

3.1 介绍

3.1.1 缓存

缓存(Cache): 计算机世界非常通用的定义。它在应用程序永久性数据存储源(如硬盘上的文本或者数据库)之间,其作用是跌应用程序直接读写硬盘(永久性数据存储源)的效率,从而增强使用的周转性能。缓存中的数量是数额存储源中数据的正片。缓存的物理介质通常是内存

缓存:程序<–(内存)–>硬盘

 

3.1.2 咦是二级缓存

 

l hibernate 提供缓存机制:一级缓存、二级缓存

一级缓存:session级别缓存,在相同次于呼吁中共享数据。

二级缓存:sessionFactory级别缓存,整个应用程序共享一个对话工厂,共享一个二级缓存。

l SessionFactory的休息存有数组成部分: 内置缓存:使用一个Map,用于存放配置信息,预定义HQL语句等,提供被Hibernate框架自己用,对外只读的。不可知操作。

外置缓存:使用其它一个Map,用于存放用户从定义数据。默认不打开。外置缓存hibernate只供专业(接口),需要第三正在实现类似。外置缓存有变为二级缓存。

 

 

3.1.3 二级缓存内部结构

 MyBatis 70

 

l 二级就是由于4部分做

n 类级别缓存

n 集合级别缓存

n 时间戳缓存

n 查询缓存(二级缓存的第2多数,三级缓存)

3.1.4 出现访问策略

 MyBatis 71

 

l 访问策略:读写型(read-write)、只读型(read-only)

 

3.1.5 下场景

l 适合放入二级缓存中的数目:

雅少吃涂改

未是雅重大之多少, 允许出现偶尔的产出问题

l 不称放入二级缓存中的数量:

时常吃改动

财务数据, 绝对莫允出现并发问题

跟另外使用数据共享的多少

3.1.6 二级缓存提供商

EHCache: 可作为进程(单机)范围外的缓存, 存放数据的物理介质可以是内存还是硬盘, 对 Hibernate 的查询缓存提供了支撑。–支持集群。

l OpenSymphony `:可作为进程范围外之缓存, 存放数据的物理介质可以是内存还是硬盘, 提供了增长的缓存数据过期策略, 对 Hibernate 的询问缓存提供了支持

l SwarmCache: 可视作集群范围外的缓存, 但不支持 Hibernate 的询问缓存

l JBossCache:可看做集群范围外的缓存, 支持 Hibernate 的询问缓存

 MyBatis 72

 

X表示支持

 

 

 

 

3.2 配置(操作)

1.导入jar包:ehcache-1.5.0.jar/ commons-logging.jar/
backport-util-concurrent.jar

2.被二级缓存(我若运用二级缓存)

3.规定二级缓存提供商(我而运谁二级缓存)

4.规定要缓存内容

1>配置需要缓存的类似

2>配置需要缓存的成团

5.配置ehcache自定义配置文件

 

 

3.2.1 导入jar包

 MyBatis 73

 

 

3.2.2 被二级缓存

 MyBatis 74

 

l 于hibernate.cfg.xml 配置二级缓存

<!– 9.1 开启二级缓存 –>

<property name="hibernate.cache.use_second_level_cache">true</property>

 

3.2.3 规定提供商

 MyBatis 75

 

l hibernate.cfg.xml 配置

<!– 9.2 提供商 –>

<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

 

 

3.2.4 确定缓存内容

l 于hibernate.cfg.xml 确定 类缓存
和汇缓存配置起

 MyBatis 76

 

l 配置

<!– 9.3 确定缓存内容 –>

<!– 类缓存 –>

<class-cache usage="read-write" class="com.itheima.a_init.Customer"/>

<class-cache usage="read-write" class="com.itheima.a_init.Order"/>

<!– 集合缓存 –>

<collection-cache usage="read-write" collection="com.itheima.a_init.Customer.orderSet"/>

 

3.2.5 ehcache配置文件

步骤1:从jar包复制xml文件

 MyBatis 77

 

步骤2:将xml重命名“ehcache.xml”

 MyBatis 78

 

手续3:将修改后的xml,拷贝到src下

 

 MyBatis 79

 

3.3 演示

3.3.1 证明

@Test

public void demo01(){

//1 证明二级缓存存在

// * 修改toString()

// * 如果二级缓存开启,查询3 没有select语句,表示从二级缓存获得的。

// * 将二级缓存关闭,查询3将触发select语句。

Session s1 = factory.openSession();

s1.beginTransaction();

 

//1 查询id=1 — 执行select (查询后,将数据存放在一级缓存,之后由一级缓存同步到二级缓存)

Customer c1 = (Customer) s1.get(Customer.class, 1);

System.out.println(c1);

//2 查询id=1 –从一级缓存获取

Customer c2 = (Customer) s1.get(Customer.class, 1);

System.out.println(c2);

 

s1.getTransaction().commit();

s1.close();

 

System.out.println("———-");

 

Session s2 = factory.openSession();

s2.beginTransaction();

 

//3 查询id=1 — 从二级缓存获取

Customer c3 = (Customer) s2.get(Customer.class, 1);

System.out.println(c3);

 

s2.getTransaction().commit();

s2.close();

}

 

3.3.2 类缓存

l 类缓存:只存放数据

l 一级缓存:存放对象自我

 MyBatis 80

 

@Test

public void demo02(){

//2 类缓存:只存放数据,散装数据。

// * 使用默认的toString();

Session s1 = factory.openSession();

s1.beginTransaction();

 

//1 查询id=1 — 执行select

Customer c1 = (Customer) s1.get(Customer.class, 1);

System.out.println(c1);

//2 查询id=1 — 从一级缓存获取,一级缓存存放对象本身

Customer c2 = (Customer) s1.get(Customer.class, 1);

System.out.println(c2);

 

s1.getTransaction().commit();

s1.close();

 

System.out.println("———-");

 

Session s2 = factory.openSession();

s2.beginTransaction();

 

//3 查询id=1 — 对象不一样,数据一样

Customer c3 = (Customer) s2.get(Customer.class, 1);

System.out.println(c3);

 

s2.getTransaction().commit();

s2.close();

}

 

3.3.3 集缓存

 

 MyBatis 81

MyBatis 82

 

 

@Test

public void demo03(){

//3 集合缓存:只存放关联对象OID的值,如果需要数据,从类缓存中获取。

// * 3.1 默认:第一条select 查询客户,第二天 select 查询客户所有订单

// * 3.2 操作:在hibernate.cfg.xml 将 Order 类缓存删除

// *** <!–  <class-cache usage="read-write" class="com.itheima.a_init.Order"/>–>

// *** 多了10条select,通过订单的id查询订单

Session s1 = factory.openSession();

s1.beginTransaction();

 

//1 查询id=1

Customer c1 = (Customer) s1.get(Customer.class, 1);

System.out.println(c1);

//2 获得订单

for (Order o1 : c1.getOrderSet()) {

System.out.println(o1);

}

 

 

s1.getTransaction().commit();

s1.close();

 

System.out.println("———-");

 

Session s2 = factory.openSession();

s2.beginTransaction();

 

//3 查询id=1

Customer c3 = (Customer) s2.get(Customer.class, 1);

System.out.println(c3);

//4 获得订单

for (Order o2 : c3.getOrderSet()) {

System.out.println(o2);

}

 

s2.getTransaction().commit();

s2.close();

}

 

3.3.4 时间戳

l 时间戳:任何操作都以时穿中记录操作时间。

 

 MyBatis 83

 

@Test

public void demo04(){

//4 时间戳: 所有的操作都会在时间戳中进行记录,如果数据不一致,将触发select语句进行查询

// * 修改toString()

Session s1 = factory.openSession();

s1.beginTransaction();

 

//1 查询id=1

Integer cid = 1;

Customer c1 = (Customer) s1.get(Customer.class, cid);

System.out.println(c1);

//2 绕过一级和二级缓存,修改数据库,修改客户cname=大东哥

s1.createQuery("update Customer set cname = ? where cid = ?")

.setString(0, "大东哥")

.setInteger(1, cid)

.executeUpdate();

//3打印

System.out.println(c1);

 

s1.getTransaction().commit();

s1.close();

 

System.out.println("———-");

 

Session s2 = factory.openSession();

s2.beginTransaction();

 

//4 查询id=1  — ?

Customer c3 = (Customer) s2.get(Customer.class, 1);

System.out.println(c3);

 

s2.getTransaction().commit();

s2.close();

}

3.3.5 询问缓存

l 查询缓存又称作三级缓存(民间)

l 查询缓存默认不应用。需要手动开启

l 查询缓存:将HQL语句与
查询结果进行绑定。通过HQL相同语句可以缓存内容。

默认情况Query对象仅拿查询结果存放于一级及二级缓存,不从一级或二级缓存获取。

查询缓存就是深受Query可以打二级缓存获得内容。

 

步骤同:开启查询缓存

 MyBatis 84

 

<!– 9.4 开启查询缓存 –>

<property name="hibernate.cache.use_query_cache">true</property>

 

步骤二:在询问query对象,设置缓存内容(注意:存放和查询
都亟需设置)

 

 MyBatis 85

 

 MyBatis 86

 

 

@Test

public void demo05(){

//5 查询缓存

Session s1 = factory.openSession();

s1.beginTransaction();

 

//1 query查询

Query q1 = s1.createQuery("from Customer");

q1.setCacheable(true);

List<Customer> a1 = q1.list();

for (Customer c1 : a1) {

System.out.println(c1);

}

 

//2 cid =1  — 一级缓存获得

Customer customer = (Customer) s1.get(Customer.class, 1);

System.out.println(customer);

 

s1.getTransaction().commit();

s1.close();

 

System.out.println("———-");

 

Session s2 = factory.openSession();

s2.beginTransaction();

 

//2 cid =1  — 二级缓存获得

Customer customer2 = (Customer) s2.get(Customer.class, 1);

System.out.println(customer2);

 

//3 query查询

Query q2 = s2.createQuery("from Customer");

q2.setCacheable(true);

List<Customer> a2 = q2.list();

for (Customer c2 : a2) {

System.out.println(c2);

}

 

s2.getTransaction().commit();

s2.close();

}

 

 

3.4 ehcache配置文件

l <diskStore path=”java.io.tmpdir”/>  设置临时文件存放位置。(缓存一般内存,一定水平时,写副硬盘。)

 

l 缓存详细设置

<defaultCache> 所有的缓存对象默认的布

<cache name=”类”> 指定对象单独安排

l 参数设置

maxElementsInMemory=”10000″  内存最要命屡屡

eternal=”false”  是否永久(内存常驻留)

timeToIdleSeconds=”120″

timeToLiveSeconds=”120″

overflowToDisk=”true”  内存满了,是否刻画副到硬盘

maxElementsOnDisk=”10000000″  硬盘最要命累

diskPersistent=”false”  关闭JVM,是否将内存保存硬盘中

diskExpiryThreadIntervalSeconds=”120″  轮询

memoryStoreEvictionPolicy=”LRU”

Least Recently Used (specified as LRU).

First In First Out (specified as FIFO)

Less Frequently Used (specified as LFU)

  • maxElementsInMemory :设置基于内存的缓存中可存放的对象最大数目
  • eternal:设置对象是否为永久的,true表示永不过期,此时将忽略timeToIdleSeconds 和 timeToLiveSeconds属性; 默认值是false
  • timeToIdleSeconds:设置对象空闲最长时间,以秒为单位, 超过这个时间,对象过期。当对象过期时,EHCache会把它从缓存中清除。如果此值为0,表示对象可以无限期地处于空闲状态。
  • timeToLiveSeconds:设置对象生存最长时间,超过这个时间,对象过期。
    如果此值为0,表示对象可以无限期地存在于缓存中. 该属性值必须大于或等于 timeToIdleSeconds 属性值
  • overflowToDisk:设置基于内在的缓存中的对象数目达到上限后,是否把溢出的对象写到基于硬盘的缓存中
  • diskPersistent 当jvm结束时是否持久化对象 true false 默认是false
  • diskExpiryThreadIntervalSeconds 指定专门用于清除过期对象的监听线程的轮询时间
  •  memoryStoreEvictionPolicy – 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出) 

 

网站地图xml地图