Hibernate的使用

  • 一、快速起步
    • 导入依赖
    • 配置文件
    • 实体类
    • 映射配置
      • 日期|时间映射
    • 新增测试
    • 备注
  • 二、Session缓存
    • 操作缓存
      • Flush
      • Refresh
      • Clear
    • 持久化对象的状态
      • 临时对象
      • 持久化对象
      • 删除对象
      • 游离对象
    • Session的核心方法
      • svae
      • persist
      • get
      • load
      • update
      • saveOrUpdate
      • merge
      • delete
      • evict
    • 调用存储过程
    • 触发器
    • C3P0
      • 依赖
      • 配置
  • 三、单项多对一
    • 保存
      • 注意
      • 保存顺序
    • 查询
      • 从多查一
    • 修改
    • 删除
  • 四、双向一对多
    • 配置
    • 保存
      • 注意
    • 解决办法
    • 查询
    • 修改
    • 配置Set的细节
      • inverse
      • cascade
      • order by
  • 五、外键映射一对一
    • 实体类
    • 映射配置
    • 测试保存
      • 注意
    • 查询
      • 问题
  • 六、主键映射一对一
    • one-to-one
  • 七、单向多对多
    • 实体类
    • 映射配置
    • 保存
    • 获取
  • 八、双向多对多
    • 实体类
    • 映射文件
    • 插入
  • 九、映射继承关系
    • subclass
      • 实体类
      • 配置
      • 插入
      • 查询
      • 缺点
    • joined-subclass
      • 配置
      • 插入
      • 缺点
      • 优点
    • union-subclass
      • 配置
      • 插入
        • MappingException
      • 更新
      • 优点
      • 缺点
    • 三种继承方式的比较
  • 十、检索策略
    • 检索数据时的2个问题
    • 类级别
    • 一对多和多对多
      • Lazy
        • 延迟与增强延迟
      • Batch-Size
      • fetch
    • 多对一和一对一
    • 小结
  • 十一、检索方式
    • HQL
      • 环境搭建
      • 起步
        • 占位符绑定参数
        • 参数名绑定参数
      • 与SQL差异
      • 绑定参数
      • 分页查询
      • 命名查询
      • 投影查询
      • 报表查询
      • (迫切)左外连接
      • (迫切)内连接
    • QBC&本地SQL
      • QBC
      • 本地SQL
  • 十二、二级缓存
    • SessionFactory
    • 注意点
    • 并发访问策略
    • 二级缓存实现方式
      • EHcache
      • 集合的二级缓存
        • 注意
      • 时间戳缓存
      • iterate
  • 十三、管理Session
    • Session 对象的生命周期与本地线程绑定
    • Util类
    • 配置管理Session方式
      • 注意
    • 批量操作
      • 通过Session批量操作
    • 注意
    • StateLessSession进行批量操作
    • HQL

一、快速起步

新建一个maven项目

导入依赖

<dependencies><dependency><groupId>antlr</groupId><artifactId>antlr</artifactId><version>2.7.7</version></dependency><dependency><groupId>dom4j</groupId><artifactId>dom4j</artifactId><version>1.6.1</version></dependency><dependency><groupId>org.hibernate.common</groupId><artifactId>hibernate-commons-annotations</artifactId><version>4.0.2.Final</version></dependency><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-core</artifactId><version>4.2.4.Final</version></dependency><dependency><groupId>org.hibernate.javax.persistence</groupId><artifactId>hibernate-jpa-2.0-api</artifactId><version>1.0.1.Final</version></dependency><dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId><version>3.15.0-GA</version></dependency><dependency><groupId>org.jboss.logging</groupId><artifactId>jboss-logging</artifactId><version>3.1.0.GA</version></dependency><dependency><groupId>org.jboss.spec.javax.transaction</groupId><artifactId>jboss-transaction-api_1.1_spec</artifactId><version>1.0.1.Final</version></dependency><!--数据库驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.9</version><scope>compile</scope></dependency></dependencies><!-- IDEA无法自动读取java文件下的xml文件,要配置声明编译JAVA目录下的文件 --><build><resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource></resources></build>

配置文件

dtd约束在官方文件上有

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"><hibernate-configuration><session-factory><!-- 配置连接数据库的基本信息 --><property name="connection.username">root</property><property name="connection.password">root</property><property name="connection.driver_class">com.mysql.jdbc.Driver</property><property name="connection.url">jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=UTF8</property><!-- 配置Hibernate的基本信息 --><!-- 1.hibernate所使用的数据库方言-》哪种数据库 --><property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property><!-- 2.执行操作时是否再控制台打印SQL --><property name="show_sql">true</property><!-- 3.是否对SQL进行格式化 --><property name="format_sql">true</property><!-- 4.指定自动生成数据表的策略 --><property name="hibernate.hbm2ddl.auto">update</property>  </session-factory></hibernate-configuration>

更多配置:官方地址

实体类

public class Person {private Integer personId;private String personName;private Integer personAge;public Person() {}@Overridepublic String toString() {return "Person{" +"personId=" + personId +", personName='" + personName + '\'' +", personAge=" + personAge +'}';}public Person(String personName, Integer personAge) {this.personName = personName;this.personAge = personAge;}public Integer getPersonId() {return personId;}public void setPersonId(Integer personId) {this.personId = personId;}public String getPersonName() {return personName;}public void setPersonName(String personName) {this.personName = personName;}public Integer getPersonAge() {return personAge;}public void setPersonAge(Integer personAge) {this.personAge = personAge;}
}

映射配置

映射文件的配置:官方文档

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC"-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping><class name="per.xgt.pojo.Person" table="PERSON"><!--name:表对应类的全类名table: 类对应的表名id标签:表的主键name:映射类的属性名type:属性类型全类名column:对应表的字段名generator:主键生成策略property:非主键的其他字段映射name:映射类的属性名type:属性类型全类名column:对应表的字段名--><id name="personId" type="java.lang.Integer"><column name="PersonId" /><!-- 指定主键的生成方式:native:数据库底层生成方式--><generator class="native" /></id><property name="personName" type="java.lang.String"><column name="PersonName" /></property><property name="personAge" type="java.lang.Integer"><column name="PersonAge" /></property></class></hibernate-mapping>

注:你可以放在resources目录下,我放在了java目录下自己建的包里面,所以会在maven里面添加最后build标签里面的内容,如果是Eclipse里面不需要,会在编译的时候直接编译进去,IDEA不会,所以需要配置一下

在hibernate核心配置文件中配置指明映射配置文件位置

<!-- 5.指定关联的 hbm.xml 文件 --><mapping resource="per/xgt/pojo/Person.hbm.xml" />

日期|时间映射

Java,java下sql包下的三个类对应SQL中Date、time、timestamp类sql中,date表示日期,time表示时间,timestamp表示时间戳(同时包含日期和时间)java.util.date是上述三个类的父类,所有能和三个类型都对应,所以在设置持久化类的date类型时,设置为util.date。

Util.date分别映射为三个类型中之一

可以通过property的type属性来进行映射<property name="date" type="timestamp"><column name="date" />
</property>
<property name="date" type="time"><column name="date" />
</property>
<property name="date" type="date"><column name="date" />
</property>
其中timestamp,date,time既不是java类型,也不是标准sql类型,而是hibernate映射类型

在这里插入图片描述
在这里插入图片描述
这是完成的目录结构
在这里插入图片描述

新增测试

public class test {@Testpublic void test(){//1.创建SessionFactory对象SessionFactory sessionFactory = null;//1)创建Configuration对象:对应Hibernate的基本配置信息和对象关系映射信息Configuration configuration = new Configuration().configure();/*** 4.0以前是这样创建的* sessionFactory = configuration.buildSessionFactory();*///2)创建一个ServiceRegistry对象:Hibernate4.x新添加的对象-》Hibernate的任何配置和服务都需要再该对象中注册后才能有效ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();//3)创建一个SessionFactorysessionFactory = configuration.buildSessionFactory(serviceRegistry);//2.创建一个Session对象Session session = sessionFactory.openSession();//3.开启事务Transaction transaction = session.beginTransaction();//4.执行保存操作Person person = new Person("河豚", 2);session.save(person);//5.提交事务transaction.commit();//6.关闭Session,关闭SessionFactorysession.close();sessionFactory.close();}}

效果
在这里插入图片描述

备注

  1. Hibernate默认需要自己手动开启和提交事务。
  • hibernate.hbm2ddl.auto

    Hibernate配置文件的配置项:可以帮助实现生成具体的表结构,取值:

    1.create-》每次运行都会根据配置重新生成表,哪怕没有任何改变

    2.update-》在没有表的时候会生成表,如果有表但是结构不同会更改表的结构,如果都相同,则只会更新数据,不会删除已有的数据

    3.create-drop-》会自动生成表,但是SessionFactory一关闭就会自动删除表

    4.validate-》会和数据库中的表进行比较,若.hbm.xml文件中的列在数据表中不存在,则会抛出异常

  • format_sql

    是否将SQL转化为格式良好的SQL,取值true|false

  • Session

    1.Hibernate向应用程序提供的操作数据库的最主要的接口,提供了基本的保存、更新、删除和加载Java对象的方法

    2.具有一个缓存,位于缓存中的对象成为持久化对象。它和数据库中的相关记录对应。Session能够在某些时间点,按照缓存中对象的变化来执行相关的SQL语句,来同步更新数据库,这一过程被称为刷新缓存(Flush)

    3.Hibernate把对象分为4种状态:持久化、临时、游离、删除。Session的特定方法能使对象从一个状态转换到另一个状态

二、Session缓存

在Session接口得实现中包含一系列得Java集合,这些Java集合构成了Session缓存,只要Seesion实例没有结束生命周期,且没有清理缓存,则存放在它缓存中得对象也不会结束生命周期-------》可较少Hibernate应用程序访问数据库得频率

操作缓存

Flush

强制使数据库与缓存对象保持一致,如果不一致,会调用SQL语句进行一致性操作

@Testpublic void testSessionFlush(){Person person = (Person) session.get(Person.class, 1);person.setPersonName("上原");}

效果
在这里插入图片描述

  1. 在Transaction的commit方法中:先调用session的flush方法,再提交事务。
  2. flush方法可能会发送SQL语句,但不会提交事务。所以需要手动提交事务。
  3. 注意:1)在未提交事务或显式的调用session.flush()方法之前,也有可能会进行flush操作:①HQL或QBC查询,会先进行flush操作,将得到数据表的最新的记录。②若记录的ID是由底层数据库使用自增的方式生成的,则在save方法后则会立即发送insert语句,因为save方法后,必须保证对象的ID是存在的。

commit和flush

  • flush执行一系列sql语句,但是不会提交事务,
  • commit方法先调用flush方法,然后提交事务,提交事务意味着数据库操作永久保存下来

Refresh

强制使内存当中数据状态与数据库保存一直,意味着会发送select语句。

@Testpublic void testSeesionReflesh() throws InterruptedException {Person person = (Person) session.get(Person.class, 2);System.out.println(person);session.refresh(person);System.out.println(person);}

在这里插入图片描述
可以看到,已经再次发送了一次select语句,但是出现的数据还是没有变化。这是数据库的隔离级别问题。
MySQL默认是可重复读
Oracle默认是读已提交
可以在命令窗口设置,也可以在Hibernate里面设置Hibernate的隔离级别:

<!-- 5.设置Hibernate的事务隔离级别 -->
<property name="connection.isolation">2</property>

隔离级别

1.READ UNCOMMITED-读未提交
2.READ COMMITED-读已提交
4.REPEATABLEREAD-可重复读
8.SERIALIZEABLE-可串行化

断点看效果
在这里插入图片描述
修改数据库数据,然后执行断点
在这里插入图片描述

Clear

清理缓存

持久化对象的状态

临时对象

(Transient)

1.在使用代理主键的情况下,OID通常为null;

2.不处于Session的缓存中;

3.在数据库中没有对应的记录

持久化对象

(托管)(Persist)

1.OID不为null;

2.位于Session缓存中;

3.若在数据库中已经有和其对应的记录,持久化对象和数据库中的相关记录对应;

4.Session在flush缓存时,会根据持久化对象的属性变化,来同步更新数据库;

5.在同一个Session实例的缓存中,数据库表中的每条记录只对应唯一的持久化对象

删除对象

(Removed)

1.在数据库中没有其OID对应的记录;

2.不再处于Session缓存中;

3.一般情况下,应用程序不再使用被删除的对象。

游离对象

(脱管)(Detached)

1.OID不为Null;

2.不再处于Session缓存中;

3.一般情况下,游离对象是由持久化对象转变过来的,因此在数据库中可能还存在与它对应的记录。

对象的状态转换图
在这里插入图片描述

Session的核心方法

svae

@Testpublic void testSave(){Person person = new Person();person.setPersonName("雪莱");person.setPersonAge(28);System.out.println(person);session.save(person);System.out.println(person);}

效果
在这里插入图片描述
save()方法

