做环氧地坪工程网站,百度用户服务中心投诉电话,wordpress 分类信息 主题,六安事件最新情况Hibernate
1、Hibernate框架概述
1.1、什么是Hibernate?
1、Hibernate是一个开放源代码的对象关系映射框架#xff0c;它对JDBC进行了非常轻量级的对象封装#xff0c;它将POJO与数据库表建立映射关系#xff0c;是一个全自动的orm框架#xff0c;hibernate可以自动生成…Hibernate
1、Hibernate框架概述
1.1、什么是Hibernate?
1、Hibernate是一个开放源代码的对象关系映射框架它对JDBC进行了非常轻量级的对象封装它将POJO与数据库表建立映射关系是一个全自动的orm框架hibernate可以自动生成SQL语句自动执行使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
2、Hibernate可以应用在任何使用JDBC的场合既可以在Java的客户端程序使用也可以在Servlet/JSP的Web应用中使用最具革命意义的是Hibernate可以在应用EJB的JaveEE架构中取代CMP完成数据持久化的重任。
3、总结下来
一个框架一个Java领域的持久层框架一个ORM框架
1.2、对象的持久化
1、狭义的理解“持久化”仅仅指把对象永久保存到数据库中
2、广义的理解“持久化包括和数据库相关的各种操作
保存把对象永久保存到数据库中。更新更新数据库中对象(记录)的状态。一删除:从数据库中删除一个对象。查询根据特定的查询条件把符合查询条件的一个或多个对象从数据库加载到内存中。加载根据特定的OID把一个对象从数据库加载到内存中。
3、什么是OID?
为了在系统中能够找到所需对象需要为每一个对象分配一个唯一的标识号。在关系数据库中称之为主键而在对象术语中则叫做对象标识(Object identifier—OID)。
1.3、对ORM的理解
1、ORM(Object/Relation Mapping)对象关系映射。ORM主要解决对象-关系的映射。 2、ORM的思想将关系数据库中表中的记录映射成为对象以对象的形式展现程序员可以把对数据库的操作转化为对对象的操作。
3、ORM采用元数据来描述对象-关系映射细节元数据通常采用XML格式并且存放在专门的对象-关系映射文件中。
1.4、Java里流行的ORM框架
1、Hibernate:
非常优秀、成熟的ORM框架。-完成对象的持久化操作Hibernate 允许开发者采用面向对象的方式来操作关系数据库。消除那些针对特定数据库厂商的SQL代码
2、MyBatis:
相比 Hibernate灵活高运行速度快开发速度慢不支持纯粹的面向对象操作需熟悉sql语句并且熟练使用sql语句优化功能
3、TopLink
4、OJB 等
2、Hibernate第一个入门程序
2.1、环境准备
使用maven新建一个普通Java项目并导入Hibernate需要的依赖(hibernate-core)junit以及MySQL驱动的依赖即可并解决资源导出问题注意这里关于Hibernate只需导入hibernate-core的依赖即可maven会自动帮助我们下载其他需要的依赖。
pom.xml
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersiongroupIdcom.howie/groupIdartifactIdday01/artifactIdversion1.0-SNAPSHOT/version!--相关依赖--dependencies!--mysql--!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.21/version/dependency!--junit--dependencygroupIdjunit/groupIdartifactIdjunit/artifactIdversion4.12/versionscopeprovided/scope/dependency!--hibernate-core--!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core --dependencygroupIdorg.hibernate/groupIdartifactIdhibernate-core/artifactIdversion5.4.10.Final/version/dependency/dependenciesbuildfinalNamessm-build/finalNameresourcesresourcedirectorysrc/main/java/directoryincludesinclude**/*.properties/includeinclude**/*.xml/include/includesfilteringfalse/filtering/resourceresourcedirectorysrc/main/resources/directoryincludesinclude**/*.properties/includeinclude**/*.xml/include/includesfilteringfalse/filtering/resource/resources/build
/project2.2、编写实体类(pojo)与映射文件(xxx.hbm.xml)
1、编写实体类注意这里我们以一个User实体类为例我们这里使用Hibernate暂时不需要创建与实体类对应数据库表只要建好数据库即可。
User.class
/*** description: User实体类* author: laizhenghua* date: 2020/12/4 13:18*/
public class User {private Integer id;private String username;private String password;public User(){} // 注意必须要有空参构造器...// getter and setter// toString
}2、编写映射文件在Hibernate中映射文件的命名规范为类名.hbm.xml。编写完的映射配置文件应与实体类在同一个包下。
User.hbm.xml
?xml version1.0 encodingUTF-8?
!DOCTYPE hibernate-mapping PUBLIC-//Hibernate/Hibernate Mapping DTD 3.0//ENhttp://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd!--Mapper映射文件--
hibernate-mapping!-- 建立类与表的映射 --class namecom.howie.pojo.User tableuser!-- 建立类中的属性与表中的主键相对应 --id nameid typejava.lang.Integercolumn nameid/!-- 主键的生成策略后面会讲native:使用数据库本地生成策略 --generator classnative//id!-- 建立类中的普通属性和表中的字段相对应 --property nameusername typejava.lang.Stringcolumn nameusername//propertyproperty namepassword typejava.lang.Stringcolumn namepassword//property/class
/hibernate-mapping2.3、编写Hibernate的核心配置文件
核心配置文件主要是Hibernate框架所使用的它主要包含了连接数据库的相关信息和Hibernate的相关配置等至于核心配置文件的命名规范为hibernate.cfg.xml为什么要这样命名呢
源码分析
// 当我们通过Configuration类的对象加载核心配置文件时读取的文件名为 hibernate.cfg.xml
public Configuration configure() throws HibernateException {return this.configure(hibernate.cfg.xml);
}hibernate.cfg.xml
?xml version1.0 encodingUTF-8?
!DOCTYPE hibernate-configuration PUBLIC-//Hibernate/Hibernate Configuration DTD 3.0//ENhttp://www.hibernate.org/dtd/hibernate-configuration-3.0.dtdhibernate-configurationsession-factory!-- Database connection settings --property nameconnection.driver_classcom.mysql.cj.jdbc.Driver/propertyproperty nameconnection.urljdbc:mysql://localhost:3306/test?useSSLFALSEamp;serverTimezoneUTCamp;allowPublicKeyRetrievaltrueamp;characterEncodingutf8/propertyproperty nameconnection.usernameroot/propertyproperty nameconnection.password101323/property!-- SQL dialect(hibernate所是的数据库方言) --property namedialectorg.hibernate.dialect.MySQL8Dialect/property!-- 是否在控制台打印SQL语句 --property nameshow_sqltrue/property!-- 是否对SQL进行格式化 --property nameformat_sqltrue/property!-- 指定自动生成数据表的策略 --property namehbm2ddl.autocreate/property!-- 告诉Hibernate的核心配置文件加载哪个映射文件 --mapping resourcecom/howie/pojo/User.hbm.xml//session-factory
/hibernate-configuration2.4、通过Hibernate API 编写入门程序
1、新建一个单元测试类并编写相应测试代码
Test
public void test(){// 1、加载 Hibernate 的核心配置文件/*Configuration类用来管理我们的配置文件的信息的通过它我们可以通过创建一个configuration实例来管理相应的配置文档,但是通常我们只创建一个configuration实例。*/Configuration configuration new Configuration().configure();//如果在Hibernate的核心配置文件没有设置加载哪个映射文件则可手动加载映射文件//configuration.addResource(com/howie/pojo/User.hbm.xml);// 2、创建SessionFactory对象类似JDBC中的链接池SessionFactory sessionFactory configuration.buildSessionFactory();// 3. 通过SessionFactory获取到Session对象类似于JDBC中的ConnectionSession session sessionFactory.openSession();// 4、手动开启事务最好是手动开启事务Transaction transaction session.beginTransaction();// 5、执行保存操作User user new User();user.setUsername(alex);user.setPassword(123);session.save(user);// 6、提交事务transaction.commit();// 7、关闭 Sessionsession.close();// 8、关闭 SessionFactorysessionFactory.close();}2、执行查看结果 ok数据库里已经添加成功到这里我们已正式入门Hibernate !
2.5、第一个入门程序总结
1、Hibernate工作原理是Configuration读取Hibernate的配置文件和映射文bai件中的信息即加载配置文件和映射文件并通过Hibernate配置文件生成一个多线程的SessionFactory对象。
2、然后多线程SessionFactory对象生成一个线程Session 对象Session对象生成Query对象或者Transaction对象可通过Session对象的get()load()save()update()delete()和saveOrUpdate( )等方法对PO进行加载、保存、更新、删除等操作。
3、在查询的情况下可通过Session 对象生成一个Query对象然后利用Query对象执行查询操作如果没有异常Transaction对象将提交这些操作结果到数据库中。
4、关于Session接口
Session是应用程序与数据库之间交互操作的一个单线程对象是Hibernate运作的中心所有持久化对象必须在session的管理下才可以进行持久化操作。此对象的生命周期很短。Session对象有一个一级缓存显式执行flush之前所有的持久层操作的数据都缓存在session对象处。相当于JDBC中的Connection。
5、Transaction(事务)
代表一次原子操作它具有数据库事务的概念。所有持久层都应该在事务管理下进行即使是只读操作。
常用方法commit() 提交相关联的session实例rollback() 撤销事务操作wasCommitted() 检查事务是否提交
6、Hibernate配置文件的两个配置项
hbm2ddl.auto该属性可帮助程序员实现正向工程即由java代码生成数据库脚本进而生成具体的表结构。取值create、update、create-drop、validate等
create会根据xx.hbm.xml文件来生成数据表但是每次运行都会删除上一次的表重新生成表哪怕二次没有任何改变create-drop会根据xx.hbm.xml文件生成表但是SessionFactory一关闭表就自动删除update最常用的属性值也会根据xx.hbm.xml文件生成表但若xx.hbm.xml文件和数据库中对应的数据表的表结构不同Hiberante将更新数据表结构但不会删除已有的行和列validate 会和数据库中的表进行比较若xx.hbm.xml文件中的列在数据表中不存在则抛出异常
format_sql是否将SQL转化为格式良好的SQL取值true | false
3、Hibernate里的Session接口
3.1、搭建实验环境
1、新建一个数据库并添加两条数据
USE test;
# 建表
CREATE TABLE user(id int(20) PRIMARY KEY NOT NULL,username varchar(30) DEFAULT NULL,password varchar(30) DEFAULT NULL
)ENGINEINNODB DEFAULT CHARSETutf8;# 添加两条数据
INSERT INTO test.USER(id,username,password) VALUE(1,alex,123);
INSERT INTO test.USER(id,username,password) VALUE(2,howie,123);2、使用maven新建一个Java项目并导入相关依赖解决资源导出等问题。
添加依赖
!--mysql--
!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --
dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.21/version
/dependency
!--junit--
dependencygroupIdjunit/groupIdartifactIdjunit/artifactIdversion4.12/versionscopeprovided/scope
/dependency
!--hibernate-core--
!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core --
dependencygroupIdorg.hibernate/groupIdartifactIdhibernate-core/artifactIdversion5.4.10.Final/version
/dependency解决资源导出问题 buildfinalNamessm-build/finalNameresourcesresourcedirectorysrc/main/java/directoryincludesinclude**/*.properties/includeinclude**/*.xml/include/includesfilteringfalse/filtering/resourceresourcedirectorysrc/main/resources/directoryincludesinclude**/*.properties/includeinclude**/*.xml/include/includesfilteringfalse/filtering/resource/resources
/build3、编写实体类与实体类对应的映射文件
User.java
/*** description: User实体类* author: laizhenghua* date: 2020/12/4 13:18*/
public class User {private Integer id;private String username;private String password;public User(){} // 提供一个无参的构造器使用Hibernate可以使用newlnstance()来实例化实体类...// getter and setter// toString 方便测试
}为了包结构简洁我们把映射文件放在src/main/resources/mapper/User.hbm.xml
User.hbm.xml
?xml version1.0 encodingUTF-8?
!DOCTYPE hibernate-mapping PUBLIC-//Hibernate/Hibernate Mapping DTD 3.0//ENhttp://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd!--Mapper映射文件--
hibernate-mapping!-- 建立类与表的映射 --class namecom.howie.pojo.User tableuser!-- 建立类中的属性与表中的主键相对应 --id nameid typejava.lang.Integercolumn nameid/!-- 主键的生成策略后面会讲native:使用数据库本地生成策略 --generator classnative//id!-- 建立类中的普通属性和表中的字段相对应 --property nameusername typejava.lang.Stringcolumn nameusername//propertyproperty namepassword typejava.lang.Stringcolumn namepassword//property/class
/hibernate-mapping4、编写Hibernate的核心配置文件
hibernate.cfg.xml
?xml version1.0 encodingUTF-8?
!DOCTYPE hibernate-configuration PUBLIC-//Hibernate/Hibernate Configuration DTD 3.0//ENhttp://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd
!-- 核心配置文件 --
hibernate-configurationsession-factory!-- Database connection settings --property nameconnection.driver_classcom.mysql.cj.jdbc.Driver/propertyproperty nameconnection.urljdbc:mysql://localhost:3306/test?useSSLFALSEamp;serverTimezoneUTCamp;allowPublicKeyRetrievaltrueamp;characterEncodingutf8/propertyproperty nameconnection.usernameroot/propertyproperty nameconnection.password101323/property!-- SQL dialect(hibernate所是的数据库方言) --property namedialectorg.hibernate.dialect.MySQL8Dialect/property!-- 是否在控制台打印SQL语句 --property nameshow_sqltrue/property!-- 是否对SQL进行格式化 --property nameformat_sqltrue/property!-- 指定自动生成数据表的策略update最常用 --property namehbm2ddl.autoupdate/property!-- 告诉Hibernate的核心配置文件加载哪个映射文件 --mapping resourcemapper/User.hbm.xml//session-factory
/hibernate-configuration5、为了方便测试我们把加载配置文件获取Session对象、Transaction对象等的代码封装为一个工具类。
HibernateUtil.java
package com.howie.utils;import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;/*** description: Hibernate的工具类用于获取Session对象与Transaction对象* author: laizhenghua* date: 2020/12/4 17:08*/
public class HibernateUtil {/* 实际开发中为了代码安全Session对象一般不能作为成员变量 */private static SessionFactory sessionFactory null;private static Session session null;/*** description: 用于获取Session对象* author: laizhenghua* date: 2020/12/4 17:13* param: null* return: org.hibernate.Session*/public static Session getSession(){// 1、加载核心配置文件Configuration configuration new Configuration().configure();// 2、创建SessionFactory对象类似JDBC中的链接池sessionFactory configuration.buildSessionFactory();// 3、返回Session对象session sessionFactory.openSession();return session;}/*** description: 获取Transaction对象(操作事务的对象)* author: laizhenghua* date: 2020/12/4 17:26* param: session* return: org.hibernate.Transaction*/public static Transaction getTransaction(Session session){return session.beginTransaction();}/*** description: 关闭Session对象* author: laizhenghua* date: 2020/12/4 17:28* param:* return: void*/public static void closeSession(){if(session ! null){session.close();}if(sessionFactory ! null){sessionFactory.close();}}
}6、新建一个测试类HibernateTest.java进行添加测试
Test
public void test(){// 1、获取Session对象Session session HibernateUtil.getSession();// 2、获取Transaction对象Transaction transaction HibernateUtil.getTransaction(session);// 3、添加一条数据User user new User();user.setId(3);user.setUsername(无情哈拉少);user.setPassword(123);String sql insert into test.user(id,username,password) value(?,?,?);session.createSQLQuery(sql).setParameter(1,user.getId()).setParameter(2,user.getUsername()).setParameter(3,user.getPassword()).executeUpdate();// 4、提交事务transaction.commit();// 5、关闭资源HibernateUtil.closeSession();
}查看结果 OK我们的环境已搭建完毕
3.2、Session接口概述
1、Session接口是Hibernate向应用程序提供的操纵数据库的最主要的接口它提供了基本的保存更新删除和加载Java对象的方法。
2、Session具有一个缓存(自带一级缓存默认开启)位于缓存中的对象称为持久化对象它和数据库中的相关记录对应。Session能够在某些时间点按照缓存中对象的变化来执行相关的SQL语句来同步更新数据库这一过程被称为刷新缓存(flush)。
3、站在持久化的角度Hibernate 把对象分为4种状态持久化状态临时状态游离状态删除状态。Session的特定方法能使对象从一个状态转换到另一个状态。
3.3、Session缓存
1、在 Session 接口的实现中包含一系列的Java集合这些Java集合构成了Session 缓存只要Session 实例没有结束生命周期且没有清理缓存则存放在它缓存中的对象也不会结束生命周期。
2、Session缓存可减少Hibernate应用程序访问数据库的频率。
3、一级缓存也叫本地缓存(Session级别的缓存)与数据库同一次会话期间查询到的数据会放在本地缓存中以后如果需要获取相同的数据直接从缓存中拿没必须再去查询数据库
/* 测试一级缓存 */
Test
public void test1(){// 1、获取Session对象Session session HibernateUtil.getSession();// 2、获取数据User user1 session.get(User.class, 2);System.out.println(user1);// 这里 user2 不在从从数据里读取的而是从缓存中读取SQL也只执行了一次User user2 session.get(User.class,2);System.out.println(user2);System.out.println(user1 user2);// 3、关闭资源HibernateUtil.closeSession();
}查看输出的日志 小结一级缓存默认是开启的只在一次Session中有效也就是拿到连接到关闭连接这个区间段
4、缓存失效情况 查询不同的东西 增删改操作可能会改变原来的数据所以必定会刷新缓存 查询不同的Mapper.xml 手动清理缓存!
Test
public void test1(){// 1、获取Session对象Session session HibernateUtil.getSession();// 2、获取数据User user1 session.get(User.class, 2);System.out.println(user1);session.clear(); // 手动清理缓存/* 此时SQL语句会执行两次 */User user2 session.get(User.class,2);System.out.println(user2);System.out.println(user1 user2); // false// 3、关闭资源HibernateUtil.closeSession();
}3.4、flush缓存
1、操作Session中的缓存 2、flushSession按照缓存中对象的属性变化来同步更新数据库。默认情况下Session在以下时间点刷新缓存:
显式调用Session的flush()方法当应用程序调用Transaction的commit()方法的时该方法先flush然后在向数据库提交事务当应用程序执行一些查询(HQLCriteria)操作时如果缓存中持久化对象的属性已经发生了变化会先flush缓存。以保证查询结果能够反映持久化对象的最新状态。
flush缓存的例外情况
如果对象使用native生成器生成OID那么当调用Session的save()方法保存对象时会立即执行向数据库插入该实体的insert语句。
3、commit()和flush()方法的区别flush 执行一系列sql语句但不提交事务commit方法先调用flush()方法然后提交事务。意味着提交事务意味着对数据库操作永久保存下来。
/**
flush: 使数据表中的记录和 Session 缓存中的对象的状态保持一致. 为了保持一致, 则可能会发送对应的 SQL 语句.
1. 在 Transaction 的 commit() 方法中: 先调用 session 的 flush 方法, 再提交事务
2. flush() 方法会可能会发送 SQL 语句, 但不会提交事务.
3. 注意: 在未提交事务或显式的调用 session.flush() 方法之前, 也有可能会进行 flush() 操作.1) 执行 HQL 或 QBC 查询, 会先进行 flush() 操作, 以得到数据表的最新的记录2) 若记录的 ID 是由底层数据库使用自增的方式生成的, 则在调用 save() 方法时, 就会立即发送 INSERT 语句. 因为 save 方法后, 必须保证对象的 ID 是存在的!*/
Test
public void testSessionFlush2(){News news new News(Java, SUN, new Date());session.save(news);
}Test
public void testSessionFlush(){News news (News) session.get(News.class, 1);news.setAuthor(Oracle);// session.flush();
// System.out.println(flush);News news2 (News) session.createCriteria(News.class).uniqueResult();System.out.println(news2);
}4、reresh()方法
Test
public void rereshTest(){/*User user new User();user.setId(4);user.setUsername(关羽);user.setPassword(123);*/Session session HibernateUtil.getSession();User user session.get(User.class, 3);System.out.println(user);session.refresh(user);/*refresh(): 会强制发送 SELECT 语句, 以使 Session 缓存中对象的状态和数据表中对应的记录保持一致!*/System.out.println(user);HibernateUtil.closeSession();
}3.5、Session接口的关系图 3.6、Hibernate中设置隔离级别
1、MySQL支持4中事务隔离级别MySQL默认的事务隔离级别为REPEATABLE READ
2、REPEATABLE READ(可重复读)确保事务可以多次从一个字段中读取相同的值。在这个事务持续期间禁止其他事物对这个字段进行更新。可以避免脏读和不可重复读但幻读的问题仍然存在。
3、回顾MySQL中设置隔离级别
# 1、每启动一个mysql程序就会获得一个单独的数据库连接。
# 2、每个数据库连接都有一个全局变量txisolation表示当前的事务隔离级别。
# 3、MySQL默认的隔离级别为RepeatableRead# 查看当前的隔离级别:
SELECT tx...isalation;# 设置当前mySQL连接的隔离级别:
set transaction isolation level read committed;# 设置数据库系统的全局的隔离级别:
set global transaction isolation level read committed;4、在Hibernate中设置隔离级别
JDBC数据库连接使用数据库系统默认的隔离级别。在Hibernate的配置文件中可以显式的设置隔离级别。每一个隔离级别都对应一个整数
READ UNCOMMITED 1
READ COMMITED 2
REPEATABLE READ 3
SERIALIZEABLE 4而我们使用Hibernate设置数据库隔离级别时只需在配置文件中添加一个property标签即可。
!--设置Hibernate的事务隔离级别--
property nameconnection.isolation2/propertyhibernate.connection.isolation 属性来设置事务的隔离级别。
4、持久化对象的状态
4.1、持久化对象的4种状态
1、站在持久化的角度Hibernate 把对象分为4种状态
持久化状态临时状态游离状态删除状态
Session的特定方法能使对象从一个状态转换到另一个状态。
2、临时对象(Transient)
在使用代理主键的情况下OID通常为null。不处于 Session 的缓存中。在数据库中没有对应的记录。
3、持久化对象(也叫托管Persist)
OID不为null。位于Session缓存中。若在数据库中已经有和其对应的记录持久化对象和数据库中的相关记录对应。Session在 flush缓存时会根据持久化对象的属性变化来同步更新数据库。在同一个Session实例的缓存中数据库表中的每条记录只对应唯一的持久化对象。
4、删除对象(Removed)
在数据库中没有其OID对应的记录不在属于 Session 缓存中一般情况下应用程序不该在使用被删除的对象。
5、游离对象(也叫脱管) (Detached)
OID不为null。不再处于Session缓存中。一般情况需下游离对象是由持久化对象转变过来的因此在数据库中可能还存在与它对应的记录。也可理解为请假虽然暂时脱离了公司的管理但是你还是公司的人。
4.2、持久化对象状态转换图 4.3、Session的save()方法
首先我们知道 Session里的save()方法可以把持久化对象从临时状态变为持久化状态并把对象保存到数据库里。
Test
public void testSave(){/*save()方法1、使临时对象转变为持久化对象2、在flush缓存时会发送一条insert语句*/Session session HibernateUtil.getSession();User user new User();user.setUsername(无情哈拉少);user.setPassword(123);System.out.println(临时状态 user);session.save(user); // 保存注意我们在数据库里设置了 id 字段自增System.out.println(持久化状态 user);HibernateUtil.closeSession();
}我们再来看输出的日志
INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
临时状态User{idnull, username无情哈拉少, password123}
Hibernate: insert intouser(username, password) values(?, ?)
持久化状态User{id6, username无情哈拉少, password123}
十二月 09, 2020 2:13:23 下午 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PoolState stop我们发现在Hibernate5版本里save()方法自动提交了事务并且发送了一条insert语句把数据保存到数据里把对象从临时对象转变为持久化状态(再次打印user时id已不为null)。
4.4、Session的persist()方法
persist()与save()方法类似也会执行INSERT语句也是把持久化对象从临时状态转变为持久化状态但是也有一些区别在Hibernate5里persist()方法不会自动提交事务 在调用 persist 方法之前, 若对象已经有 id 了, 则不会执行 INSERT, 而抛出异常
Test
public void persistTest(){Session session HibernateUtil.getSession();Transaction transaction HibernateUtil.getTransaction(session); // 获取操作事务的对象User user new User();user.setUsername(persist);user.setPassword(123);System.out.println(临时状态 user);session.persist(user); // 保存对象System.out.println(持久化状态 user);transaction.commit(); // 提交事务HibernateUtil.closeSession();
}/* 输出的部分日志
INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
临时状态User{idnull, usernamepersist, password123}
Hibernate: insert intouser(username, password) values(?, ?)
持久化状态User{id7, usernamepersist, password123}
十二月 09, 2020 2:35:13 下午 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PoolState stop
*/4.5、Session的get()load()方法
Session中load()方法和get()方法的功能类似也是查询出指定的一条记录都会发送查询语句但是get()和load()也有一定的区别
Test
public void loadTest(){Session session HibernateUtil.getSession();User user1 session.load(User.class, 1); // load延迟加载节省内存(使用就加载不使用则不加载)System.out.println(user1.getClass().getName()); // 代理对象com.howie.pojo.User$HibernateProxy$3aJET1Gxsession.close();// 若打印对象前把Session关闭会抛出一个懒加载异常System.out.println(user1);/*User user2 session.get(User.class, 1);System.out.println(user1 user2); // true*//*get() vs load()1、执行get方法会立即加载对象而执行load方法若不使用对象的属性则不会立即执行查询操作而返回一个代理对象。2、get是立即检索而load是延迟检索3、若数据库表中没有对应的记录且 Session 也没有被关闭同时需要使用对象时。get在返回null。load抛出异常load方法若不使用该对象也不会抛出异常。4、load方法可能会抛出懒加载异常org.hibernate.LazyInitializationException。在需要初始化代理对象之前已经关闭Session此时就会抛出懒加载异常*/
}
Test
public void testGet(){Session session HibernateUtil.getSession();User user session.get(User.class, 1);session.close();// 即使Session已经关闭了但是执行get方法时对象已经加载了所以可以打印出对象System.out.println(user);
}4.6、Session的update()方法
1、Session的update()方法使一个游离对象转变为持久化对象并且计划执行一条update语句。
2、若希望 Session仅当修改了User对象的属性时才执行update()语句可以把映射文件中元素的select-before-update设为true该属性的默认值为false。
3、update()方法关联一个游离对象时如果在Session的缓存中已经存在相同OID的持久化对象会抛出异常。
4、当update()方法关联一个游离对象时如果在数据库中不存在相应的记录也会抛出异常。
/*
update()方法
1、前面我们知道若持久化对象与查询出来的数据表的记录不一样提交事务后Hibernate会自动发送一条更新语句更新最新的记录
2、若更新一个持久化对象不需要显示调用 update方法因为提交事务时会先执行 Session 的flush() 方法。
3、更新一个游离对象需要显示调用 Session 的 update()方法可以把一个游离对象变为持久化对象注意点
1、无论要更新的游离对象和数据表的记录是否一致都会发送update语句如何才能让 update 方法不盲目的发送update语句在 xxx.hbm.xml 映射文件中的 class 节点设置一个 select-before-updatetrue (默认为false通常不用设置此属性)
2、若数据表中没有对应的记录但还调用了 update 方法会抛出异常。
3、update()方法关联一个游离对象时如果在Session的缓存中已经存在相同OID的持久化对象会抛出异常。Session缓存中不能有两个 OID 相同的对象
*/
Test
public void updateTest(){Session session HibernateUtil.getSession();Transaction transaction HibernateUtil.getTransaction(session);User user session.get(User.class, 1);transaction.commit();HibernateUtil.closeSession();session HibernateUtil.getSession();transaction HibernateUtil.getTransaction(session);user.setUsername(alex); // 此时user对象就变为游离状态需要显示调用 update 方法session.update(user);transaction.commit();System.out.println(user);
}4.7、Session的saveOrUpate()方法
1、Session的saveQrUpdate()方法同时包含了save()与update()方法的功能。 2、判断对象为临时对象的标准
Java对象的 OID 为 null映射文件中为设置了unsaved-value属性并且Java对象的OID取值与这个unsaved-value属性值匹配
/*
注意点
1、若 OID 不为null但数据表中还没有和其对应的记录会抛出异常
2、了解0ID 值等于id的unsaved-value属性值的对象也被认为是一个游离对象*/
Test
public void saveOrUpdateTest(){User user new User();user.setUsername(哈士奇);user.setPassword(123);Session session HibernateUtil.getSession();Transaction transaction HibernateUtil.getTransaction(session);session.saveOrUpdate(user); // 执行save()方法发送 insert 语句// user.setId(1); 执行update()方法发送update语句transaction.commit();HibernateUtil.closeSession();
}4.8、Session的delete()方法
1、Session的delete()方法既可以删除一个游离对象也可以删除一个持久化对象。
2、Session的delete()方法处理过程
计划执行一条delete语句。把对象从Session缓存中删除该对象进入删除状态。
/*
delete()方法
1、执行删除操作只要OID和数据表中有一条记录对应就会准备执行delete操作
2、若OID咋数据表中没有对应的记录则抛出异常*/
Test
public void deleteTest(){User user new User();user.setId(8);Session session HibernateUtil.getSession();Transaction transaction HibernateUtil.getTransaction(session);session.delete(user); // 删除游离对象transaction.commit();HibernateUtil.closeSession();
}/* 输出的日志
INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
Hibernate: delete fromuser whereid?
十二月 11, 2020 11:52:20 上午 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PoolState stop
*/3、Hibernate 的cfg.xml配置文件中有一个hibernate.use_identifier_rollback属性其默认值为false若把它设为true将改变delete()方法的运行行为delete()方法会把持久化对象或游离对象的OID设置为null使它们变为临时对象。
修改hibernate.cfg.xml配置文件
!--删除对象后使其OID置为null--
property namehibernate.use_identifier_rollbacktrue/property测试
Test
public void deleteTest(){Session session HibernateUtil.getSession();Transaction transaction HibernateUtil.getTransaction(session);User user session.get(User.class, 6);session.delete(user);System.out.println(user);transaction.commit();HibernateUtil.closeSession();
}
/* 输出的日志
INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
Hibernate: selectuser0_.id as id1_0_0_,user0_.username as username2_0_0_,user0_.password as password3_0_0_ fromuser user0_ whereuser0_.id?
User{idnull, username无情哈拉少, password123}
Hibernate: delete fromuser whereid?
十二月 11, 2020 11:59:07 上午 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PoolState stop
*/4.9、Session的evict()方法
1、Session中的evict()方法从session缓存中把指定的持久化对象移除。
2、测试
Test
public void evictTest(){Session session HibernateUtil.getSession();Transaction transaction HibernateUtil.getTransaction(session);User user session.get(User.class, 2);user.setUsername(哈士奇);session.evict(user); // 从session缓存中移除user对象数据表中并没有得到更新transaction.commit();HibernateUtil.closeSession();
}5、Hibernate中的存储过程
5.1、通过Hibernate调用存储过程
1、Hibernate并没有提供操作存储过程的API在Hibernate里我们只能操作原生jdbc的Connection来操作存储过程等。
2、Session的doWork(Work)方法用于执行Work 对象指定的操作即调用Work 对象的execute()方法。Session会把当前使用的数据库连接传递给execute()方法。
Test
public void doWorkTest(){Session session HibernateUtil.getSession();session.doWork(new Work() {Overridepublic void execute(Connection connection) throws SQLException {System.out.println(connection); // com.mysql.cj.jdbc.ConnectionImpl5327a06e// 在此我们可以操作原生 jdbc的Connection从而操作存储过程}});
}5.2、Hibernate与触发器协同工作
1、Hibernate 与数据库中的触发器协同工作时会造成两类问题
触发器使Session的缓存中的持久化对象与数据库中对应的数据不一致触发 器运行在数据库中它执行的操作对Session是透明的。Session 的update()方法盲目地激发触发器无论游离对象的属性是否发生变 化都会执行update语句而update语句会激发数据库中相应的触发器。
2、解决方案
在执行完Session的相关操作后立即调用Session 的flush()和refresh()方法迫使Session的缓存与数据库同步(refresh()方法重新从数据库中加载对象)在映射文件的的元素中设置select-before-update属性当Session的update() 或saveOrUpdate()方法更新一个游离对象时会先执行Select语句获得当前游离对象在数据库中的最新数据只有在不一致的情况下才会执行update语句。
6、Hibernate配置文件详解
1、Hibernate配置文件主要用于配置数据库连接和Hibernate运行时所需的各种属性。每个Hibernate配置文件对应一个Configuration对象。
2、Hibernate配置文件可以有两种格式
hibernate.propertieshibernate.cfg.xml 推荐使用
3、下面就介绍hibernate.cfg.xml常用的属性。
6.1、JDBC连接属性
1、常用属性名
connection.url数据库URL
connection.username数据库用户名
connection.password数据库用户密码
connection.driver_class数据库JDBC驱动
dialect配置数据库的方言,根据底层的数据库不同产生不同的sgl语句Hibernate 会针对数据库的特性在访问时进行优化。
2、配置实例
!-- Database connection settings --
property nameconnection.driver_classcom.mysql.cj.jdbc.Driver/property
property nameconnection.urljdbc:mysql://localhost:3306/test?useSSLFALSEamp;serverTimezoneUTCamp;allowPublicKeyRetrievaltrueamp;characterEncodingutf8/property
property nameconnection.usernameroot/property
property nameconnection.passwordxxx/property!-- SQL dialect(hibernate所是的数据库方言) --
property namedialectorg.hibernate.dialect.MySQL8Dialect/property
!-- 是否在控制台打印SQL语句 --6.2、切换数据库连接池
1、Hibernate自带的连接池算法相当不成熟.。它只是为了让你快些上手并不适合用于产品系统或性能测试中。 出于最佳性能和稳定性考虑你应该使用第三方的连接池。只需要用特定连接池的设置替hibernate.connection.pool_size即可。这将关闭Hibernate自带的连接池。例如我们可以使用C3P0/Druid等这里我们以Druid为例
2、关于更多数据库连接池的学习可在网上自行学习
3、使用步骤
引入maven依赖
!-- https://mvnrepository.com/artifact/com.alibaba/druid --
dependencygroupIdcom.alibaba/groupIdartifactIddruid/artifactIdversion1.1.21/version
/dependency加入配置(这里只列出常用配置)
?xml version1.0 encodingUTF-8?
!DOCTYPE hibernate-configuration PUBLIC-//Hibernate/Hibernate Configuration DTD 3.0//ENhttp://www.hibernate.org/dtd/hibernate-configuration-3.0.dtdhibernate-configurationsession-factory!-- SQL dialect(hibernate所是的数据库方言) --property namedialectorg.hibernate.dialect.MySQL8Dialect/property!-- 是否在控制台打印SQL语句 --property nameshow_sqltrue/property!-- 是否对SQL进行格式化 --property nameformat_sqltrue/property!-- 指定自动生成数据表的策略 --property namehbm2ddl.autoupdate/property!--删除对象后使其OID置为null--property namehibernate.use_identifier_rollbacktrue/property!-- 告诉Hibernate的核心配置文件加载哪个映射文件 --!-- 配合Druid数据源 --property nameconnection.provider_classcom.alibaba.druid.support.hibernate.DruidConnectionProvider/propertyproperty nameurljdbc:mysql://localhost:3306/test?useSSLFALSEamp;serverTimezoneUTCamp;allowPublicKeyRetrievaltrueamp;characterEncodingutf8/propertyproperty nameusernameroot/propertyproperty namepassword101323/propertyproperty namedriverClassNamecom.mysql.cj.jdbc.Driver/propertyproperty namefiltersstat/propertyproperty namemaxActive20/propertyproperty nameinitialSize1/propertyproperty namemaxWait60000/propertyproperty nameminIdle1/propertyproperty nametimeBetweenEvictionRunsMillis60000/propertyproperty nameminEvictableIdleTimeMillis300000/propertyproperty nametestWhileIdletrue/propertyproperty nametestOnBorrowfalse/propertyproperty nametestOnReturnfalse/propertyproperty namepoolPreparedStatementstrue/propertyproperty namemaxOpenPreparedStatements20/propertyproperty nameasyncInittrue/propertymapping resourcemapper/User.hbm.xml//session-factory
/hibernate-configuration更多配置可自行查询
我们来编写测试方法来查看数据源
Test
public void druidTest(){Session session HibernateUtil.getSession();session.doWork(new Work() {Overridepublic void execute(Connection connection) throws SQLException {System.out.println(数据源 connection);}});
}输出结果
6.3、其他配置
1、show_sql是否将运行期生成的SQL输出到日志以供调试。取值true | false
2、format_sql是否将SQL转化为格式良好的SQL。取值true | false
3、hbm2ddl.auto在启动和停止时自动地创建更新或删除数据库模式。取值create | update | create-drop l validate
!-- SQL dialect(hibernate所是的数据库方言) --
property namedialectorg.hibernate.dialect.MySQL8Dialect/property
!-- 是否在控制台打印SQL语句 --
property nameshow_sqltrue/property
!-- 是否对SQL进行格式化 --
property nameformat_sqltrue/property
!-- 指定自动生成数据表的策略 --
property namehbm2ddl.autoupdate/property
!--删除对象后使其OID置为null--
property namehibernate.use_identifier_rollbacktrue/property
!-- 告诉Hibernate的核心配置文件加载哪个映射文件 --
mapping resourcemapper/User.hbm.xml/4、hibernate.jdbc.fetch_size实质是调用 Statement.setFetchSize() 方法设定JDBC的Statement读取数据的时候每次从数据库中取出的记录条数。
/*
例如一次查询1万条记录对于Oracle的JDBC驱动来说是不会1次性把1万条取出来的而只会取出fetchSize, 条
数当结果集遍历完了这些记录以后,再去数据库取 fetchSize 条数据。因此大大节省了无谓的内存消耗。FetchSize设的越大读数据库的次数越少速度越快;FetchSize越小读数据库的次数越多速度越慢。Oracle
数据库的JDBC驱动默认的FetchSize 10,是一个保守的设定根据测试当Fetch Size50时性能会提升1倍
之多当fetch Size100性能还能继续提升20%Fetch Size继续增大性能提升的就不显著了。并不是所有的
数据库都支持Fetch Size特性例如MlySQL就不支持.
*/5、hibernate.jdbc.batch_size设定对数据库进行批量删除批量更新和批量插入的时候的批次大小类似于设置缓冲区大小的意思。batchSize越大批量操作时向数据库发送sql的次数越少速度就越快。
/*
测试结果是当Batch Size 0 的时候使用Hibernate对Oracle数据库删除1万条记录需要25秒
Batch Size 50的时候删除仅仅需要5秒! Oracle数据库batchSize30的时候比较合适。
*/7、对象关系映射文件
7.1、映射文件说明
1、我们知道在使用Hibernate作为持久层框架时都需要在hibernate.cfg.xml配置文件里指明要加载的映射文件有了映射文件hibernate才能完成对象与数据表的关系映射。
2、POJO类和关系数据库之间的映射可以用一个XML文档来定义。
3、通过POJO类的数据库映射文件Hibernate可以理解持久化类和数据表之间的对应关系也可以理解持久化类属性与数据库表列之间的对应关系。
4、在运行时Hibernate将根据这个映射文件来生成各种SQL语句。映射文件的扩展名为实体类名.hbm.xml
5、官方中文文档https://hibernate.net.cn/column/5.html
7.2、hibernate-mapping
1、类层次(class标签)
主键id
被映射的类必须定义对应数据库表主键字段。大多数类有一个JavaBeans风格的属性为每一个实例包含唯一的标识。id元素定义了该属性到数据库表主键字段的映射。
基本类型property
实体引用类many-to-one | one-to-one
集合set | list | map | array
one-to-manymany-to-many
子类subclass | joined-subclass
其它component | any 等
2、查询语句query (用来放置查询语句便于对数据库查询的统一管理和优化)
3、每个Hibernate-mapping中可以同时定义多个类。但更推荐为每个类都创建一个单独的映射文件。
4、hibernate-mapping可配置属性 例如package属性的配置
我们指明包路径后建立类与表的映射关系时只需写明类名即可。
!--Mapper映射文件--
hibernate-mapping packagecom.howie.pojo!-- 建立类与表的映射 --class nameUser tableuser select-before-updatetrue....7.3、映射对象标识符
1、Hibernate使用对象标识符(OID)来建立内存中的对象和数据库表中记录的对应关系.对象的OID和数据表的主键对应Hibernate通过标识符生成器来为主键赋值。
2、Hibernate 推荐在数据表中使用代理主键即不具备业务含义的字段代理主键通常为整数类型因为整数类型比字符串类型要节省更多的数据库空间。
3、在对象-关系映射文件中id元素用来设置对象标识符。generator子元素用来设定标识符生成器。
4、Hibernate提供了标识符生成器接口LdentifierGenerator并提供了各种内置实现
end
所有有关Hibernate有关的内容都可以在官网上查询得到
官网地址http://hibernate.org/