百度百科——Hibernate
1.0 Log4j
学习本章内容之需要用到常用的日志工具类——Log4j。
1.1 平时可见的学习资料中,都是用的log4j 1.x版本
这次我们都使用较新的技术—— log4j 2.x版本
1.2 log4j 2.x版本不再支持像1.x中的.properties后缀的文件配置方式
2.x版本配置文件后缀名只能为".xml",".json"或者".jsn".
系统选择配置文件的优先级(从先到后)如下:
.classpath下的名为log4j2-test.json 或者log4j2-test.jsn的文件.
.classpath下的名为log4j2-test.xml的文件.
.classpath下名为log4j2.json 或者log4j2.jsn的文件.
.classpath下名为log4j2.xml的文件.
1.3 我们一般默认使用log4j2.xml进行命名。
如果本地要测试,可以把log4j2-test.xml放到classpath,而正式环境使用log4j2.xml,则在打包部署的时候不要打包log4j2-test.xml即可。
1.4根节点Configuration有两个属性:status和monitorinterval
- 有两个子节点:Appenders和Loggers(可以定义多个Appender和Logger).
status用来指定log4j本身的打印日志的级别.
monitorinterval用于指定log4j自动重新配置的监测间隔时间,单位是s,最小是5s.
1.5 Appenders节点,常见的有三种子节点:Console、RollingFile、File.
-
Console节点用来定义输出到控制台的Appender.
- name:指定Appender的名字.
- target:SYSTEM_OUT 或 SYSTEM_ERR,一般只设置默认:SYSTEM_OUT.
- PatternLayout:输出格式,不设置默认为:%m%n.
-
File节点用来定义输出到指定位置的文件的Appender.
- name:指定Appender的名字.
- fileName:指定输出日志的目的文件带全路径的文件名.
- PatternLayout:输出格式,不设置默认为:%m%n.
参考格式为:
- RollingFile节点用来定义超过指定大小自动删除旧的创建新的的Appender.
- name:指定Appender的名字.
- fileName:指定输出日志的目的文件带全路径的文件名.
- PatternLayout:输出格式,不设置默认为:%m%n.
- filePattern:指定新建日志文件的名称格式.
- Policies:指定滚动日志的策略,就是什么时候进行新建日志文件输出日志.
- TimeBasedTriggeringPolicy:Policies子节点,基于时间的滚动策略,interval属性用来指定多久滚动一次,默认是1 hour。modulate=true用来调整时间:比如现在是早上3am,interval是4,那么第一次滚动是在4am,接着是8am,12am...而不是7am.
- SizeBasedTriggeringPolicy:Policies子节点,基于指定文件大小的滚动策略,size属性用来定义每个日志文件的大小.
- DefaultRolloverStrategy:用来指定同一个文件夹下最多有几个日志文件时开始删除最旧的,创建新的(通过max属性)。
1.6 Loggers节点,常见的有两种:Root和Logger.
-
Root节点用来指定项目的根日志,如果没有单独指定Logger,那么就会默认使用该Root日志输出
- level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF.
- AppenderRef:Root的子节点,用来指定该日志输出到哪个Appender.
-
Logger节点用来单独指定日志的形式,比如要为指定包下的class指定不同的日志级别等。
- level:日志输出级别,共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF.
- name:用来指定该Logger所适用的类或者类所在的包全路径,继承自Root节点.
- AppenderRef:Logger的子节点,用来指定该日志输出到哪个Appender,如果没有指定,就会默认继承自Root.如果指定了,那么会在指定的这个Appender和Root的Appender中都会输出,此时我们可以设置Logger的additivity="false"只在自定义的Appender中进行输出。
1.7 关于日志level.
共有8个级别,按照从低到高为:All < Trace < Debug < Info < Warn < Error < Fatal < OFF.
- All:最低等级的,用于打开所有日志记录.
- Trace:是追踪,就是程序推进以下,你就可以写个trace输出,所以trace应该会特别多,不过没关系,我们可以设置最低日志级别不让他输出.
- Debug:指出细粒度信息事件对调试应用程序是非常有帮助的.
- Info:消息在粗粒度级别上突出强调应用程序的运行过程.
- Warn:输出警告及warn以下级别的日志.
- Error:输出错误信息日志.
- Fatal:输出每个严重的错误事件将会导致应用程序的退出的日志.
- OFF:最高等级的,用于关闭所有日志记录.
程序会打印高于或等于所设置级别的日志,设置的日志等级越高,打印出来的日志就越少。
我的log4j2.xml文件放在sec/resource目录下,配置内容如下:
2.0 Configuration
说明:Hibernate的配置对象
1.0 Configuration 类的作用是对Hibernate 进行配置,以及对它进行启动。
2.0 在Hibernate 的启动过程中,Configuration 类的实例首先定位映射文档的位置,读取这些配置,然后创建一个SessionFactory对象。
3.0 虽然Configuration 类在整个Hibernate 项目中只扮演着一个很小的角色,但它是启动hibernate 时所遇到的第一个对象。
所以,Configuration的作用就2个:
2.1 加载核心配置文件
如果是一个属性文件,hibernate.properties:
Configuration cfg = new Configuration();
属性文件无法手动加载映射,可以通过如下代码实现:
Configuration configuration = new Configuration().configure();
//手动加载映射
configuration.addResource("com/edp/learn/Customer.hbm.xml");
2.2 手动加载映射文件
// 手动加载映射
configuration.addResource("com/edp/learn/Customer.hbm.xml" );
3.0 SessionFactory
3.1 基本说明
说明:Session工厂
1.0 SessionFactory接口负责初始化Hibernate。
2.0 它充当数据存储源的代理,并负责创建Session对象。这里用到了工厂模式。
3.0 需要注意的是SessionFactory并不是轻量级的,因为一般情况下,一个项目通常只需要一个SessionFactory就够,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。
SessionFactory内部维护了Hibernate的连接池和Hibernate的二级缓存(目前企业中一般不用)。是线程安全的对象,一个项目创建一个对象即可。
3.2 配置连接池
当然,我们可以自己配置连接池。
C3P0:C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate、Spring等。
org.hibernate.connection.C3P0ConnectionProvider
5
20
120
2
true
3000
当然,在之前需要导入C3P0的jar包:
将这三个包复制到项目中的lib目录中并导入:
运行结果如下:
可以看出,标线处开始启动C3P0。
3.3 SessionFactory工厂方法,创建一次即可
-
既然创建一次,就需要编写抽取工具类。
在com.edp.hibernate.utils路径下新建HibernateUtils.java
HibernateUtils.java:
import org.hibernate.Session;
/**
*
* @author EdPeng
* @version 创建时间 2020年1月23日上午12:39:24
* 类说明 Hibernate工具类
*/
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtils {
public static final Configuration cfg;
public static final SessionFactory sf;
static {
cfg = new Configuration().configure();
sf = cfg.buildSessionFactory();
}
public static Session openSession() {
return sf.openSession();
}
}
在com.edp.hibernate.demo1路径下新建HibernateUtils.java
代码如下:
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.edp.hibernate.utils.HibernateUtils;
/**
*
* @author EdPeng
* @version 创建时间 2020年1月23日上午12:43:16
* 类说明 Hibernate的工具类的测试
*/
public class HibernateDemo2 {
@Test
public void demo1() {
Session session = HibernateUtils.openSession();
Transaction txTransaction = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("王二小");
session.save(customer);
txTransaction.commit();
session.close();
}
}
这样就能做到不重复新建SessionFactory对象。
4.0 Session
相当于JDBC中的Connection对象,是连接对象。代表Hibernate和数据库,建立起连接,是非线程安全的。是与数据库交互的桥梁。
- Session接口负责执行被持久化对象的CRUD操作(CRUD的任务是完成与数据库的交流,包含了很多常见的SQL语句)。
- 但需要注意的是Session对象是非线程安全的。
- 同时,Hibernate的session不同于JSP应用中的HttpSession。这里当使用session这个术语时,其实指的是Hibernate中的session,而以后会将HttpSession对象称为用户session。
4.1 Session中的API
- 保存方法:
Serializable save(Object obj);
- 查询方法:
T get(Class c,Serializable id);
T load(Class c,Serializable id);
- 修改方法
void update(Object obj);
- 删除方法
void delete(Object obj);s
- 保存或更新
void saveOrUpdate(Object obj)
查询所有
在我们使用Hibernate的所有代码都可以共用一块模板:
@Test
//查询
public void demo2() {
Session session = HibernateUtils.openSession();
Transaction txTransaction = session.beginTransaction();
//写自己的代码
txTransaction.commit();
session.close();
}
4.2 get方法和load方法的区别?
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.edp.hibernate.utils.HibernateUtils;
/**
*
* @author EdPeng
* @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
*/
public class HibernateDemo2 {
@Test
// 查询
// ******** get方法和load方法的区别
public void demo2() {
Session session = HibernateUtils.openSession();
Transaction txTransaction = session.beginTransaction();
/**
* get 方法 * 采用的是立即加载,执行到这行代码的的时候,就会马上发送SQL语句去查询。 * 查询或返回是真实对象本身。 *
* 查询一个找不到的对象的时候,返回null。
*
* load方法 * 采用的是延迟加载(lazy懒加载)。执行到这行代码的时候不会发送SQL语句。当真正使用这个对象的时候,才会发送SQL语句。 *
* 查询后返回的是代理对象。javassist-3.24.0-GA.jar 利用第三方的javassist技术产生的代理。 *
* 查询一个找不到的对象的时候,返回ObjectNotFoundException
*/
// 使用get方法查询
Customer customer = session.get(Customer.class, 1l);// 发送sql语句
System.out.println(customer.toString());
// 使用load方法查询
Customer customer1 = session.load(Customer.class, 2l);
System.out.println(customer1.toString());
txTransaction.commit();
session.close();
}
}
查询结果:
4.3 修改方法
void update(Object obj);
修改操作有2种方法。
1. 第一种,直接修改。
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.edp.hibernate.utils.HibernateUtils;
/**
*
* @author EdPeng
* @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
*/
public class HibernateDemo2 {
@Test
// 修改操作
public void demo3() {
Session session = HibernateUtils.openSession();
Transaction txTransaction = session.beginTransaction();
//
// 直接创建对象,进行修改
Customer customer = new Customer();
customer.setCust_id(1l);
customer.setCust_name("张三丰");
session.update(customer);
// 先查询后修改(推荐)
// Customer customer2 = session.get(Customer.class, 3l);
// customer2.setCust_name("周伯通");
// session.update(customer2);
txTransaction.commit();
session.close();
}
}
执行之前的数据库:
执行结果:
执行之后的数据库:
可见,用着种方法,会默认把其他set方法设置为null,导致数据丢失。
2. 先查询,后修改。
我们一般推荐如下方法:
package com.edp.hibernate.demo1;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.edp.hibernate.utils.HibernateUtils;
/**
*
* @author EdPeng
* @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
*/
public class HibernateDemo2 {
@Test
// 修改操作
public void demo3() {
Session session = HibernateUtils.openSession();
Transaction txTransaction = session.beginTransaction();
//
// 直接创建对象,进行修改
// Customer customer = new Customer();
// customer.setCust_id(1l);
// customer.setCust_name("张三丰");
// session.update(customer);
// 先查询后修改(推荐)
Customer customer2 = session.get(Customer.class, 3l);
customer2.setCust_name("周伯通");
session.update(customer2);
txTransaction.commit();
session.close();
}
}
执行前的数据库:
执行结果:
执行后的数据库:
所以再一次推荐修改操作为第二种:先查询后修改(推荐)。
4.4 删除方法
void delete(Object obj);
删除也有两种方法,一种是直接删除,一种是先查询后删除,同样我们推荐第二种方法。
1. 直接删除
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.edp.hibernate.utils.HibernateUtils;
/**
*
* @author EdPeng
* @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
*/
public class HibernateDemo2 {
@Test
//删除操作
public void demo4() {
Session session = HibernateUtils.openSession();
Transaction txTransaction = session.beginTransaction();
//直接创建对象,删除
Customer customer = new Customer();
customer.setCust_id(4l);
session.delete(customer);
//先查询再删除(推荐) 级联删除必须先查询后删除
//比如多表的映射,客户下面还有订单,建立1对多的关系,这样可以把客户及其订单全删掉。
// Customer customer2 = session.get(Customer.class,5l);
// session.delete(customer2);
txTransaction.commit();
session.close();
}
}
报PersistenceException错误,并提示not-null property references a null or transient value
,无法成功运行。原因在于在我们的数据库配置文件Customer.hbm.xml中,对
将其设置not-null设置为true,而我们的数据库是允许其为null,这里需要将所有的not-null属性设置为false,或者不设置not-null属性即可。
执行之前的数据库:
执行结果:
执行之后的数据库:
2. 先查询后删除
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.edp.hibernate.utils.HibernateUtils;
/**
*
* @author EdPeng
* @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
*/
public class HibernateDemo2 {
@Test
//删除操作
public void demo4() {
Session session = HibernateUtils.openSession();
Transaction txTransaction = session.beginTransaction();
//直接创建对象,删除
// Customer customer = new Customer();
// customer.setCust_id(1l);
// session.delete(customer);
//先查询再删除(推荐) 级联删除必须先查询后删除
//比如多表的映射,客户下面还有订单,建立1对多的关系,这样可以把客户及其订单全删掉。
Customer customer2 = session.get(Customer.class,5l);
session.delete(customer2);
txTransaction.commit();
session.close();
}
}
执行之前的数据库:
执行结果:
执行之后的数据库:
同样,我们推荐第二种删除方法,因为第二种支持级联删除,联删除必须先查询后删除,比如多表的映射,客户下面还有订单,建立1对多的关系,这样可以把客户及其订单全删掉。
而第一种我们知道,会把没有写明的其他属性值重置为null,再进行相关操作,会删除关联信息,导致关联的其他表格数据无法被删除。
4.5 保存或更新方法
void saveOrUpdate(Object obj)
保存或更新方法也有两种,一种是直接通过setCust_name等方法添加字段,这是更新操作,另一种是通过setCust_id(7l)加其他set方法,实现保存(修改)操作。
1. 保存更新操作
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.edp.hibernate.utils.HibernateUtils;
/**
*
* @author EdPeng
* @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
*/
public class HibernateDemo2 {
@Test
// 保存或更新操作
public void demo5() {
Session session = HibernateUtils.openSession();
Transaction txTransaction = session.beginTransaction();
// 直接添加,更新
Customer customer = new Customer();
customer.setCust_name("柯镇恶");
session.saveOrUpdate(customer);
// 有id,则是保存,id找不到则会报错
// Customer customer2 = new Customer();
// customer2.setCust_id(7l);
// customer2.setCust_name("风清扬");
// session.saveOrUpdate(customer2);
txTransaction.commit();
session.close();
}
}
执行之前的数据库:
执行结果:
执行之后的数据库:
2. 保存(修改)操作
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.edp.hibernate.utils.HibernateUtils;
/**
*
* @author EdPeng
* @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
*/
public class HibernateDemo2 {
@Test
// 保存或更新操作
public void demo5() {
Session session = HibernateUtils.openSession();
Transaction txTransaction = session.beginTransaction();
// 直接添加,更新
// Customer customer = new Customer();
// customer.setCust_name("柯镇恶");
// session.saveOrUpdate(customer);
// 有id,则是更新,id找不到则会报错
Customer customer2 = new Customer();
customer2.setCust_id(7l);
customer2.setCust_name("风清扬");
session.saveOrUpdate(customer2);
txTransaction.commit();
session.close();
}
}
执行之前的数据库:
执行结果:
执行之后的数据库:
4.6 查询所有
NativeQuery Session.createSQLQuery(String arg0);
1. 支持HQL语句查询,返回Query类型。
- HQL:Hibernate Query Language 面向对象的查询语言
代码演示:
import java.util.List;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.Query;
import org.junit.Test;
import com.edp.hibernate.utils.HibernateUtils;
/**
*
* @author EdPeng
* @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
*/
public class HibernateDemo2 {
@Test
// 查询所有
public void demo6() {
Session session = HibernateUtils.openSession();
Transaction txTransaction = session.beginTransaction();
// 接收HQL:Hibernate Query Language 面向对象的查询语言
// 需要向createQuery方法传递一个HQL参数
//返回Query类型
Query query = session.createQuery("from Customer");
List list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
txTransaction.commit();
session.close();
}
}
数据库:
执行结果:
2. 支持SQL语句查询,返回NativeQuery 类型(5.2之前使用SQLQuery类型)。
hibernate 5.2 之后,SQLQuery类已作废,用NativeQuery替代。
将查询结果作为列表返回。如果查询每行包含多个结果,则结果将在Object[]的实例中返回。
示范代码:
import java.util.Arrays;
import java.util.List;
import org.hibernate.query.NativeQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.Query;
import org.junit.Test;
import com.edp.hibernate.utils.HibernateUtils;
/**
*
* @author EdPeng
* @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
*/
public class HibernateDemo2 {
@Test
// 查询所有
public void demo6() {
Session session = HibernateUtils.openSession();
Transaction txTransaction = session.beginTransaction();
// 接收HQL:Hibernate Query Language 面向对象的查询语言
// 需要向createQuery方法传递一个HQL参数
// Query query = session.createQuery("from Customer");
// List list = query.list();
// for (Customer customer : list) {
// System.out.println(customer);
// }
// 接收SQL
NativeQuery nativeQuery= session.createSQLQuery("select * from cst_customer");
List
执行结果为:
5.0 Transaction:事务对象
Hibernate中管理事务的对象,其中的API非常少。最常用的就以下两个方法:
commit(); 提交
rollback(); 回滚
- Transaction 接口是一个可选的API,可以选择不使用这个接口,取而代之的是Hibernate 的设计者自己写的底层事务处理代码。
- Transaction 接口是对实际事务实现的一个抽象,这些实现包括JDBC的事务、JTA 中的UserTransaction、甚至可以是CORBA 事务。
- 之所以这样设计是能让开发者能够使用一个统一事务的操作界面,使得自己的项目可以在不同的环境和容器之间方便地移植。
没有配置C3P0,需要编写开启和提交代码,如果自带的连接池,Hibernate会帮我们自动开启和提交事务。
6.0 附录
最后,附上整个项目的目录和本章的完整代码:
import java.util.Arrays;
import java.util.List;
import org.hibernate.query.NativeQuery;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.Query;
import org.junit.Test;
import com.edp.hibernate.utils.HibernateUtils;
/**
*
* @author EdPeng
* @version 创建时间 2020年1月23日上午12:43:16 类说明 Hibernate的工具类的测试
*/
public class HibernateDemo2 {
@Test
public void demo1() {
Session session = HibernateUtils.openSession();
Transaction txTransaction = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("王二小");
session.save(customer);
txTransaction.commit();
session.close();
}
@Test
// 查询
// ******** get方法和load方法的区别
public void demo2() {
Session session = HibernateUtils.openSession();
Transaction txTransaction = session.beginTransaction();
/**
* get 方法 * 采用的是立即加载,执行到这行代码的的时候,就会马上发送SQL语句去查询。 * 查询或返回是真实对象本身。
* *查询一个找不到的对象的时候,返回null。
*
* load方法 * 采用的是延迟加载(lazy懒加载)。执行到这行代码的时候不会发送SQL语句。当真正使用这个对象的时候,才会发送SQL语句。 *
* 查询后返回的是代理对象。javassist-3.24.0-GA.jar 利用第三方的javassist技术产生的代理。 *
* 查询一个找不到的对象的时候,返回ObjectNotFoundException
*/
// 使用get方法查询
Customer customer = session.get(Customer.class, 1l);// 发送sql语句
System.out.println(customer.toString());
// 使用load方法查询
Customer customer1 = session.load(Customer.class, 2l);
System.out.println(customer1.toString());
txTransaction.commit();
session.close();
}
@Test
// 修改操作
public void demo3() {
Session session = HibernateUtils.openSession();
Transaction txTransaction = session.beginTransaction();
//
// 直接创建对象,进行修改
// Customer customer = new Customer();
// customer.setCust_id(1l);
// customer.setCust_name("张三丰");
// session.update(customer);
// 先查询后修改(推荐)
Customer customer2 = session.get(Customer.class, 3l);
customer2.setCust_name("周伯通");
session.update(customer2);
txTransaction.commit();
session.close();
}
@Test
// 删除操作
public void demo4() {
Session session = HibernateUtils.openSession();
Transaction txTransaction = session.beginTransaction();
// 直接创建对象,删除
Customer customer = new Customer();
customer.setCust_id(4l);
session.delete(customer);
// 先查询再删除(推荐) 级联删除必须先查询后删除
// 比如多表的映射,客户下面还有订单,建立1对多的关系,这样可以把客户及其订单全删掉。
// Customer customer2 = session.get(Customer.class,5l);
// session.delete(customer2);
txTransaction.commit();
session.close();
}
@Test
// 保存或更新操作
public void demo5() {
Session session = HibernateUtils.openSession();
Transaction txTransaction = session.beginTransaction();
// 直接添加,更新
// Customer customer = new Customer();
// customer.setCust_name("柯镇恶");
// session.saveOrUpdate(customer);
// 有id,则是更新,id找不到则会报错
Customer customer2 = new Customer();
customer2.setCust_id(7l);
customer2.setCust_name("风清扬");
session.saveOrUpdate(customer2);
txTransaction.commit();
session.close();
}
@Test
// 查询所有
public void demo6() {
Session session = HibernateUtils.openSession();
Transaction txTransaction = session.beginTransaction();
// 接收HQL:Hibernate Query Language 面向对象的查询语言
// 需要向createQuery方法传递一个HQL参数
// Query query = session.createQuery("from Customer");
// List list = query.list();
// for (Customer customer : list) {
// System.out.println(customer);
// }
// 接收SQL
NativeQuery nativeQuery= session.createSQLQuery("select * from cst_customer");
List
END