  1. 使临时对象变化为持久化对象
  2. 为对象分配ID
  3. 在flush缓存时,会发送一条insert语句
  4. 在save方法之前设置id是无效的
  5. 持久化对象的ID是不能被修改的

persist

@Testpublic void testPersist(){Person person = new Person();person.setPersonName("亚衣");person.setPersonAge(28);System.out.println(person);session.persist(person);System.out.println(person);}

效果
在这里插入图片描述
persist()方法

  1. 也会执行一个insert语句
  2. 在调用persist方法之前,若对象已经有id了,则不会执行insert语句,则会抛出一个一场

get

@Testpublic void testGet(){Person person = (Person)session.get(Person.class, 1);System.out.println(person);}

效果
在这里插入图片描述

load

@Testpublic void testLoad(){Person person = (Person)session.load(Person.class, 1);System.out.println(person);}

效果
在这里插入图片描述
get和load的区别

  1. 执行get方法,会立即加载对象—》立即加载(检索)

    执行load方法,若不使用该对象,则不会立即执行select查询,而会返回一个代理对象—》延迟加载(检索)

  2. 若数据表中没有对应的记录,且Session也没有关闭,同时需要使用对象时:

    get:返回null

    load:若不是用对象的任何属性,没问题;若需要初始化了,抛出异常。

  3. load方法可能会抛出懒加载异常(LazyInitializationException),在需要初始化代理对象之前,已经关闭了Session

update

  1. 若更新一个持久化对象,不需要显示地调用update方法,因为在调用Transaction的commit方法时,会先执行session的flush方法

  2. 更新一个游离对象,需要显示地调用Session的update方法,可以把一个游离对象变为持久化对象

  3. 无论要更新的游离对象和数据表的记录是否一直,都会发送update语句

  4. 让session不再盲目地发出update语句:再.hbm.xml的class节点设置select-before-update = true(默认为false,通常不需要设置)

在这里插入图片描述

  1. 若数据表中没有对应的记录,但还是调用了update方法,会抛出异常

  2. 当update方法关联一个游离对象时,如果在Session的缓存中已经存在相同OID的持久化对象,会抛出异常

saveOrUpdate

saveOrUpdate方法同时包含了save和update方法的功能

如果是游离对象:update

如果是临时对象:save

判断对象为临时对象的标准

  1. Java对象的OID为null
  2. 映射文件中为设置了unsaved-value属性,并且java对象的OID取值与这个unsaved-value属性值匹配
@Test
public void testSaveOrUpdate(){Person person = new Person();person.setPersonName("小泽");person.setPersonAge(35);session.saveOrUpdate(person);
}

在这里插入图片描述

@Testpublic void testSaveOrUpdate(){Person person = new Person();person.setPersonName("玛丽亚");person.setPersonAge(35);person.setPersonId(11);session.saveOrUpdate(person);}

在这里插入图片描述
注意

