第1章 Hibernate_day01
1.1 Hibernate的学习路线
Hibernate第一天:Hibernate的入门(搭建Hibernate的环境,完成单表CRUD的操作) ,ORM(对象关系映射)。
Hibernate第二天:Hibernate的持久化类编写,Hibernate一级缓存、快照的内容
Hiberante第三天:Hibernate的关联关系映射(一对多,多对多)
Hibernate第四天:Hibernate的查询的方式及抓取策略。
1.2 Hibernate的概述
1.2.1 什么Hibernate
Hibernate就是一个持久层的ORM的框架。对JDBC做了轻量级封装。
1.2.2 什么是ORM
ORM:Object Relational Mapping对象关系映射。
将对象与数据库中表建立映射关系,操作对象就可以操作数据库中表。
/*
* 回顾JDBC代码
*/
publicclass JdbcTest {
@Test
publicvoid testJDBC(){
Connectionconnection = null;
PreparedStatementstatement = null;
ResultSetresultSet = null;
try {
// 准备连接参数
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://127.0.0.1:3306/mybatis_1221";
String user = "root";
String password = "123";
// 加载驱动
Class.forName(driver);
// 建立连接
connection = DriverManager.getConnection(url, user, password);
// 编写SQL
String sql = "SELECT * FROM tb_user WHERE id =?";
// 编译SQL,形成statement
statement = connection.prepareStatement(sql);
// 设置SQL的参数,因为ID是Long类型数据,所以我们用setLong方法
// 通过参数的索引位置进行设置,索引位置是从1开始
statement.setLong(1, 1L);
// 执行查询,获取结果集
resultSet = statement.executeQuery();
// 解析数据
while(resultSet.next()){
System.out.println("id:" + resultSet.getLong("id"));
System.out.println("username:" + resultSet.getString("user_name"));
System.out.println("password:" + resultSet.getString("password"));
System.out.println("age:" + resultSet.getInt("age"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {// 关闭资源
if( resultSet != null){
resultSet.close();
}
} catch(SQLException e) {
e.printStackTrace();
}
try {
if( statement != null){
statement.close();
}
} catch(SQLException e) {
e.printStackTrace();
}
try {
if( connection != null){
connection.close();
}
} catch(SQLException e) {
e.printStackTrace();
}
}
}
}
1.2.3 为什么学习Hibernate
Hibernate:完全面向对象访问数据库(底层会将映射关系组织成sql语句,然后再执行),应用场景:中小型项目
Mybatis:(映射关系,直接写SQL语句),应用场景:大型项目(电商)
1.3 Hibernate的入门
1.3.1 下载Hibernate的开发包
Hibernate提供了3.x 、4.x、 5.x版本
https://sourceforge.net/projects/hibernate/files/hibernate-orm/5.0.7.Final/
1.3.2 解压hibernate
documentation :Hibernate的开发规范和文档
lib :Hibernate的开发使用的jar包
project :Hibernate的提供测试的工程。
1.3.3 创建项目,引入jar包
创建项目hibernate5_day01
(1)引入lib/required/*.jar
(2)数据库驱动包
(3)日志记录的包
* 传统写代码的时候,输出内容,调试操作的时候,通过System.out.println();打印的。
* log4j:日志记录。级别error,warn,info,debug,trace,从高到低
查看项目
1 | antlr-2.7.7.jar | 一个语言转换工具,Hibernate利用它实现HQL到SQL的转换 |
2 | dom4j-1.6.1.jar | Xml解析器 |
3 | geronimo-jta_1.1_spec-1.1.1.jar | 标准的JAVA事务处理接口(跨数据库) |
4 | Hibernate-commons-annotations-5.0.1.Final.jar | 使用javax.persistence下的Annotation可以不依赖Hibernate的JAR包,可以切换到其他的ORM框架 |
5 | Hibernate-core-5.0.7.Final.jar | 核心包 |
6 | hibernate-jpa-2.1-api-1.0.0.Final.jar | 对JPA(Java持久化API)规范的支持,注解开发 |
7 | Jandex-2.0.0.Final.jar | 用来索引annotation的 |
8 | javassist-3.18.1.GA.jar | 代理类生成工具包 |
9 | Jboss-logging-3.3.0.Final.jar | JBoss的日志接口 |
10 | slf4j-api-1.6.1.jar | 简单日志对象接口包 |
11 | slf4j-log4j12-1.7.2.jar | 连接包 |
12 | log4j-1.2.16.jar | Log4j日志包 |
13 | mysql-connector-java-5.1.7-bin.jar | Mysql驱动包 |
在src下创建:log4j.properties文件
### directlog messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE}%5p%c{1}:%L-%m%n
### directmessages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c\:mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE}%5p%c{1}:%L-%m%n
### set loglevels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=info,stdout
1.3.4 创建数据库和表
创建数据库:
创建表
CREATE TABLE`cst_customer` (
`cust_id` bigint(32) NOT NULL AUTO_INCREMENTCOMMENT '客户编号(主键)',
`cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
`cust_source` varchar(32) DEFAULT NULLCOMMENT '客户信息来源',
`cust_industry` varchar(32) DEFAULT NULLCOMMENT '客户所属行业',
`cust_level` varchar(32) DEFAULT NULL COMMENT'客户级别',
`cust_phone` varchar(64) DEFAULT NULL COMMENT'固定电话',
`cust_mobile` varchar(16) DEFAULT NULLCOMMENT '移动电话',
PRIMARY KEY (`cust_id`)
) ENGINE=InnoDBAUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
1.3.5 创建实体类
创建实体类Customer.java,提供set和get方法,每个属性和数据库的列名相对应。
publicclass Customer {
private Long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_phone;
private String cust_mobile;
}
1.3.6 创建Hibernate的映射文件(ORM)
Hibernate的映射文件只要是一个XML文件就可以了。一般映射命名:类名.hbm.xml
作用:让实体类和数据库的表对应;让实体类中的属性和数据库表的字段相对应。直接操作对象就可以操作数据库。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mappingPUBLIC
"-//Hibernate/HibernateMapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- 建立映射关系:将类与表建立映射关系 -->
<!--
class标签:用于建立类与表的映射
* name :类的全路径
* table :数据库表名称
-->
<class name="com.itheima.hibernate.domain.Customer"table="cst_customer"catalog="itcasthibernate">
<!-- 建立类中的属性与表中的字段的映射 -->
<!--
id标签:用来建立表中的主键字段与类中的属性的映射
-->
<id name="cust_id"column="cust_id">
<!-- 主键生成策略:native表示自增长 -->
<generator class="native"/>
</id>
<!-- 其他的属性都是用property建立映射 -->
<property name="cust_name" column="cust_name"/>
<property name="cust_source" column="cust_source"/>
<property name="cust_industry" column="cust_industry"/>
<property name="cust_level" column="cust_level"/>
<property name="cust_phone" column="cust_phone"/>
<property name="cust_mobile" column="cust_mobile"/>
</class>
</hibernate-mapping>
注意:
引入dtd的头信息:
<!DOCTYPEhibernate-mapping PUBLIC
"-//Hibernate/HibernateMapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
配置本地提示:
【请注意】在配置完catalog之后,需要重新打开Customer.hbm.xml文件
1.3.7 创建Hibernate核心配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configurationPUBLIC
"-//Hibernate/HibernateConfiguration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 一:配置连接数据库的基本的信息 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///itcasthibernate</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!-- 二:配置Hibernate的相关属性 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 可选属性 -->
<!-- 显示SQL -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化SQL -->
<property name="hibernate.format_sql">true</property>
<!--
hibernate.hbm2ddl.auto:Hibernate的映射转成DDL
*create :每次都会创建一个新的表。(如果没有表,创建表,如果数据库有表,删除该表,重新创建一个表)-测试的时候
*create-drop :每次都会创建一个新的表,程序结束后,会删除该表。-测试的时候
*update :如果没有表,创建一个新表,如果有表,使用原有表,更新表结构。
*validate :只会使用原有的表。校验映射和表结构是否一致。
-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 三:加载映射文件: -->
<mappingresource="com/itheima/hibernate/domain/Customer.hbm.xml"/>
</session-factory>
</hibernate-configuration>
1.3.8 编写代码
/**
* Hibernate的测试类:入门的测试
*
*/
publicclass HibernateDemo1 {
@Test
/**
* 保存客户
*/
publicvoidsave(){
// 1.加载核心配置文件:
Configurationconfiguration = newConfiguration().configure();
// 1.1手动加载映射:
//configuration.addResource("com/itheima/hibernate/domain/Customer.hbm.xml");
// 1.2这个方法也可以加载映射,前提是实体类与映射文件必须在一个包下。
// configuration.addClass(Customer.class);
// 1.3(推荐)在hibernate.cfg.xml中,添加映射<mappingresource="com/itheima/hibernate/domain/Customer.hbm.xml"/>
// 2.创建一个SessionFactory对象(类似于连接池)
SessionFactorysessionFactory = configuration.buildSessionFactory();
// 3.获得Session对象(连接对象)
Sessionsession = sessionFactory.openSession();
// 4.开启事务
Transactiontransaction = session.beginTransaction();
// 5.操作
Customercustomer = newCustomer();
customer.setCust_name("王宝强");
customer.setCust_level("一级客户");
customer.setCust_source("新浪");
customer.setCust_industry("互联网");
customer.setCust_mobile("13212341234");
customer.setCust_phone("010-34323433");
session.save(customer);
// 6.事务提交
transaction.commit();
// 7.资源释放
session.close();
sessionFactory.close();
}
}
控制台输出的sql语句:
当看到控制台打印如下语句的时候,表明所有的配置都是正确的
1.4 Hibernate的常见配置
1.4.1 XML的提示问题
(1)联网下载:
(2)使用XML Catalog加载:
1.4.2 映射文件配置
映射文件就是将类与表建立映射关系文件,这个文件只要是XML即可。通常名称:类名.hbm.xml
l class标签:建立类和表的映射
n name :类的全路径
n table :数据库中表的名称。如果类名和表名一致的,那么table属性可以省略。
n catalog :数据库名称(可以省略)
l id标签:建立主键和类中属性映射
n name :类中的属性的名称
n column :表中的字段名称。(如果类中的属性名和表中的字段名一致,column可以省略)
n length :字段的长度
n type :字段的类型(可以省略)
n <generator class="native"></generator>:主键生成策略,native表示自增长
l property标签:建立普通字段与类中属性映射
n name :类中的属性的名称
n column :表中的字段名称。(如果类中的属性名和表中的字段名一致,column可以省略)
n length :字段的长度
n type :字段的类型
n not-null :非空
n unique :唯一
1.4.3 核心配置文件的配置
l Hibernate的核心配置文件的方式有两种
n hibernate.properties :不能加载映射文件。必须手动编写代码加载映射文件。
n hibernate.cfg.xml :结构清晰。
l Hibernate的核心配置文件中的内容:
n 数据库连接基本的参数
<!-- 配置连接数据库的基本的信息 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///itcasthibernate</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
n Hibernate的属性
<!-- 配置Hibernate的相关属性 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 可选属性 -->
<!-- 显示SQL -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化SQL -->
<property name="hibernate.format_sql">true</property>
<!--
hibernate.hbm2ddl.auto:Hibernate的映射转成DDL
* create :每次都会创建一个新的表。(如果没有表,创建表,如果数据库有表,删除该表,重新创建一个表)-测试的时候
* create-drop :每次都会创建一个新的表,程序结束后,会删除该表。-测试的时候
* update :如果没有表,创建一个新表,如果有表,使用原有表,更新表结构。
* validate :只会使用原有的表。校验映射和表结构是否一致。
当hbm文件与表的结构一致的时候,什么都不干
当hbm文件与表的结构不一致的时候,就自动报错
-->
<property name="hibernate.hbm2ddl.auto">update</property>
n 映射文件加载
<!-- 加载映射文件: -->
<mapping resource="com/itheima/hibernate/domain/Customer.hbm.xml"/>
1.4.4 Configuration :配置对象
l 用来加载核心配置文件
n 方式一:hibernate.properties
Configuration cfg= new Configuration();
【配置示例】
第一步:在src下创建hibernate.properties:
hibernate.dialect org.hibernate.dialect.MySQLDialect hibernate.connection.driver_class com.mysql.jdbc.Driver hibernate.connection.url jdbc:mysql:///itcasthibernate hibernate.connection.username root hibernate.connection.password root hibernate.show_sql true hibernate.format_sql true hibernate.hbm2ddl.auto update |
提示:上述配置是Hibernate的最小化配置。
【注意】使用hibernate.properties文件的时候,一定知道,这种配置的缺陷是:无法动态的加载*.hbm.xml文件
,正是因为这种缺陷,导致了这种配置方式基本不用,那如果使用这种方式,未来项目中,如何加载配置文件呢?
答:在代码中手动的加载
第二步:【测试新增】
在HibernateDemo1.java中添加:
@Test
/**
* 使用hibernate.properties文件
*/
publicvoidsave_properties(){
/**
* new Configuration():
* * 默认加载src下的hiberante.properties
* new Configuration().config():
* * 默认加载src下的hiberante.properties和hibernate.cfg.xml
* * 此时hibernate.cfg.xml覆盖前面hiberante.properties文件的配置
*/
Configurationconfiguration = newConfiguration();
//加载对应的映射文件(通过代码)
configuration.addResource("com\\itheima\\hibernate\\domain\\Customer.hbm.xml");
SessionFactorysessionFactory = configuration.buildSessionFactory();
Sessionsession = sessionFactory.openSession();
Transactiontransaction = session.beginTransaction();
//5:操作数据库(面向对象就可以操作数据库表)
Customercustomer = newCustomer();
customer.setCust_name("柳岩");
customer.setCust_level("二级客户");
customer.setCust_source("百度");
customer.setCust_industry("互联网");
customer.setCust_mobile("13512121212");
customer.setCust_phone("010-88886666");
session.save(customer);
transaction.commit();
session.close();
sessionFactory.close();
}
n 方式二:hibernate.cfg.xml
Configuration cfg = new Configuration().configure();
l 用来加载映射文件
// 1.1手动加载映射:
//configuration.addResource("com/itheima/hibernate/domain/Customer.hbm.xml");
// 1.2这个方法也可以加载映射,前提是实体类与映射文件必须在一个包下。
//configuration.addClass(Customer.class);
// 1.3(推荐)在hibernate.cfg.xml中,
// 添加映射<mapping resource="com/itheima/hibernate/domain/Customer.hbm.xml"/>
1.5 Hibernate的常用API
1.5.1 SessionFactory:session工厂对象
SessionFactory工厂对象
作用:用来缓存一些配置和数据的
可以缓存:
n Hibernate常用属性(包括连接池)
n hbm类和数据表映射信息
n 预定义SQL语句(命名查询语句)
n 二级缓存
SessionFactory是线程安全的.即当多个线程访问同一个SessionFactory是不存在线程问题的。构造SessionFactory很消耗资源,一般情况下,一个应用(项目)只需要初始化一个,即操作一个全局的SessionFactory对象。
l 抽取工具类:
创建包:com.itheima.hibernate.utils,创建类HibernateUtils.java
/**
* Hibernate的工具类
*/
publicclass HibernateUtils {
privatestaticfinal Configuration cfg;
privatestaticfinal SessionFactory sf;
static{
cfg = newConfiguration().configure();
sf = cfg.buildSessionFactory();
}
// 获得连接的方法:
publicstatic Session openSession(){
returnsf.openSession();
}
}
l 配置C3P0连接池:
引入C3P0相关jar包:
配置C3P0
<!-- 配置C3P0连接池 -->
<property name="connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
<!--在连接池中可用的数据库连接的最少数目 -->
<property name="c3p0.min_size">5</property>
<!--在连接池中所有数据库连接的最大数目 -->
<property name="c3p0.max_size">20</property>
<!--设定数据库连接的过期时间,以秒为单位,如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除-->
<property name="c3p0.timeout">120</property>
<!--每3000秒检查所有连接池中的空闲连接以秒为单位-->
<property name="c3p0.idle_test_period">3000</property>
1.5.2 Session(*****) :连接对象(重点)
Session相对于Connection,是线程不安全的,轻量级对象。Session是Hibernate持久化操作的核心API。
l Serializable save(Object obj); 保存数据
l Serializable update(Object obj); 更新数据
l void delete(Object obj); 更新数据
l T get(Class clazz, Serializable id); 根据ID查询数据
l T load(Class clazz, Serializable id); 根据ID查询数据
创建类:HibernateDemo2.java
l 【保存】
@Test
/**
* 保存客户
*/
publicvoidsave(){
Sessionsession = HibernateUtils.openSession();
Transactiontransaction = session.beginTransaction();
Customercustomer = newCustomer();
customer.setCust_name("如花");
customer.setCust_level("一级客户");
customer.setCust_source("新浪");
customer.setCust_industry("互联网");
customer.setCust_mobile("13212341234");
customer.setCust_phone("010-34323433");
Serializable id = session.save(customer);
System.out.println(id);
transaction.commit();
session.close();
}
l 更新update(Object obj);
/**
* 修改id为4的客户的信息
*/
@Test
publicvoidupdate(){
Sessionsession = HibernateUtils.openSession();
Transactiontransaction = session.beginTransaction();
// 1.直接创建对象进行修改,针对所有字段更新
/*Customer customer = newCustomer();
customer.setCust_id(4L);
customer.setCust_name("星爷");
session.update(customer);*/
// 2.先查询再修改(推荐),可针对某个字段更新
Customercustomer = session.get(Customer.class, 4L);
customer.setCust_name("星爷");
transaction.commit();
session.close();
}
l 删除delete(Object obj);
/**
* 删除操作:
*/
@Test
publicvoiddelete(){
Sessionsession = HibernateUtils.openSession();
Transactiontransaction = session.beginTransaction();
// 1.直接创建对象,传入id删除
/*Customer customer = newCustomer();
customer.setCust_id(4L);
session.delete(customer);*/
// 2.先查询再删除(推荐:级联删除)
Customercustomer = session.get(Customer.class, 4L);
session.delete(customer);
transaction.commit();
session.close();
}
l 查询get()/load();
@Test
/**
* 根据id查询客户
*/
publicvoidgetAndLoad(){
Sessionsession = HibernateUtils.openSession();
Transactiontransaction = session.beginTransaction();
/**
* get和load区别:
* * get采用的立即加载 :程序执行到这行的时候,就会马上发送SQL语句进行查询。
* * get方法查询对象的时候返回的是真实对象本身。
* * get方法查询一个找不到的对象的时候输出null。
*
* * load采用的延迟加载(lazy):程序执行到这行的时候,不会发送SQL语句,真正使用这个对象的时候(使用非主键属性),才会发送SQL语句。
* * load方法查询对象的时候返回的是代理对象。
* * load查询一个找不到的对象的时候返回ObjectNotFoundException.
*/
// get方法
Customercustomer = session.get(Customer.class, 3L);// 马上发送一条SQL语句
System.out.println(customer);
// load方法
/*Customer customer =session.load(Customer.class, 3L);// 没有马上发送SQL语句,调用对象中除了ID之外属性的时候,才发出sql语句
System.out.println(customer.getCust_name());*/
transaction.commit();
session.close();
}
1.5.3 Transaction :事务对象
l commit();提交事务
l rollback();回滚事务