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

set马克斯Results(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{

//一对多:一个客户 拥有 五个订单

MyBatis,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 笛Carl积

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地图