  1. 若OID不为null,但数据表中还没有和其对应的记录,会抛异常(执行的是一个update操作)
  2. OID值等于id的unsaved-value属性值的对象,也被认为是一个游离对象

merge

delete

执行删除操作,只要OID和数据表中一条记录对应,就会准备执行delete操作,若OID在数据表中没有对应的记录,则抛出异常

@Testpublic void testDelete(){Person person = new Person();person.setPersonId(11);session.delete(person);}

效果
在这里插入图片描述

@Testpublic void testDelete(){Person person = new Person();person.setPersonId(12);session.delete(person);}

在这里插入图片描述

可以通过Hibernate配置文件使删除对象后,把OID值置为null

<!-- 删除对象后,把OID置为NULL --><property name="use_identifier_rollback">true</property>

evict

从Session缓存中把指定的持久化对象移除

@Testpublic void testEvict(){Person person1 = (Person) session.get(Person.class, 10);Person person2 = (Person) session.get(Person.class, 11);person1.setPersonAge(30);person2.setPersonAge(30);session.evict(person1);}

效果:只有一个update语句
在这里插入图片描述

调用存储过程

@Testpublic void testDoWork(){session.doWork(new Work() {@Overridepublic void execute(Connection connection) throws SQLException {System.out.println(connection);//TODO 可以调用存储过程}});}

Work接口:直接通过JDBC API来访问数据库的操作。

Session的doWordk(Work)方法用于执行Work对象指定的操作,即调用Work对象的execute方法,Session会把当前使用的数据库链接传递给execute方法

触发器

  1. 在执行完Session的相关操作后,立即调用Session的flush和refresh方法,迫使Session的缓存与数据库同步(Refresh)方法重新从数据库表中加载对象;
  2. 在映射文件中class元素中设置select-before-update属性,方Session在update或saveOrUpdate方法更新一个游离对象时,会先执行select语句,获得当前游离对象在数据库表中的最新数据,只有在不一致的情况下才会执行update语句。

C3P0

依赖

<dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.2.1</version></dependency><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-c3p0</artifactId><version>4.2.4.Final</version></dependency><dependency><groupId>com.mchange</groupId><artifactId>mchange-commons-java</artifactId><version>0.2.3.4</version></dependency>

配置

  1. max_size:数据库连接池最大连接数
  2. min_size:数据库连接池最小连接数
  3. acquire_increment:当数据库连接池中的链接耗尽时,同一时刻获取多少个数据库链接
  4. timeout:数据库连接池中连接对象在多长时间没有使用过后,就应该被销毁
  5. idle_test_period:连接池检测线程多长时间检测一次池内的所有链接对象是否超时,连接池本身不会把自己从连接池中移除,而是专门有一个线程按照一定的时间间隔来做这件事,这个线程通过比较链接对象最后一次被使用的时间和当前的时间差来和timeout做比对,进而决定是否销毁这个链接对象
  6. max_statments:缓存statment对象的数量
<!-- 配置C3P0数据源 --><property name="c3p0.max_size">10</property><property name="c3p0.min_size">5</property><property name="c3p0.acquire_increment">2</property><property name="c3p0.idle_test_period">2000</property><property name="c3p0.timeout">2000</property><property name="c3p0.max_statements">1</property>

三、单项多对一

实体类

public class Customer {private Integer customerId;private String customerName;public Customer() {}public Integer getCustomerId() {return customerId;}public void setCustomerId(Integer customerId) {this.customerId = customerId;}public String getCustomerName() {return customerName;}public void setCustomerName(String customerName) {this.customerName = customerName;}}
public class Order {private Integer orderId;private String orderName;private Customer customer;public Order() {}public Integer getOrderId() {return orderId;}public void setOrderId(Integer orderId) {this.orderId = orderId;}public String getOrderName() {return orderName;}public void setOrderName(String orderName) {this.orderName = orderName;}public Customer getCustomer() {return customer;}public void setCustomer(Customer customer) {this.customer = customer;}
}

映射配置文件

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="per.xgt.pojo"><class name="Order" table="ORDERS"><id name="orderId" type="java.lang.Integer"><column name="ORDER_ID" /><generator class="native" /></id><property name="orderName" type="java.lang.String"><column name="ORDER_NAME" /></property><!--映射多对一的关联关系。使用 many-to-one 来映射多对一的关联关系name: 多对一,多一端类里面对应一的属性的名字class: 一那一端的属性对应的类名column: 一那一端在多的一端对应的数据表中的外键的列的列名--><many-to-one name="customer" class="Customer" column="CUSTOMER_ID"></many-to-one></class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="per.xgt.pojo.Customer" table="CUSTOMERS"><id name="customerId" type="java.lang.Integer"><column name="CUSTOMER_ID" /><generator class="native" /></id><property name="customerName" type="java.lang.String"><column name="CUSTOMER_NAME" /></property></class></hibernate-mapping>

Hibernate的配置

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"><hibernate-configuration><session-factory><!-- 配置连接数据库的基本信息 --><property name="connection.username">root</property><property name="connection.password">root</property><property name="connection.driver_class">com.mysql.jdbc.Driver</property><property name="connection.url">jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=UTF8</property><!-- 配置C3P0数据源 --><property name="c3p0.max_size">10</property><property name="c3p0.min_size">5</property><property name="c3p0.acquire_increment">2</property><property name="c3p0.idle_test_period">2000</property><property name="c3p0.timeout">2000</property><property name="c3p0.max_statements">1</property><!-- 配置Hibernate的基本信息 --><!-- 1.hibernate所使用的数据库方言-》哪种数据库 --><property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property><!-- 2.执行操作时是否再控制台打印SQL --><property name="show_sql">true</property><!-- 3.是否对SQL进行格式化 --><property name="format_sql">true</property><!-- 4.指定自动生成数据表的策略 --><property name="hibernate.hbm2ddl.auto">create</property><!-- 5.设置Hibernate的事务隔离级别 --><property name="connection.isolation">2</property><!-- 删除对象后,把OID置为NULL --><property name="use_identifier_rollback">true</property><!-- 调用Statment.setFetchSize方法设置JDBC的statment读取数据的时候每次从数据库中取出的记录条数,Oracle驱动默认10,Mysql不支持 --><property name="hibernate.jdbc.fetch_size">100</property><!-- 设定对数据库进行批量删除,批量更新和插入的时候的批次大小,类似于设置缓冲区大小的意思,越大批量操作时想数据库发送的SQL的次数越多,速度就越快 Oracle设置成30比较合适 --><property name="hibernate.jdbc.batch_size">30</property><!-- 6.指定关联的 hbm.xml 文件 --><mapping resource="per/xgt/pojo/Person.hbm.xml" /><mapping resource="per/xgt/pojo/Customer.hbm.xml" /><mapping resource="per/xgt/pojo/Order.hbm.xml" /></session-factory></hibernate-configuration>

保存

/*** @Author: Yvonneflynn's husband* @Email:I don't know* @CreateTime: 2020-09-21 15:16:36* @Descirption:*/
public class TestManyToOne {private SessionFactory sessionFactory;private Session session;private Transaction transaction;@Beforepublic void init() {Configuration configuration = new Configuration().configure();ServiceRegistry serviceRegistry= new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();sessionFactory = configuration.buildSessionFactory(serviceRegistry);session = sessionFactory.openSession();transaction = session.beginTransaction();}@Afterpublic void destroy() {transaction.commit();session.close();sessionFactory.close();}@Testpublic void testMany2One(){Customer customer = new Customer();customer.setCustomerName("AA");Order order1 = new Order();order1.setOrderName("Order1");Order order2 = new Order();order2.setOrderName("Order2");//设定关联关系order1.setCustomer(customer);order2.setCustomer(customer);//执行save操作session.save(customer);session.save(order1);session.save(order2);}
}

注意

如果第一次运行根据实体类创建表的时候出现某张表不存在:
把策略改为create或update(推荐)
把数据库方言换成以下(mysql的)
在这里插入图片描述
解释原因
在多的一方的映射文件中,要写包名,且包内或子包内要同时包含多与一
在这里插入图片描述

保存顺序

最好是先保存一的一方,再保存多的一方,因为如果先保存多的一方,而没有一的一方,多的一方保存没有外键,所以在执行完所有insert语句之后会回头执行update语句,浪费了资源。

查询

从多查一

@Testpublic void testMany2OneGet() {  Order order = (Order) session.get(Order.class, 1);System.out.println(order.getCustomer());Customer customer = order.getCustomer();System.out.println(customer);}

注意

  1. 若查询多的一端的对象,则默认情况下只查询了多的一端的对象而没有查询关联一的一方对象
  2. 只有在使用的时候才会发送sql查询一方的对象
  3. 在查询一的一方对象时,由多的一方到一的一方的时候,可能发生懒加载异常
  4. 获取多的一方对象时,其关联的一的一方的对象是代理对象

修改

与普通的修改是一样的,没啥说的,直接调用set方法就行

删除

在不设定级联关系的情况下,不能直接删除一的一方的对象(一的一方的对象有N的对象的引用)

四、双向一对多

配置

一的一方实体类
在这里插入图片描述

需要把集合初始化,且需要使用接口类型,因为Hibernate在获取集合类型时,返回的是Hibernate内置的集合类型不是SE的实现,防止发生空指针异常

映射文件
在这里插入图片描述

<!-- 映射1-n的集合属性set:映射set类型的属性table:set集合中元素对应的记录表名key;指定多的一方表中外键的列名one-to-many:指定映射类名-->
<!-- 映射1-n的集合属性 --><set name="orders" table="ORDERS"><key column="CUSTOMER_ID"></key><one-to-many class="Order"/></set>

保存

@Testpublic void testMany2One() {Customer customer = new Customer();customer.setCustomerName("AA");Order order1 = new Order();order1.setOrderName("Order1");Order order2 = new Order();order2.setOrderName("Order2");//设定关联关系order1.setCustomer(customer);order2.setCustomer(customer);customer.getOrders().add(order1);customer.getOrders().add(order2);//执行save操作session.save(customer);session.save(order1);session.save(order2);}

效果
在这里插入图片描述

注意

执行save操作,先执行一的一方再执行多的一方,会多发update语句

先执行多的一方再执行一的一方一样会多update语句,且更多

因为一的一端和多的一端都维护关联外键关系,所以会多出update语句

解决办法

取消1的一端对外键维护权
在这里插入图片描述
再次测试效果
在这里插入图片描述

查询

从一端查询多端,一样使用的是延迟加载,如果session关闭,会抛出懒加载异常。

修改

@Testpublic void testUpdateOne2Many(){Customer customer = (Customer)session.get(Customer.class, 1);customer.getOrders().iterator().next().setOrderName("修改了");}

SET是没有顺序的,所以,不知道改哪一个
在这里插入图片描述

配置Set的细节

inverse

在这里插入图片描述

  1. 在hibernate中通过对inverse属性来决定双线关系外键关联属性由哪一方来维护,为false的一方主动维护,true的一方放弃维护
  2. 在没有设置的情况下,双方都会维护(默认为true)
  3. 1-n关系中,让n方维护外键关系有助于性能改善(配置集合的那里)
  4. 1-n中,将1方设为维护方会额外多出update语句,且在插入的时候无法为外键列添加非空约束

cascade

在这里插入图片描述
cascade(级联) (可选) 表明操作是否从父对象级联到被关联的对象。

1. 需要掌握的取值如下* none                      -- 不使用级联* save-update               -- 级联保存或更新* delete                    -- 级联删除* delete-orphan             -- 孤儿删除.(注意:只能应用在一对多关系)* all                       -- 除了delete-orphan的所有情况.(包含save-update delete)* all-delete-orphan         -- 包含了delete-orphan的所有情况.(包含save-update delete delete-orphan)2. 孤儿删除(孤子删除),只有在一对多的环境下才有孤儿删除* 在一对多的关系中,可以将一的一方认为是父方.将多的一方认为是子方.孤儿删除:在解除了父子关系的时候.将子方记录就直接删除。* <many-to-one cascade="delete-orphan" />

开发时不建议设定该属性,删除修改建议使用手动操作

order by

如果设置了该属性,当Hibernate通过select语句到数据库中检索集合对象时,利用order by子句进行排序,属性中还可以加入SQL函数

里面使用的是表的字段名,而不是类的属性名

五、外键映射一对一

实体类

/*** @Author: Yvonneflynn's husband* @Email:I don't know* @CreateTime: 2020-09-22 10:59:37* @Descirption:*/
public class Manager {private Integer mgrId;private String mgrName;private Department department;public Integer getMgrId() {return mgrId;}public void setMgrId(Integer mgrId) {this.mgrId = mgrId;}public String getMgrName() {return mgrName;}public void setMgrName(String mgrName) {this.mgrName = mgrName;}public Department getDepartment() {return department;}public void setDepartment(Department department) {this.department = department;}
}
/*** @Author: Yvonneflynn's husband* @Email:I don't know* @CreateTime: 2020-09-22 10:59:47* @Descirption:*/
public class Department {private Integer deptId;private String deptName;private Manager manager;public Integer getDeptId() {return deptId;}public void setDeptId(Integer deptId) {this.deptId = deptId;}public String getDeptName() {return deptName;}public void setDeptName(String deptName) {this.deptName = deptName;}public Manager getManager() {return manager;}public void setManager(Manager manager) {this.manager = manager;}
}

映射配置

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping><class name="per.xgt.pojo.Department" table="DEPARTMENTS"><id name="deptId" type="java.lang.Integer"><column name="DEPT_ID" /><generator class="native" /></id><property name="deptName" type="java.lang.String"><column name="DEPT_NAME" /></property><!-- 使用many-to-one方式来映射1-1关系 --><many-to-one name="manager"class="per.xgt.pojo.Manager"column="MGR_ID"unique="true"></many-to-one></class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="per.xgt.pojo.Manager" table="MANAGERS"><id name="mgrId" type="java.lang.Integer"><column name="MGR_ID" /><generator class="native" /></id><property name="mgrName" type="java.lang.String"><column name="MGR_NAME" /></property><!-- 映射1-1的关联关系:在对应的数据表中已经有外键了,当前持久化类使用one-to-one进行映射 --><one-to-one name="department" class="per.xgt.pojo.Department"></one-to-one></class></hibernate-mapping>

测试保存

private SessionFactory sessionFactory;private Session session;private Transaction transaction;@Beforepublic void init() {Configuration configuration = new Configuration().configure();ServiceRegistry serviceRegistry= new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();sessionFactory = configuration.buildSessionFactory(serviceRegistry);session = sessionFactory.openSession();transaction = session.beginTransaction();}@Afterpublic void destroy() {transaction.commit();session.close();sessionFactory.close();}@Testpublic void test(){}@Testpublic void testSave(){Department department = new Department();department.setDeptName("D1");Manager manager = new Manager();manager.setMgrName("M1");department.setManager(manager);manager.setDepartment(department);session.save(manager);session.save(department);}

效果
在这里插入图片描述

注意

建议先保存没有外键列的对象,会减少UPDATE语句

查询

@Testpublic void testGet(){Department department = (Department) session.get(Department.class, 1);System.out.println(department);Manager manager = department.getManager();System.out.println(manager.getMgrName());}

效果
在这里插入图片描述

问题

在这里插入图片描述

查询条件应该是departments.mgr_id = managers.mgr_id
没有外键的一端需要使用one-to-one元素,该元素使用propertu-ref属性指定使用被关联实体主键以外的字段作为关联字段

<one-to-onename="department"class="per.xgt.pojo.Department"property-ref="manager"></one-to-one>

在查询没有外键的实体对象时,使用左外连接查询,一并查询出其关联的对象,并已经进行初始化

六、主键映射一对一

基于逐渐的映射策略:一端的主键生成器使用foreign策略,表明根据对方的主键来生成自己的主键,自己并不能独立生成主键。子元素指定使用当前持久化类的哪个属性作为对方

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="per.xgt.pojo"><class name="per.xgt.pojo.Department" table="DEPARTMENTS"><id name="deptId" type="java.lang.Integer"><column name="DEPT_ID" /><!--使用外键的方式来生成当前的主键--><generator class="foreign"><!--property属性指定使用当前持久化类的哪一个属性的主键作为外键--><param name="property">manager</param></generator></id><property name="deptName" type="java.lang.String"><column name="DEPT_NAME" /></property><one-to-one name="manager" class="Manager"></one-to-one></class>
</hibernate-mapping>

在这里插入图片描述

在这里插入图片描述

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="per.xgt.pojo.Manager" table="MANAGERS"><id name="mgrId" type="java.lang.Integer"><column name="MGR_ID" /><generator class="native" /></id><property name="mgrName" type="java.lang.String"><column name="MGR_NAME" /></property><!-- 映射1-1的关联关系:在对应的数据表中已经有外键了,当前持久化类使用one-to-one进行映射 --><!-- 没有外键的一端需要使用one-to-one元素,该元素使用propertu-ref属性指定使用被关联实体主键以外的字段作为关联字段 --><one-to-onename="department"class="per.xgt.pojo.Department"></one-to-one></class></hibernate-mapping>

在这里插入图片描述
没有外键关联

 <one-to-one name="manager" class="Manager" constrained="true"></one-to-one>

先插入哪一个实体类都可以,不会有多余的update语句,因为主键根据另一方生成,没有主见插入不了,得等另一方插入后才能根据另一方主键生成主键才能插入

one-to-one

采用foreign主键生成器策略的一端增加one-to-one元素映射关联属性,其one-to-one节点还应增加constrained=true属性,以使当前的主键上添加外键约束

七、单向多对多

实体类

/*** @Author: Yvonneflynn's husband* @Email:I don't know* @CreateTime: 2020-09-23 09:48:04* @Descirption:*/
public class Category {private Integer id;private String name;private Set<Item> items = new HashSet<>();public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Set<Item> getItems() {return items;}public void setItems(Set<Item> items) {this.items = items;}
}
/*** @Author: Yvonneflynn's husband* @Email:I don't know* @CreateTime: 2020-09-23 09:48:13* @Descirption:*/
public class Item {private Integer id;private String name;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

映射配置

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="per.xgt.pojo"><class name="Category" table="CATEGORIES"><id name="id" type="java.lang.Integer"><column name="ID" /><generator class="native" /></id><property name="name" type="java.lang.String"><column name="NAME" /></property><!-- table: 指定中间表 --><set name="items" table="CATEGORIES_ITEMS"><key><column name="C_ID" /></key><!-- 使用 many-to-many 指定多对多的关联关系. column 执行 Set 集合中的持久化类在中间表的外键列的名称  --><many-to-many class="Item" column="I_ID"></many-to-many></set></class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="per.xgt.pojo.Item" table="ITEMS"><id name="id" type="java.lang.Integer"><column name="ID" /><generator class="native" /></id><property name="name" type="java.lang.String"><column name="NAME" /></property> </class>
</hibernate-mapping>

保存

@Testpublic void test1(){Category category1 = new Category();category1.setName("C1");Category category2 = new Category();category2.setName("C2");Item item1 = new Item();item1.setName("I1");Item item2 = new Item();item2.setName("I2");category1.getItems().add(item1);category2.getItems().add(item2);category1.getItems().add(item2);category2.getItems().add(item1);session.save(category1);session.save(category2);session.save(item1);session.save(item2);}

打印效果

Hibernate: insert intoCATEGORIES(NAME) values(?)
Hibernate: insert intoCATEGORIES(NAME) values(?)
Hibernate: insert intoITEMS(NAME) values(?)
Hibernate: insert intoITEMS(NAME) values(?)
Hibernate: insert intoCATEGORIES_ITEMS(C_ID, I_ID) values(?, ?)
Hibernate: insert intoCATEGORIES_ITEMS(C_ID, I_ID) values(?, ?)
Hibernate: insert intoCATEGORIES_ITEMS(C_ID, I_ID) values(?, ?)
Hibernate: insert intoCATEGORIES_ITEMS(C_ID, I_ID) values(?, ?)Process finished with exit code 0

获取

@Testpublic void test2(){Category category = (Category) session.get(Category.class, 1);System.out.println(category.getName());Set<Item> items = category.getItems();System.out.println(items.size());}

结果
在这里插入图片描述
查询链接中间表

八、双向多对多

  • 双向n-n关联需要两端都是用集合属性
  • 双向n-n关联必须使用连接表(中间表)
  • 集合属性应增加key子元素以映射外键列,集合元素里还应增加many-to-many子元素关联实体类
  • 在双向n-n关联的两边都需要指定连接表的表名以及外键列的列名,两个集合元素的set的table元素的值必须指定,而且必须相同。set元素的两个子元素key和many-to-many都必须指定column属性,其中key和many-to-many分别分别指定本持久化类和关联类在链接表中的外键列名,因此两边的key和many-to-many的column属性交叉相同。也就是说,一边的set元素的key的column值为a,many-yo-many的column为b;则另一边的set元素的key和column的值为b,many-to-many的column值为a。
  • 对于双向n-n关联,必须把其中一段的inverse设置为true,否则两端都为hi关联关系可能会造成主键冲突。

实体类

在Item里里面新增Catgory的Set集合属性

private Set<Category> categories = new HashSet<>();public Set<Category> getCategories() {return categories;}public void setCategories(Set<Category> categories) {this.categories = categories;}

映射文件

在Item的映射文件增加Set子元素

<set name="categories" table="CATEGORIES_ITEMS" inverse="true"><key column="I_ID"></key><many-to-many class="per.xgt.pojo.Category" column="C_ID"></many-to-many></set>

插入

@Testpublic void test1(){Category category1 = new Category();category1.setName("C11");Category category2 = new Category();category2.setName("C22");Item item1 = new Item();item1.setName("I11");Item item2 = new Item();item2.setName("I22");category1.getItems().add(item1);category2.getItems().add(item2);category1.getItems().add(item2);category2.getItems().add(item1);item1.getCategories().add(category1);item1.getCategories().add(category2);item2.getCategories().add(category1);item2.getCategories().add(category2);session.save(category1);session.save(category2);session.save(item1);session.save(item2);}

效果

在这里插入图片描述

九、映射继承关系

Hibernate支持三种继承映射策略

  1. **使用subclass进行映射:**将域模型中的每一个实体对象映射到一个独立的表中,也就是说不用在关系数据模型中可考虑域模型的继承关系和多态。
  2. **使用joined-subclass进行映射:**对于继承关系中的子类使用同一个表,这就需要在数据库坐标中新增加额外的区分子类类型的字段。
  3. **使用union-subclass进行映射:**域模型中的每个类映射到一个表,通过关系数据模型中的外键来描述表之间的继承关系。这也就相当于按照域模型的结构来建立数据库中的表,并通过外键来建立表之间得继承关系。

subclass

  • 采用 subclass 的继承映射可以实现对于继承关系中父类和子类使用同一张表
  • 因为父类和子类的实例全部保存在同一个表中,因此需要在该表内增加一列,使用该列来区分每行记录到低是哪个类的实例----这个列被称为辨别者列(discriminator)
  • 在这种映射策略下,使用 subclass 来映射子类,使用 class 或 subclass 的 discriminator-value 属性指定辨别者列的值
  • **所有子类定义的字段都不能有非空约束。**如果为那些字段添加非空约束,那么父类的实例在那些列其实并没有值,这将引起数据库完整性冲突,导致父类的实例无法保存到数据库中

实体类

/*** @Author: Yvonneflynn's husband* @Email:I don't know* @CreateTime: 2020-09-23 10:49:52* @Descirption:*/
public class Person {private Integer id;private String name;private int age;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
public class Student extends Person{private String school;public String getSchool() {return school;}public void setSchool(String school) {this.school = school;}
}

配置

只需要一个映射文件就可以了

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="per.xgt.pojo"><class name="Person" table="PERSONS" discriminator-value="PERSON"><id name="id" type="java.lang.Integer"><column name="ID" /><generator class="native" /></id><!-- 配置辨别者列 --><discriminator column="TYPE" type="string"></discriminator><property name="name" type="java.lang.String"><column name="NAME" /></property><property name="age" type="int"><column name="AGE" /></property><!-- 映射子类 Student, 使用 subclass 进行映射 --><subclass name="Student" discriminator-value="STUDENT"><property name="school" type="string" column="SCHOOL"></property></subclass></class>
</hibernate-mapping>

插入

@Testpublic void test3(){Person person = new Person();person.setAge(11);person.setName("A");session.save(person);Student student = new Student();student.setAge(2);student.setName("B");student.setSchool("AA");session.save(student);}

在这里插入图片描述

在这里插入图片描述

  1. 对子类对象只需要把记录插入到一张数据表中
  2. 辨别者列有Hibernate自动维护

查询

@Testpublic void test4(){List<Person> persons = session.createQuery("FROM Person").list();System.out.println(persons.size());}

在这里插入图片描述
查询

  1. 查询父类记录只需要查询一张数据表
  2. 对于子类记录,也只需要查询一张数据表

缺点

  1. 使用了辨别者列
  2. 子类独有的字段不能添加非空约束
  3. 若继承层次比较深,则数据表的字段也会比较多

joined-subclass

  • 采用 joined-subclass 元素的继承映射可以实现每个子类一张表
  • 采用这种映射策略时,父类实例保存在父类表中,子类实例由父类表和子类表共同存储。因为子类实例也是一个特殊的父类实例,因此必然也包含了父类实例的属性。于是将子类和父类共有的属性保存在父类表中,子类增加的属性,则保存在子类表中。
  • 在这种映射策略下,无须使用鉴别者列,但需要为每个子类使用 key 元素映射共有主键。
  • 子类增加的属性可以添加非空约束。因为子类的属性和父类的属性没有保存在同一个表中

配置

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="per.xgt.pojo"><class name="Person" table="PERSONS" discriminator-value="PERSON"><id name="id" type="java.lang.Integer"><column name="ID" /><generator class="native" /></id><!-- 配置辨别者列 --><!--<discriminator column="TYPE" type="string"></discriminator>--><property name="name" type="java.lang.String"><column name="NAME" /></property><property name="age" type="int"><column name="AGE" /></property><!-- 映射子类 Student, 使用 subclass 进行映射 --><!--<subclass name="Student" discriminator-value="STUDENT"><property name="school" type="string" column="SCHOOL"></property></subclass>--><joined-subclass name="Student" table="STUDENTS"><key column="STUDENT_ID"></key><property name="school" type="java.lang.String" column="SCHOOL"></property></joined-subclass></class>
</hibernate-mapping>

插入

@Test
public void test3(){Person person = new Person();person.setAge(111);person.setName("A1");session.save(person);Student student = new Student();student.setAge(222);student.setName("B2");student.setSchool("AABB");session.save(student);}

缺点

  1. 对于子类对象至少需要插入到两张数据表中
  2. 查询父类记录,需要一个左外连接查询
  3. 对于子查询,需要一个内连接查询

优点

  1. 不需要辨别者列
  2. 子类独有的字段能添加非空约束
  3. 表结构没有冗余的字段

union-subclass

  1. 采用 union-subclass 元素可以实现将每一个实体对象映射到一个独立的表中
  2. 子类增加的属性可以有非空约束 — 即父类实例的数据保存在父表中,而子类实例的数据保存在子类表中
  3. 子类实例的数据仅保存在子类表中, 而在父类表中没有任何记录
  4. 在这种映射策略下,子类表的字段会比父类表的映射字段要多,因为子类表的字段等于父类表的字段、加子类增加属性的总和
  5. 在这种映射策略下,既不需要使用鉴别者列,也无须使用 key 元素来映射共有主键
  6. 使用 union-subclass 映射策略是不可使用 identity 的主键生成策略, 因为同一类继承层次中所有实体类都需要使用同一个主键种子, 即多个持久化实体对应的记录的主键应该是连续的. 受此影响, 也不该使用 native 主键生成策略, 因为 native 会根据数据库来选择使用 identity 或 sequence

配置

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="per.xgt.pojo"><!--<class name="Person" table="PERSONS" discriminator-value="PERSON">--><class name="Person" table="PERSONS"><id name="id" type="java.lang.Integer"><column name="ID" /><generator class="native" /></id><!-- 配置辨别者列 --><!--<discriminator column="TYPE" type="string"></discriminator>--><property name="name" type="java.lang.String"><column name="NAME" /></property><property name="age" type="int"><column name="AGE" /></property><union-subclass name="Student" table="STUDENS"><property name="school" column="SCHOOL" type="java.lang.String"></property></union-subclass><!-- 映射子类 Student, 使用 subclass 进行映射 --><!--<subclass name="Student" discriminator-value="STUDENT"><property name="school" type="string" column="SCHOOL"></property></subclass>--><!--<joined-subclass name="Student" table="STUDENTS"><key column="STUDENT_ID"></key><property name="school" type="java.lang.String" column="SCHOOL"></property></joined-subclass>--></class>
</hibernate-mapping>

插入

@Test
public void test3(){Person person = new Person();person.setAge(111);person.setName("A1");session.save(person);Student student = new Student();student.setAge(222);student.setName("B2");student.setSchool("AABB");session.save(student);}

MappingException

org.hibernate.MappingException: Cannot use identity column key generation with <union-subclass> mapping for: per.xgt.pojo.Studentat org.hibernate.persister.entity.UnionSubclassEntityPersister.<init>(UnionSubclassEntityPersister.java:95)at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)at java.lang.reflect.Constructor.newInstance(Constructor.java:423)at org.hibernate.persister.internal.PersisterFactoryImpl.create(PersisterFactoryImpl.java:163)at org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(PersisterFactoryImpl.java:135)at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:385)at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1790)at per.xgt.pojo.MyTest.init(MyTest.java:35)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:69)at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:48)at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)at org.junit.runners.ParentRunner.run(ParentRunner.java:292)at org.junit.runner.JUnitCore.run(JUnitCore.java:157)at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)java.lang.NullPointerExceptionat per.xgt.pojo.MyTest.destroy(MyTest.java:43)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:37)at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:69)at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:48)at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)at org.junit.runners.ParentRunner.run(ParentRunner.java:292)at org.junit.runner.JUnitCore.run(JUnitCore.java:157)at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)

在create表的时候,关联表删除出现错误,因为Student表与Person表关联,得先删除子表,再删除父表,所以清空数据库数据,删除表

更新

@Test
public void test5(){String hql = "update Person p set p.age = 20";session.createQuery(hql).executeUpdate();
}

结果

Hibernate: insert intoHT_PERSONSselectperson0_.ID as ID from( selectID,NAME,AGE,null as SCHOOL,0 as clazz_ fromPERSONS unionselectID,NAME,AGE,SCHOOL,1 as clazz_ fromSTUDENS ) person0_
Hibernate: updatePERSONS setAGE=20 where(ID) IN (selectID fromHT_PERSONS)
Hibernate: updatePERSONS setAGE=20 where(ID) IN (selectID fromHT_PERSONS)
Hibernate: updateSTUDENS setAGE=20 where(ID) IN (selectID fromHT_PERSONS)Process finished with exit code 0

优点

  1. 无需使用辨别者列
  2. 子类独有的字段能添加非空约束

缺点

  1. 查询父类,需要把父表和子表汇总到一起再做查询,性能稍差,存在冗余的字段。
  2. 更新父表字段的效率较低

三种继承方式的比较

在这里插入图片描述

十、检索策略

检索数据时的2个问题

  1. **不浪费内存:**当 Hibernate 从数据库中加载 Customer 对象时, 如果同时加载所有关联的 Order 对象, 而程序实际上仅仅需要访问 Customer 对象, 那么这些关联的 Order 对象就白白浪费了许多内存.
  2. **更高的查询效率:**发送尽可能少的 SQL 语句

类级别

  1. 立即检索: 立即加载检索方法指定的对象
  2. 延迟检索: 延迟加载检索方法指定的对象,在使用具体的属性时,再进行加载

通过元素的lazy属性进行设置

  • 如果程序加载一个对象的目的是为了访问它的属性, 可以采取立即检索.
  • 如果程序加载一个持久化对象的目的是仅仅为了获得它的引用, 可以采用延迟检索。注意出现懒加载异常!

在这里插入图片描述

  1. 无论 元素的 lazy 属性是 true 还是 false, Session 的 get() 方法及 Query 的 list() 方法在类级别总是使用立即检索策略
  2. 若 元素的 lazy 属性为 true 或取默认值, Session 的 load() 方法不会执行查询数据表的 SELECT 语句, 仅返回代理类对象的实例, 该代理类实例有如下特征:
    • 由 Hibernate 在运行时采用 CGLIB 工具动态生成
    • Hibernate 创建代理类实例时, 仅初始化其 OID 属性
    • 在应用程序第一次访问代理类实例的非 OID 属性时, Hibernate 会初始化代理类实例

一对多和多对多

Lazy

  • 在映射文件中, 用 元素来配置一对多关联及多对多关联关系. 元素有 lazy 和 fetch 属性
    1. lazy: 主要决定 orders 集合被初始化的时机. 即到底是在加载 Customer 对象时就被初始化, 还是在程序访问 orders 集合时被初始化
    2. fetch: 取值为 “select” 或 “subselect” 时, 决定初始化 orders 的查询语句的形式; 若取值为”join”, 则决定 orders 集合被初始化的时机
    3. 若把 fetch 设置为 “join”, lazy 属性将被忽略
    4. 元素的 batch-size 属性:用来为延迟检索策略或立即检索策略设定批量检索的数量. 批量检索能减少 SELECT 语句的数目, 提高延迟检索或立即检索的运行性能.

不建议lazy设置为false

延迟与增强延迟

  1. 在延迟检索(lazy 属性值为 true) 集合属性时, Hibernate 在以下情况下初始化集合代理类实例
    • 应用程序第一次访问集合属性: iterator(), size(), isEmpty(), contains() 等方法
    • 通过 Hibernate.initialize() 静态方法显式初始化
  2. 增强延迟检索(lazy 属性为 extra): 与 lazy=“true” 类似. 主要区别是增强延迟检索策略能进一步延迟 Customer 对象的 orders 集合代理实例的初始化时机:
    • 当程序第一次访问 orders 属性的 iterator() 方法时, 会导致 orders 集合代理类实例的初始化
    • 当程序第一次访问 order 属性的 size(), contains() 和 isEmpty() 方法时, Hibernate 不会初始化 orders 集合类的实例, 仅通过特定的 select 语句查询必要的信息, 不会检索所有的 Order 对象

Batch-Size

元素有一个 batch-size 属性, 用来为延迟检索策略或立即检索策略设定批量检索的数量. 批量检索能减少 SELECT 语句的数目, 提高延迟检索或立即检索的运行性能.

fetch

  1. fetch: 取值为 “select” 或 “subselect” 时, 决定初始化 orders 的查询语句的形式; 若取值为”join”, 则决定 orders 集合被初始化的时机
  2. 若把 fetch 设置为 “join”, lazy 属性将被忽略
<set> 元素的 fetch 属性: 取值为 “select” 或 “subselect” 时, 决定初始化 orders 的查询语句的形式;  若取值为”join”, 则决定 orders 集合被初始化的时机.默认值为 select:正常的方式来初始化set元素
-------当 fetch 属性为 “subselect” 时
1.假定 Session 缓存中有 n 个 orders 集合代理类实例没有被初始化, Hibernate 能够通过带子查询的 select 语句, 来批量初始化 n 个 orders 集合代理类实例
2.batch-size 属性将被忽略
3.子查询中的 select 语句为查询 CUSTOMERS 表 OID 的 SELECT 语句
-------当 fetch 属性为 “join” 时:
检索 Customer 对象时, 会采用迫切左外连接(通过左外连接加载与检索指定的对象关联的对象)策略来检索所有关联的 Order 对象
lazy 属性将被忽略
Query 的list() 方法会忽略映射文件中配置的迫切左外连接检索策略, 而依旧采用延迟加载策略

多对一和一对一

和 SET一样, many-to-one>元素也有一个 lazy 属性和 fetch 属性
在这里插入图片描述

  1. 若 fetch 属性设为 join, 那么 lazy 属性被忽略
  2. 迫切左外连接检索策略的优点在于比立即检索策略使用的 SELECT 语句更少.
  3. 无代理延迟检索需要增强持久化类的字节码才能实现
Query 的 list 方法会忽略映射文件配置的迫切左外连接检索策略, 而采用延迟检索策略
如果在关联级别使用了延迟加载或立即加载检索策略, 可以设定批量检索的大小, 以帮助提高延迟检索或立即检索的运行性能. 
Hibernate 允许在应用程序中覆盖映射文件中设定的检索策略.

小结

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

十一、检索方式

  1. 导航对象图检索方式: 根据已经加载的对象导航到其他对象
  2. OID 检索方式: 按照对象的 OID 来检索对象
  3. HQL 检索方式: 使用面向对象的 HQL 查询语言
  4. QBC 检索方式: 使用 QBC(Query By Criteria) API 来检索对象. 这种 API 封装了基于字符串形式的查询语句, 提供了更加面向对象的查询接口.
  5. 本地 SQL 检索方式: 使用本地数据库的 SQL 查询语句

HQL

HQL(Hibernate Query Language) 是面向对象的查询语言, 它和 SQL 查询语言有些相似. 在 Hibernate 提供的各种检索方式中, HQL 是使用最广的一种检索方式. 它有如下功能:

  1. 在查询语句中设定各种查询条件
  2. 支持投影查询, 即仅检索出对象的部分属性
  3. 支持分页查询
  4. 支持连接查询
  5. 支持分组查询, 允许使用 HAVING 和 GROUP BY 关键字
  6. 提供内置聚集函数, 如 sum(), min() 和 max()
  7. 支持子查询
  8. 支持动态绑定参数
  9. 能够调用 用户定义的 SQL 函数或标准的 SQL 函数
  10. Qurey 接口支持方法链编程风格, 它的 setXxx() 方法返回自身实例, 而不是 void 类型
  11. HQL 采用 ORDER BY 关键字对查询结果排序

环境搭建

POM依赖

我是用一下Oracle-JDK1.8-ORACLE19C

<dependencies><dependency><groupId>antlr</groupId><artifactId>antlr</artifactId><version>2.7.7</version></dependency><dependency><groupId>dom4j</groupId><artifactId>dom4j</artifactId><version>1.6.1</version></dependency><dependency><groupId>org.hibernate.common</groupId><artifactId>hibernate-commons-annotations</artifactId><version>4.0.2.Final</version></dependency><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-core</artifactId><version>4.2.4.Final</version></dependency><dependency><groupId>org.hibernate.javax.persistence</groupId><artifactId>hibernate-jpa-2.0-api</artifactId><version>1.0.1.Final</version></dependency><dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId><version>3.15.0-GA</version></dependency><dependency><groupId>org.jboss.logging</groupId><artifactId>jboss-logging</artifactId><version>3.1.0.GA</version></dependency><dependency><groupId>org.jboss.spec.javax.transaction</groupId><artifactId>jboss-transaction-api_1.1_spec</artifactId><version>1.0.1.Final</version></dependency><!--MySQL数据库驱动--><!--<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency>--><!--Oracle数据库驱动--><dependency><groupId>com.oracle.database.jdbc</groupId><artifactId>ojdbc8</artifactId><version>19.7.0.0</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.9</version><scope>compile</scope></dependency><dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.2.1</version></dependency><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-c3p0</artifactId><version>4.2.4.Final</version></dependency><dependency><groupId>com.mchange</groupId><artifactId>mchange-commons-java</artifactId><version>0.2.3.4</version></dependency></dependencies><build><resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource></resources></build>

实体类

/*** @Author: Yvonneflynn's husband* @Email:I don't know* @CreateTime: 2020-09-24 15:50:38* @Descirption:*/
public class Department {private String id;private String name;private Set<Employee> emps = new HashSet<>();public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Set<Employee> getEmps() {return emps;}public void setEmps(Set<Employee> emps) {this.emps = emps;}
}
/*** @Author: Yvonneflynn's husband* @Email:I don't know* @CreateTime: 2020-09-24 15:50:48* @Descirption:*/
public class Employee {private Integer id;private String name;private float salary;private String email;private Department dept;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public float getSalary() {return salary;}public void setSalary(float salary) {this.salary = salary;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public Department getDept() {return dept;}public void setDept(Department dept) {this.dept = dept;}
}

映射配置

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="per.xgt.pojo.Department" table="T_DEPARTMENT"><id name="id" type="java.lang.Integer"><column name="ID" /><generator class="native" /></id><property name="name" type="java.lang.String"><column name="NAME" /></property><set name="emps" table="T_EMPLOYEE" inverse="true" lazy="true"><key><column name="DEPT_ID" /></key><one-to-many class="per.xgt.pojo.Employee" /></set></class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="per.xgt.pojo.Employee" table="T_EMPLOYEE"><!--  <cache usage="read-write"/>--><id name="id" type="java.lang.Integer"><column name="ID" /><generator class="native" /></id><property name="name" type="java.lang.String"><column name="NAME" /></property><property name="salary" type="float"><column name="SALARY" /></property><property name="email" type="java.lang.String"><column name="EMAIL" /></property><many-to-one name="dept" class="per.xgt.pojo.Department"><column name="DEPT_ID" /></many-to-one></class><query name="salaryEmps"><![CDATA[FROM Employee e WHERE e.salary > :minSal AND e.salary < :maxSal]]></query></hibernate-mapping>

Hibernate配置文件

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC"-//Hibernate/Hibernate Configuration DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"><hibernate-configuration><session-factory><!-- 配置连接数据库的基本信息 --><property name="connection.username">root</property><property name="connection.password">root</property><property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property><property name="connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property><!-- 配置C3P0数据源 --><!--<property name="c3p0.max_size">10</property><property name="c3p0.min_size">5</property><property name="c3p0.acquire_increment">2</property><property name="c3p0.idle_test_period">2000</property><property name="c3p0.timeout">2000</property><property name="c3p0.max_statements">1</property>--><!-- 配置Hibernate的基本信息 --><!-- 1.hibernate所使用的数据库方言-》哪种数据库 --><property name="dialect">org.hibernate.dialect.Oracle10gDialect</property><!-- 2.执行操作时是否再控制台打印SQL --><property name="show_sql">true</property><!-- 3.是否对SQL进行格式化 --><property name="format_sql">true</property><!-- 4.指定自动生成数据表的策略 --><property name="hibernate.hbm2ddl.auto">update</property><!-- 5.设置Hibernate的事务隔离级别 --><property name="connection.isolation">2</property><!-- 删除对象后,把OID置为NULL --><property name="use_identifier_rollback">true</property><!-- 调用Statment.setFetchSize方法设置JDBC的statment读取数据的时候每次从数据库中取出的记录条数,Oracle驱动默认10,Mysql不支持 --><property name="hibernate.jdbc.fetch_size">100</property><!-- 设定对数据库进行批量删除,批量更新和插入的时候的批次大小,类似于设置缓冲区大小的意思,越大批量操作时想数据库发送的SQL的次数越多,速度就越快 Oracle设置成30比较合适 --><property name="hibernate.jdbc.batch_size">30</property><!-- 6.指定关联的 hbm.xml 文件 --><mapping resource="per/xgt/pojo/Employee.hbm.xml" /><mapping resource="per/xgt/pojo/Department.hbm.xml" /></session-factory></hibernate-configuration>

测试连接并建表

public class MyTest {private SessionFactory sessionFactory;private Session session;private Transaction transaction;@Beforepublic void init() {Configuration configuration = new Configuration().configure();ServiceRegistry serviceRegistry= new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();sessionFactory = configuration.buildSessionFactory(serviceRegistry);session = sessionFactory.openSession();transaction = session.beginTransaction();}@Afterpublic void destroy() {transaction.commit();session.close();sessionFactory.close();}@Testpublic void test(){}}

效果
在这里插入图片描述

起步

占位符绑定参数

@Test
public void testHQL(){//1.创建Query对象String hql = "FROM Employee e where e.salary > ? and e.email like ?";Query query = session.createQuery(hql);//2.绑定参数query.setFloat(0, 800).setString(1, "%V%");//3.执行查询List list = query.list();System.out.println(list.getClass());System.out.println(list);}

结果:我没数据
在这里插入图片描述

参数名绑定参数

@Testpublic void testHQL2(){//1.创建Query对象String hql = "FROM Employee e where e.salary > :sal and e.email like :email";Query query = session.createQuery(hql);//2.绑定参数query.setFloat("sal", 800).setString("email", "%V%");//3.执行查询List list = query.list();System.out.println(list.getClass());System.out.println(list);}

效果
在这里插入图片描述

如果参数是一个实体类,只需要有ID就行,你可以查询出来,或者new出来都可以

与SQL差异

  • HQL 查询语句是面向对象的, Hibernate 负责解析 HQL 查询语句, 然后根据对象-关系映射文件中的映射信息, 把 HQL 查询语句翻译成相应的 SQL 语句. HQL 查询语句中的主体是域模型中的类及类的属性
  • SQL 查询语句是与关系数据库绑定在一起的. SQL 查询语句中的主体是数据库表及表的字段.

绑定参数

Hibernate 的参数绑定机制依赖于 JDBC API 中的PreparedStatement 的预定义 SQL 语句功能.
HQL 的参数绑定由两种形式:

  1. 按参数名字绑定: 在 HQL 查询语句中定义命名参数, 命名参数以 “:” 开头.
  2. 按参数位置绑定: 在 HQL 查询语句中用 “?” 来定义参数位置

相关方法:

  1. setEntity(): 把参数与一个持久化类绑定
  2. setParameter(): 绑定任意类型的参数. 该方法的第三个参数显式指定 Hibernate 映射类型

分页查询

  1. setFirstResult(int firstResult): 设定从哪一个对象开始检索, 参数 firstResult 表示这个对象在查询结果中的索引位置, 索引位置的起始值为 0. 默认情况下, Query 从查询结果中的第一个对象开始检索
  2. setMaxResults(int maxResults): 设定一次最多检索出的对象的数目. 在默认情况下, Query 和 Criteria 接口检索出查询结果中所有的对象
@Testpublic void testPageQuery(){String hql = "FROM Employee";Query query = session.createQuery(hql);int pageNo = 3;int pageSize = 5;List list = query.setFirstResult((pageNo - 1) * pageSize).setMaxResults(pageSize).list();System.out.println(list);}

命名查询

Hibernate 允许在映射文件中定义字符串形式的查询语句. 
<query> 元素用于定义一个 HQL 查询语句, 它和 <class> 元素并列. 
在程序中通过 Session 的 getNamedQuery() 方法获取查询语句对应的 Query 对象. 
<query name="salaryEmps"><![CDATA[FROM Employee e WHERE e.salary > :minSal AND e.salary < :maxSal]]></query>
@Testpublic void testNameQuery(){Query query = session.getNamedQuery("salaryEmps");List list = query.setFloat("minSal", 6).setFloat("maxSal", 10).list();System.out.println(list);}

投影查询

投影查询: 查询结果仅包含实体的部分属性. 通过 SELECT 关键字实现.
Query 的 list() 方法返回的集合中包含的是数组类型的元素, 每个对象数组代表查询结果的一条记录
可以在持久化类中定义一个对象的构造器来包装投影查询返回的记录, 使程序代码能完全运用面向对象的语义来访问查询结果集. 
可以通过 DISTINCT 关键字来保证查询结果不会返回重复元素
@Testpublic void testFieldQuery(){String hql = "select e.email,e.salary from Employee e where e.dept = :dept";Query query = session.createQuery(hql);Department dept = new Department();dept.setId(100);List<Object[]> list = query.setEntity("dept", dept).list();System.out.println(list);}

结果
在这里插入图片描述
操作数组比较麻烦,可以把整个查询结果封装到对象里面,返回List里面,前提是类里面有一个带参构造器
在这里插入图片描述

@Testpublic void testFieldQuery2(){String hql = "select new Employee(e.email,e.salary) from Employee e where e.dept = :dept";Query query = session.createQuery(hql);Department dept = new Department();dept.setId(100);List<Employee> list = query.setEntity("dept", dept).list();}

在这里插入图片描述
注意,构造器的入参和查询出参顺序要一致,不然会报错,没有对应的构造器

报表查询

报表查询用于对数据分组和统计,SQL 一样, HQL 利用 GROUP BY 关键字对数据分组,HAVING 关键字对分组数据设定约束条件.
在 HQL 查询语句中可以调用以下聚集函数
count()
min()
max()
sum()
avg()

用法和SQL里面是一致的,只是函数括号里面是属性名

(迫切)左外连接

LEFT JOIN FETCH 关键字表示迫切左外连接检索策略.
list() 方法返回的集合中存放实体对象的引用, 每个 Department 对象关联的 Employee  集合都被初始化, 存放所有关联的 Employee 的实体对象. 
查询结果中可能会包含重复元素, 可以通过一个 HashSet 来过滤重复元素
左外连接:
LEFT JOIN 关键字表示左外连接查询. 
list() 方法返回的集合中存放的是对象数组类型
根据配置文件来决定 Employee 集合的检索策略. 
如果希望 list() 方法返回的集合中仅包含 Department 对象, 可以在HQL 查询语句中使用 SELECT 关键字

(迫切)内连接

INNER JOIN FETCH 关键字表示迫切内连接, 也可以省略 INNER 关键字
list() 方法返回的集合中存放 Department 对象的引用, 每个 Department 对象的 Employee 集合都被初始化, 存放所有关联的 Employee 对象
内连接:
INNER JOIN 关键字表示内连接, 也可以省略 INNER 关键字
list() 方法的集合中存放的每个元素对应查询结果的一条记录, 每个元素都是对象数组类型
如果希望 list() 方法的返回的集合仅包含 Department  对象, 可以在 HQL 查询语句中使用 SELECT 关键字

注意

如果在 HQL 中没有显式指定检索策略, 将使用映射文件配置的检索策略. 
HQL 会忽略映射文件中设置的迫切左外连接检索策略, 如果希望 HQL 采用迫切左外连接策略, 就必须在 HQL 查询语句中显式的指定它
若在 HQL 代码中显式指定了检索策略, 就会覆盖映射文件中配置的检索策略

QBC&本地SQL

  1. QBC 查询就是通过使用 Hibernate 提供的 Query By Criteria API 来查询对象,这种 API 封装了 SQL 语句的动态拼装,对查询提供了更加面向对象的功能接口
  2. 本地SQL查询来完善HQL不能涵盖所有的查询特性

QBC

@Testpublic void testQBC(){//1.创建一个Criteria对象Criteria criteria = session.createCriteria(Employee.class);//2.添加查询条件:QBC中查询条件使用Criterion来表示//Criterion可以通过Restrictions的静态方法得到criteria.add(Restrictions.eq("email", "22"));criteria.add(Restrictions.gt("salary", 100F));//AND 使用Conjunction表示:本身就是一个Criterion对象Conjunction conjunction = Restrictions.conjunction();conjunction.add(Restrictions.like("name", "xx", MatchMode.ANYWHERE));Department department = new Department();department.setId(1);conjunction.add(Restrictions.eq("dept",department));System.out.println(conjunction);//OR Disjunction disjunction = Restrictions.disjunction();disjunction.add(Restrictions.ge("salary", 200F));disjunction.add(Restrictions.isNotNull("email"));criteria.add(disjunction);criteria.add(conjunction);//3.执行查询Employee employee = (Employee) criteria.uniqueResult();System.out.println(employee);}

打印SQL 效果
在这里插入图片描述
在这里插入图片描述

本地SQL

@Test
public void testSQL(){String sql = "insert into T_DEPARTMENT values(?,?)";SQLQuery sqlQuery = session.createSQLQuery(sql);sqlQuery.setInteger(0, 100).setString(1, "哈哈").executeUpdate();}

十二、二级缓存

Hibernate中提供了两个级别的缓存
第一级别的缓存是 Session 级别的缓存,它是属于事务范围的缓存。这一级别的缓存由 hibernate 管理的
第二级别的缓存是 SessionFactory 级别的缓存,它是属于进程范围的缓存

SessionFactory

SessionFactory 的缓存可以分为两类:
内置缓存: Hibernate 自带的, 不可卸载. 通常在 Hibernate 的初始化阶段, Hibernate 会把映射元数据和预定义的 SQL 语句放到 SessionFactory 的缓存中, 映射元数据是映射文件中数据(.hbm.xml 文件中的数据)的复制. 该内置缓存是只读的. 
外置缓存(二级缓存): 一个可配置的缓存插件. 在默认情况下, SessionFactory 不会启用这个缓存插件. 外置缓存中的数据是数据库数据的复制, 外置缓存的物理介质可以是内存或硬盘

注意点

----适合放入二级缓存中的数据:
1.很少被修改
2.不是很重要的数据, 允许出现偶尔的并发问题
----不适合放入二级缓存中的数据:
1.经常被修改
2.财务数据, 绝对不允许出现并发问题
3.与其他应用程序共享的数据

并发访问策略

两个并发的事务同时访问持久层的缓存的相同数据时, 也有可能出现各类并发问题. 
二级缓存可以设定以下 4 种类型的并发访问策略, 每一种访问策略对应一种事务隔离级别
非严格读写(Nonstrict-read-write): 不保证缓存与数据库中数据的一致性. 提供 Read Uncommited 事务隔离级别, 对于极少被修改, 而且允许脏读的数据, 可以采用这种策略
读写型(Read-write): 提供 Read Commited 数据隔离级别.对于经常读但是很少被修改的数据, 可以采用这种隔离类型, 因为它可以防止脏读
事务型(Transactional): 仅在受管理环境下适用. 它提供了 Repeatable Read 事务隔离级别. 对于经常读但是很少被修改的数据, 可以采用这种隔离类型, 因为它可以防止脏读和不可重复读
只读型(Read-Only):提供 Serializable 数据隔离级别, 对于从来不会被修改的数据, 可以采用这种访问策略

二级缓存实现方式

EHcache

  1. 加入二级缓存的jar和配置文件

    <!-- EHCache --><dependency><groupId>net.sf.ehcache</groupId><artifactId>ehcache-core</artifactId><version>2.4.3</version></dependency><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-ehcache</artifactId><version>4.2.4.Final</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.6.1</version></dependency>
    
    ehcache.xml<ehcache><!-- Sets the path to the directory where cache .data files are created.If the path is a Java System Property it is replaced byits value in the running VM.The following properties are translated:user.home - User's home directoryuser.dir - User's current working directoryjava.io.tmpdir - Default temp file path --><!--  指定一个目录:当 EHCache 把数据写到硬盘上时, 将把数据写到这个目录下.-->     <diskStore path="D:\\CacheFile"/><!--Default Cache configuration. These will applied to caches programmatically created throughthe CacheManager.The following attributes are required for defaultCache:maxInMemory       - Sets the maximum number of objects that will be created in memoryeternal           - Sets whether elements are eternal. If eternal,  timeouts are ignored and the elementis never expired.timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only usedif the element is not eternal. Idle time is now - last accessed timetimeToLiveSeconds - Sets the time to live for an element before it expires. Is only usedif the element is not eternal. TTL is now - creation timeoverflowToDisk    - Sets whether elements can overflow to disk when the in-memory cachehas reached the maxInMemory limit.--><!--  设置缓存的默认数据过期策略 -->    <defaultCachemaxElementsInMemory="10000"eternal="false"timeToIdleSeconds="120"timeToLiveSeconds="120"overflowToDisk="true"/><!--  设定具体的命名缓存的数据过期策略。每个命名缓存代表一个缓存区域缓存区域(region):一个具有名称的缓存块,可以给每一个缓存块设置不同的缓存策略。如果没有设置任何的缓存区域,则所有被缓存的对象,都将使用默认的缓存策略。即:<defaultCache.../>Hibernate 在不同的缓存区域保存不同的类/集合。对于类而言,区域的名称是类名。如:per.xgt.pojo.Customer对于集合而言,区域的名称是类名加属性名。如per.xgt.pojo.Customer.orders--><!--  name: 设置缓存的名字,它的取值为类的全限定名或类的集合的名字 maxElementsInMemory: 设置基于内存的缓存中可存放的对象最大数目 eternal: 设置对象是否为永久的, true表示永不过期,此时将忽略timeToIdleSeconds 和 timeToLiveSeconds属性; 默认值是false timeToIdleSeconds:设置对象空闲最长时间,以秒为单位, 超过这个时间,对象过期。当对象过期时,EHCache会把它从缓存中清除。如果此值为0,表示对象可以无限期地处于空闲状态。 timeToLiveSeconds:设置对象生存最长时间,超过这个时间,对象过期。如果此值为0,表示对象可以无限期地存在于缓存中. 该属性值必须大于或等于 timeToIdleSeconds 属性值 overflowToDisk:设置基于内存的缓存中的对象数目达到上限后,是否把溢出的对象写到基于硬盘的缓存中 --><cache name="per.xgt.pojo.Employee"maxElementsInMemory="1"eternal="false"timeToIdleSeconds="300"timeToLiveSeconds="600"overflowToDisk="true"/><cache name="per.xgt.pojo.Department.emps"maxElementsInMemory="1000"eternal="true"timeToIdleSeconds="0"timeToLiveSeconds="0"overflowToDisk="false"/></ehcache>
    

    默认情况下,设置的缓存对HQL和QBC查询是无效的,但是可以一下方式使其是有效的

    1. 在Hibernate配置文件中开启查询缓存
    2. 调用Query或Criteria的setCatcheable开启缓存

    查询缓存依赖与二级缓存

    Hibernate 配置文件里面添加<!-- 启用二级缓存 --><property name="cache.use_second_level_cache">true</property><!-- 配置使用的二级缓存的产品 --><property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
    <!-- 配置启用查询缓存 --><property name="cache.use_query_cache">true</property><class-cache class="per.xgt.pojo.Employee" usage="read-write" />
    
    实际上也可以在 .hbm.xml文件上配置对哪些类使用二级缓存,以及二级缓存的策略是什么
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j410nWV0-1601201264829)(UsersHPDesktopBjimgs/image-20200925155616740.png)]

集合的二级缓存

<class-cache class="per.xgt.pojo.Department" usage="read-write" /><collection-cache collection="per.xgt.pojo.Department.emps" usage="read-write" />
<set name="emps" table="T_EMPLOYEE" inverse="true" lazy="true"><cache usage="read-write"/><key><column name="DEPT_ID" /></key><one-to-many class="per.xgt.pojo.Employee" /></set>

两种方式都可以,一种是Hibernate配置文件配置一个是在映射文件配置

注意

还需要配置集合中得元素对应的持久化类也使用二级缓存,否则会多出N条SQL

时间戳缓存

时间戳缓存区域存放了对于查询结果相关的表进行插入, 更新或删除操作的时间戳.  Hibernate 通过时间戳缓存区域来判断被缓存的查询结果是否过期, 其运行过程如下:T1 时刻执行查询操作, 把查询结果存放在 QueryCache 区域, 记录该区域的时间戳为 T1T2 时刻对查询结果相关的表进行更新操作, Hibernate 把 T2 时刻存放在 UpdateTimestampCache 区域.T3 时刻执行查询结果前, 先比较 QueryCache 区域的时间戳	和 UpdateTimestampCache 区域的时间戳, 若 T2 >T1, 那么就丢弃原先存放在 QueryCache 区域的查询结果, 重新到数据库中查询数据, 再把结果存放到 QueryCache 区域; 若 T2 < T1, 直接从 QueryCache 中获得查询结果

iterate

Query 接口的 iterator() 方法
同 list() 一样也能执行查询操作
list() 方法执行的 SQL 语句包含实体类对应的数据表的所有字段
Iterator() 方法执行的SQL 语句中仅包含实体类对应的数据表的 ID 字段
当遍历访问结果集时, 该方法先到 Session 缓存及二级缓存中查看是否存在特定 OID 的对象, 如果存在, 就直接返回该对象, 如果不存在该对象就通过相应的 SQL Select 语句到数据库中加载特定的实体对象
大多数情况下, 应考虑使用 list() 方法执行查询操作. iterator() 方法仅在满足以下条件的场合, 可以稍微提高查询性能:
1.要查询的数据表中包含大量字段
2.启用了二级缓存, 且二级缓存中可能已经包含了待查询的对象

十三、管理Session

Hibernate  自身提供了三种管理 Session 对象的方法1.Session 对象的生命周期与本地线程绑定2.Session 对象的生命周期与 JTA 事务绑定3.Hibernate 委托程序管理 Session 对象的生命周期
在 Hibernate 的配置文件中, hibernate.current_session_context_class 属性用于指定 Session 管理方式, 可选值包括1.thread: Session 对象的生命周期与本地线程绑定2.jta*: Session 对象的生命周期与 JTA 事务绑定3.managed: Hibernate 委托程序来管理 Session 对象的生命周期

Session 对象的生命周期与本地线程绑定

如果把 Hibernate 配置文件的 hibernate.current_session_context_class 属性值设为 thread, Hibernate 就会按照与本地线程绑定的方式来管理 Session
Hibernate 按一下规则把 Session 与本地线程绑定当一个线程(threadA)第一次调用 SessionFactory 对象的 getCurrentSession() 方法时, 该方法会创建一个新的 Session(sessionA) 对象, 把该对象与 threadA 绑定, 并将 sessionA 返回 当 threadA 再次调用 SessionFactory 对象的 getCurrentSession() 方法时, 该方法将返回 sessionA 对象当 threadA 提交 sessionA 对象关联的事务时, Hibernate 会自动flush sessionA 对象的缓存, 然后提交事务, 关闭 sessionA 对象. 当 threadA 撤销 sessionA 对象关联的事务时, 也会自动关闭 sessionA 对象若 threadA 再次调用 SessionFactory 对象的 getCurrentSession() 方法时, 该方法会又创建一个新的 Session(sessionB) 对象, 把该对象与 threadA 绑定, 并将 sessionB 返回 

Util类

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;/*** @Author: Yvonneflynn's husband* @Email:I don't know* @CreateTime: 2020-09-27 16:19:17* @Descirption:*/
public class HibernateUtils {private HibernateUtils(){}private static HibernateUtils instance = new HibernateUtils();public static HibernateUtils getInstance(){return instance;}private SessionFactory sessionFactory;public SessionFactory getSessionFactory() {if (sessionFactory == null){Configuration configuration = new Configuration().configure();ServiceRegistry serviceRegistry= new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();sessionFactory = configuration.buildSessionFactory(serviceRegistry);}return sessionFactory;}public Session getSession(){return getSessionFactory().getCurrentSession();}
}

配置管理Session方式

<!-- 配置管理Session的方式 --><property name="current_session_context_class">thread</property>

注意

如Session是由thread管理的,则在提交或回滚事务的时候Session就关闭了

批量操作

涉及到批量操作数据的时候,使用原生的JDBCAPI是最快的,所以推荐使用

@Test
public void testBatch(){session.doWork(new Work() {@Overridepublic void execute(Connection connection) throws SQLException {//通过JDBC原生API进行批量操作,效率最高,速度最快//TODO 批量操作代码}});
}

通过Session批量操作

Session 的 save()update() 方法都会把处理的对象存放在自己的缓存中. 如果通过一个 Session 对象来处理大量持久化对象, 应该及时从缓存中清空已经处理完毕并且不会再访问的对象. 具体的做法是在处理完一个对象或小批量对象后, 立即调用 flush() 方法刷新缓存, 然后在调用 clear() 方法清空缓存
通过 Session 来进行处理操作会受到以下约束
需要在  Hibernate 配置文件中设置 JDBC 单次批量处理的数目, 应保证每次向数据库发送的批量的 SQL 语句数目与 batch_size 属性一致
若对象采用 “identity” 标识符生成器, 则 Hibernate 无法在 JDBC 层进行批量插入操作
进行批量操作时, 建议关闭 Hibernate 的二级缓存
批量更新: 在进行批量更新时, 如果一下子把所有对象都加载到 Session 缓存, 然后再缓存中一一更新, 显然是不可取的
使用可滚动的结果集 org.hibernate.ScrollableResults, 该对象中实际上并不包含任何对象, 只包含用于在线定位记录的游标. 只有当程序遍历访问 ScrollableResults 对象的特定元素时, 它才会到数据库中加载相应的对象. 
org.hibernate.ScrollableResults 对象由 Query 的 scroll 方法返回

注意

批量更新: 在进行批量更新时, 如果一下子把所有对象都加载到 Session 缓存, 然后再缓存中一一更新, 显然是不可取的
使用可滚动的结果集 org.hibernate.ScrollableResults, 该对象中实际上并不包含任何对象, 只包含用于在线定位记录的游标. 只有当程序遍历访问 ScrollableResults 对象的特定元素时, 它才会到数据库中加载相应的对象. 
org.hibernate.ScrollableResults 对象由 Query 的 scroll 方法返回

StateLessSession进行批量操作

从形式上看,StatelessSession与session的用法类似。StatelessSession与session相比,有以下区别:
StatelessSession没有缓存,通过StatelessSession来加载、保存或更新后的对象处于游离状态。
StatelessSession不会与Hibernate的第二级缓存交互。
当调用StatelessSession的save()update()delete()方法时,这些方法会立即执行相应的SQL语句,而不会仅计划执行一条SQL语句
StatelessSession不会进行脏检查,因此修改了Customer对象属性后,还需要调用StatelessSession的update()方法来更新数据库中数据。
StatelessSession不会对关联的对象进行任何级联操作。
通过同一个StatelessSession对象两次加载OID为1的Customer对象,得到的两个对象内存地址不同。
StatelessSession所做的操作可以被Interceptor拦截器捕获到,但是会被Hibernate的事件处理系统忽略掉。

HQL

注意: HQL 只支持 INSERT INTOSELECT 形式的插入语句, 但不支持 INSERT INTOVALUES 形式的插入语句. 所以使用 HQL 不能进行批量插入操作. 
查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 各种STL库中有序数据结构的结构体存储排序?

    对于set&#xff0c;map&#xff0c;还有函数lower_bound(),upper_bound(),还有优先队列都可以使用类似的方法 /* L1-8 公交换乘 (20分) 著名旅游城市B市为了鼓励大家采用公共交通方式出行&#xff0c;推出了一种地铁换乘公交车的优惠方案&#xff1a;在搭乘一次地铁后可以获得…...

    2024/4/24 4:05:02
  2. RCS.DEV | 双节倒计时,旅游业打响“促销战”——5G消息大有可为

    今年&#xff0c;中国、国庆双节并行&#xff0c;随着疫情得到控制&#xff0c;大家出游意愿增强&#xff0c;旅游市场也开始逐步恢复。为了实现绝地反击&#xff0c;旅游业的“促销战”一触即发。为了刺激旅游市场消费复苏&#xff0c;各大旅游企业在营销方面各出奇招&#xf…...

    2024/4/24 8:25:39
  3. centos8安装openoffice和字体

    一、安装openoffice 1、在官网上下载安装包&#xff0c;我下载的是Apache_OpenOffice_4.1.7_Linux_x86-64_install-rpm_zh-CN.tar.gz 2、把安装包上传至Linux根目录下&#xff0c;解压&#xff1a; tar -zxvf Apache_OpenOffice_4.1.7_Linux_x86-64_install-rpm_zh-CN.tar.gz…...

    2024/4/2 4:03:21
  4. 《数据安全能力成熟度模型》实践指南:数据质量管理

    2019年8月30日&#xff0c;《信息安全技术 数据安全能力成熟度模型》&#xff08;GB/T 37988-2019&#xff09;简称DSMM&#xff08;Data Security Maturity Model&#xff09;正式成为国标对外发布&#xff0c;并已于2020年3月起正式实施。 ​ DSMM将数据按照其生命周期分阶…...

    2024/4/22 23:38:24
  5. 游戏服务器架构

    一、游戏服务器特征 游戏服务器&#xff0c;是一个会长期运行程序&#xff0c;并且它还要服务于多个不定时&#xff0c;不定点的网络请求。所以这类服务的特点是要特别关注稳定性和性能。这类程序如果需要多个协作来提高承载能力&#xff0c;则还要关注部署和扩容的便利性&…...

    2024/4/23 3:30:34
  6. JavaScript 中回调地狱的今生前世

    JavaScript 中回调JavaScript 中回调地狱的今生前世异步编程异步实现回调promiseGeneratorawait/asyncJavaScript 中回调地狱的今生前世 你好&#xff01; 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章&#x…...

    2024/4/21 19:23:08
  7. ctfshow月饼杯 web wp

    这次的这个比赛中的web是我和羽师傅还有m3w师傅一起出的&#xff0c;一人一道。 其中最喜欢的是web3 羽师傅出的&#xff0c;真的太有意思啦。感谢羽师傅呢。 还有web1让自己复习序列化知识&#xff0c;感谢m3w师傅呢 web1_此夜圆 <?php error_reporting(0); class a {pub…...

    2024/5/2 8:12:45
  8. 超星尔雅通识智慧树题库答案查询方法教程

    本文转载于&#xff1a;龚—粽–浩【海燕题库】【芦柑题库】 超星尔雅通识智慧树题库答案查询方法如下&#xff1a; 问&#xff1a;以下哪些诗句是杜甫写自己蜀中生活细节的&#xff1f; 答&#xff1a;昼引老妻乘小艇&#xff0c;晴看稚子浴清江。 新添水槛供垂钓&#xff0c…...

    2024/4/27 11:16:24
  9. sqlserver 误删除数据恢复

    原文链接&#xff1a;https://blog.csdn.net/dba_huangzj/article/details/8491327 文章只做留存使用 问题&#xff1a; 经常看到有人误删数据&#xff0c;或者误操作&#xff0c;特别是update和delete的时候没有加where&#xff0c;然后就喊爹喊娘了。人非圣贤孰能无过&…...

    2024/4/20 14:55:26
  10. 一位默默奋斗的专科生自我宣言

    现在大二结束出来实习&#xff0c;作为专科生&#xff0c;我不知道该如何面对未来的发展&#xff0c;大学期间努力学习&#xff0c;虽然保持住着本校的专业第一&#xff0c;但是自己的水平到底如何还是个未知数。如井底之蛙&#xff0c;管中窥豹一般。对于校招&#xff0c;也是…...

    2024/4/24 13:12:24
  11. Tuts4you lena‘s 40 crackme教程[1]

    资源百度云盘链接&#xff1a;https://pan.baidu.com/s/1Pey2Yz2-1c2C_BW2vfy3pg 提取码&#xff1a;c7gm 这是一个名为Lena的破解者写的40个crackme, 我准备把这40个crackme的破解教程以博客形式发出&#xff0c;今天是第一个。首先看一下第一个crackme里面包含的所有文件: 把…...

    2024/4/28 11:37:20
  12. Android音视频开发(五):学习MediaCodec API,完成音频AAC硬编、硬解

    前言 在Android音视频开发中&#xff0c;网上知识点过于零碎&#xff0c;自学起来难度非常大&#xff0c;不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》。本文是Android音视频任务列表的其中一个&#xff0c; 对应的要学习的内容是&#xff1a;学习M…...

    2024/5/2 7:39:42
  13. BHP2.0小课堂丨了解BHP2.0虚拟机(BHP VM)

    ​序&#xff1a;BHP2.0星空测试网(https://bhpnet.io)于2020年8月28日正式启航。BHP2.0是基于Cosmos的Tendermint机制以及Cosmos SDK进行构建的开源区块链公链。与目前的BHP相比&#xff0c;BHP2.0有了很大的改变与不同&#xff0c;为了让大家能够率先了解BHP2.0的方方面面&am…...

    2024/3/15 10:43:31
  14. Spring详细使用总结

    文章目录Spring1 基本使用2 Bean的装配3 注入/DI3.1 基于XML的DI3.2 基于注解的DI4 AOP概要5 AspectJ对AOP的实现5.1 通知类型5.2 切入点表达式5.3 基于注解的实现5.4 基于XML的实现6 Spring实现AOP7 集成MyBatis8 Spring事务8.1 事务管理器接口8.2 Spring 的回滚方式8.3 事务定…...

    2024/4/22 16:58:08
  15. 万万没想到,亚麻也是职场PUA老手....

    疫情下全美都在缩招裁员&#xff0c;而Amazon却逆势增长&#xff0c;随之而来的还有人员规模的疯狂扩张&#xff1a;从9月4日&#xff5e;9月14日&#xff0c;Amzon接连宣布扩招&#xff0c;合计将在全美和加拿大增加10w岗位 然而大举招人的背后往往紧跟着换血式裁员——Amazo…...

    2024/3/16 15:42:59
  16. STM32的RTC晶振不起振的原因及解决方法

    STM32外部晶振不起振 使用STM32cubemx生成工程不起振&#xff0c;烧录标准库的程序后&#xff0c;晶振启震&#xff0c;再烧录STM32cubemx生成工程&#xff0c;晶振正常启震。 STM32外部晶振不起振 https://blog.csdn.net/qq_33559992/article/details/83009134?utm_medium…...

    2024/5/2 7:11:14
  17. ubuntu 安装 pptp 服务

    ubuntu 安装 pptpd 服务 参考链接 安装及配置过程可以参考以下链接&#xff1a; https://gitee.com/null_848_6596/ubuntu_pptpd_vpn https://blog.csdn.net/zwliang98/article/details/108357108 测试验证 /// 在服务端查看pptpd服务 ps -aux | grep pptpwindows10客户端…...

    2024/3/15 9:05:11
  18. vue学习经验总结(双向数据绑定底层原理)

    双向绑定原理 vue的双向绑定是由数据劫持结合发布者&#xff0d;订阅者模式实现的&#xff0c;那么什么是数据劫持&#xff1f; vue是如何进行数据劫持的&#xff1f;说白了就是通过Object.defineProperty()来劫持对象属性的setter和getter操作&#xff0c;在数据变动时做你想…...

    2024/4/15 14:48:08
  19. 看完阿里大佬分享的微服务实战文档,让我茅塞顿开,超赞!

    前言 很多人对于微服务技术也都有着一些疑虑&#xff0c;比如&#xff1a; 微服务这技术虽然面试的时候总有人提&#xff0c;但作为一个开发&#xff0c;是不是和我关系不大&#xff1f;那不都是架构师的事吗&#xff1f;微服务不都是大厂在玩吗&#xff1f;我们这个业务体量…...

    2024/4/23 10:32:06
  20. 前后端分离场景应用接口安全考虑

    前后端分离场景应用接口安全考虑接口安全指标分类指标分析认证和授权防篡改加密传输防重放防模拟必须防模拟怎么办在各个前端上怎么做&#xff08;TODO&#xff09;IOS APP &#xff08;TODO&#xff09;android APP&#xff08;TODO&#xff09;WEB 浏览器&#xff08;TODO&am…...

    2024/4/2 13:38:14

最新文章

  1. Hive 与 MySQL 的数据库限制对比

    数据库的大小 Hive: 由于Hive是建立在Hadoop生态系统之上&#xff0c;理论上其数据库大小仅受Hadoop分布式文件系统&#xff08;HDFS&#xff09;的限制&#xff0c;可以达到PB级别或更高。MySQL: MySQL数据库的大小受到磁盘空间和文件系统的限制。在实践中&#xff0c;单个实例…...

    2024/5/2 8:43:44
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 面试算法-166-排序链表

    题目 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4] 解 class Solution {public ListNode sortList(ListNode head) {if (head null || head.next null…...

    2024/4/30 17:47:41
  4. Ubuntu磁盘扩容

    使用 df -h命令查看系统磁盘控件的使用情况&#xff1a; [samspobosrv:~]$ df -h Filesystem Size Used Avail Use% Mounted on udev 7.8G 0 7.8G 0% /dev tmpfs 1.6G 1.7M 1.…...

    2024/5/1 4:24:23
  5. 汽车疲劳测试试验平台技术要求(北重厂家)

    汽车疲劳测试试验平台技术要求通常包括以下几个方面&#xff1a; 车辆加载能力&#xff1a;测试平台需要具备足够的承载能力&#xff0c;能够同时测试多种车型和不同重量的车辆。 动力系统&#xff1a;测试平台需要具备稳定可靠的动力系统&#xff0c;能够提供足够的力和速度来…...

    2024/5/1 13:14:16
  6. 416. 分割等和子集问题(动态规划)

    题目 题解 class Solution:def canPartition(self, nums: List[int]) -> bool:# badcaseif not nums:return True# 不能被2整除if sum(nums) % 2 ! 0:return False# 状态定义&#xff1a;dp[i][j]表示当背包容量为j&#xff0c;用前i个物品是否正好可以将背包填满&#xff…...

    2024/5/1 10:25:26
  7. 【Java】ExcelWriter自适应宽度工具类(支持中文)

    工具类 import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;/*** Excel工具类** author xiaoming* date 2023/11/17 10:40*/ public class ExcelUti…...

    2024/5/1 13:20:04
  8. Spring cloud负载均衡@LoadBalanced LoadBalancerClient

    LoadBalance vs Ribbon 由于Spring cloud2020之后移除了Ribbon&#xff0c;直接使用Spring Cloud LoadBalancer作为客户端负载均衡组件&#xff0c;我们讨论Spring负载均衡以Spring Cloud2020之后版本为主&#xff0c;学习Spring Cloud LoadBalance&#xff0c;暂不讨论Ribbon…...

    2024/5/1 21:18:12
  9. TSINGSEE青犀AI智能分析+视频监控工业园区周界安全防范方案

    一、背景需求分析 在工业产业园、化工园或生产制造园区中&#xff0c;周界防范意义重大&#xff0c;对园区的安全起到重要的作用。常规的安防方式是采用人员巡查&#xff0c;人力投入成本大而且效率低。周界一旦被破坏或入侵&#xff0c;会影响园区人员和资产安全&#xff0c;…...

    2024/5/1 4:07:45
  10. VB.net WebBrowser网页元素抓取分析方法

    在用WebBrowser编程实现网页操作自动化时&#xff0c;常要分析网页Html&#xff0c;例如网页在加载数据时&#xff0c;常会显示“系统处理中&#xff0c;请稍候..”&#xff0c;我们需要在数据加载完成后才能继续下一步操作&#xff0c;如何抓取这个信息的网页html元素变化&…...

    2024/4/30 23:32:22
  11. 【Objective-C】Objective-C汇总

    方法定义 参考&#xff1a;https://www.yiibai.com/objective_c/objective_c_functions.html Objective-C编程语言中方法定义的一般形式如下 - (return_type) method_name:( argumentType1 )argumentName1 joiningArgument2:( argumentType2 )argumentName2 ... joiningArgu…...

    2024/5/2 6:03:07
  12. 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】

    &#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】&#x1f30f;题目描述&#x1f30f;输入格…...

    2024/5/1 6:35:25
  13. 【ES6.0】- 扩展运算符(...)

    【ES6.0】- 扩展运算符... 文章目录 【ES6.0】- 扩展运算符...一、概述二、拷贝数组对象三、合并操作四、参数传递五、数组去重六、字符串转字符数组七、NodeList转数组八、解构变量九、打印日志十、总结 一、概述 **扩展运算符(...)**允许一个表达式在期望多个参数&#xff0…...

    2024/5/1 11:24:00
  14. 摩根看好的前智能硬件头部品牌双11交易数据极度异常!——是模式创新还是饮鸩止渴?

    文 | 螳螂观察 作者 | 李燃 双11狂欢已落下帷幕&#xff0c;各大品牌纷纷晒出优异的成绩单&#xff0c;摩根士丹利投资的智能硬件头部品牌凯迪仕也不例外。然而有爆料称&#xff0c;在自媒体平台发布霸榜各大榜单喜讯的凯迪仕智能锁&#xff0c;多个平台数据都表现出极度异常…...

    2024/5/2 5:31:39
  15. Go语言常用命令详解(二)

    文章目录 前言常用命令go bug示例参数说明 go doc示例参数说明 go env示例 go fix示例 go fmt示例 go generate示例 总结写在最后 前言 接着上一篇继续介绍Go语言的常用命令 常用命令 以下是一些常用的Go命令&#xff0c;这些命令可以帮助您在Go开发中进行编译、测试、运行和…...

    2024/5/1 20:22:59
  16. 用欧拉路径判断图同构推出reverse合法性:1116T4

    http://cplusoj.com/d/senior/p/SS231116D 假设我们要把 a a a 变成 b b b&#xff0c;我们在 a i a_i ai​ 和 a i 1 a_{i1} ai1​ 之间连边&#xff0c; b b b 同理&#xff0c;则 a a a 能变成 b b b 的充要条件是两图 A , B A,B A,B 同构。 必要性显然&#xff0…...

    2024/4/30 22:14:26
  17. 【NGINX--1】基础知识

    1、在 Debian/Ubuntu 上安装 NGINX 在 Debian 或 Ubuntu 机器上安装 NGINX 开源版。 更新已配置源的软件包信息&#xff0c;并安装一些有助于配置官方 NGINX 软件包仓库的软件包&#xff1a; apt-get update apt install -y curl gnupg2 ca-certificates lsb-release debian-…...

    2024/5/1 6:34:45
  18. Hive默认分割符、存储格式与数据压缩

    目录 1、Hive默认分割符2、Hive存储格式3、Hive数据压缩 1、Hive默认分割符 Hive创建表时指定的行受限&#xff08;ROW FORMAT&#xff09;配置标准HQL为&#xff1a; ... ROW FORMAT DELIMITED FIELDS TERMINATED BY \u0001 COLLECTION ITEMS TERMINATED BY , MAP KEYS TERMI…...

    2024/5/2 0:07:22
  19. 【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法

    文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中&#xff0c;传感器和控制器产生大量周…...

    2024/5/2 8:37:00
  20. --max-old-space-size=8192报错

    vue项目运行时&#xff0c;如果经常运行慢&#xff0c;崩溃停止服务&#xff0c;报如下错误 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 因为在 Node 中&#xff0c;通过JavaScript使用内存时只能使用部分内存&#xff08;64位系统&…...

    2024/5/1 4:45:02
  21. 基于深度学习的恶意软件检测

    恶意软件是指恶意软件犯罪者用来感染个人计算机或整个组织的网络的软件。 它利用目标系统漏洞&#xff0c;例如可以被劫持的合法软件&#xff08;例如浏览器或 Web 应用程序插件&#xff09;中的错误。 恶意软件渗透可能会造成灾难性的后果&#xff0c;包括数据被盗、勒索或网…...

    2024/5/1 8:32:56
  22. JS原型对象prototype

    让我简单的为大家介绍一下原型对象prototype吧&#xff01; 使用原型实现方法共享 1.构造函数通过原型分配的函数是所有对象所 共享的。 2.JavaScript 规定&#xff0c;每一个构造函数都有一个 prototype 属性&#xff0c;指向另一个对象&#xff0c;所以我们也称为原型对象…...

    2024/5/1 14:33:22
  23. C++中只能有一个实例的单例类

    C中只能有一个实例的单例类 前面讨论的 President 类很不错&#xff0c;但存在一个缺陷&#xff1a;无法禁止通过实例化多个对象来创建多名总统&#xff1a; President One, Two, Three; 由于复制构造函数是私有的&#xff0c;其中每个对象都是不可复制的&#xff0c;但您的目…...

    2024/5/1 11:51:23
  24. python django 小程序图书借阅源码

    开发工具&#xff1a; PyCharm&#xff0c;mysql5.7&#xff0c;微信开发者工具 技术说明&#xff1a; python django html 小程序 功能介绍&#xff1a; 用户端&#xff1a; 登录注册&#xff08;含授权登录&#xff09; 首页显示搜索图书&#xff0c;轮播图&#xff0…...

    2024/5/2 7:30:11
  25. 电子学会C/C++编程等级考试2022年03月(一级)真题解析

    C/C++等级考试(1~8级)全部真题・点这里 第1题:双精度浮点数的输入输出 输入一个双精度浮点数,保留8位小数,输出这个浮点数。 时间限制:1000 内存限制:65536输入 只有一行,一个双精度浮点数。输出 一行,保留8位小数的浮点数。样例输入 3.1415926535798932样例输出 3.1…...

    2024/5/1 20:56:20
  26. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  27. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  28. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  29. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  30. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  31. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  32. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  33. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  34. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  35. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  36. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  37. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  38. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  39. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  40. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  41. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  42. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  43. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  44. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  45. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57