单元测试:
当一个项目中我们完成了某个小功能,如果在早期我们需要测试该功能,大部分需要启动整个项目,测试完有问题,需要更改,之后又需要启动整个项目.这种测试手段比较麻烦,我们就可以将需要测试的功能,在单元测试中完成,确定没有问题,在启动项目.
@Before:每个测试方法之前执行的方法
@Before
public void Before() {
/*
* configure()方法没参数时,默认加载src下hibernate.cfg.xml文件;
* 如果该配置文件的路径或名称没有使用默认的,就需要给configure()方法加参数,
* 指定路径或新名称.
*/
//(1)读取并解析hibernate.cfg.xml配置文件
Configuration config = new Configuration().configure();
/*(2)由hibernate.cfg.xml中的<mapping resource="com/xx/User.hbm.xml"/>读取并解析映射信息*/
// (3)创建会话SessionFactory对象
SessionFactory sf = config.buildSessionFactory();
// (4)加载Session对象
Session session = sf.openSession();
}
@Test:
该方法就是测试方法,把需要测试的功能在该方法中完成测试,测试方法不能有返回值和参数.
@Test
public void testAdd() {
//(5)开启事务Transation
//hibernate不会自动提交事务,session对数据的所有操作需要在事务中进行
Transaction ts = session.beginTransaction();
try{
//(6)持久化操作
//(7)提交事务
ts.commit();
} catch (Exception e) {
//(8)回滚
ts.rollback();
e.printStackTrace();
}
}
@After:每个测试方法之后执行的方法
@After
public void After() {
if (session != null) {
session.clear();
//(9) 关闭session对象
session.close();
/*
*关闭session工厂,清空资源.由于sessionFactory对象持有整个持久化操作的资源,
*关闭之后,下次在使用又需要创建,太耗内存,通过监听器application servletContext对象,
*当服务器关闭或Web应用被移除时,ServletContext对象跟着销毁,
*当停止进程时,再清理sessionFactory资源
*/
//(10) 关闭sessionFactory对象
sessionFactory.close();
}
}
hibernate.cfg.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<!-- 对session工厂的设置 -->
<session-factory>
<!-- 四本一言的设置 -->
<!--数据库地址-->
<property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/hibernatem?characterEncoding=utf8</property>
<!-- 数据库用户名 -->
<property name="hibernate.connection.username">root</property>
<!-- 数据库密码 -->
<property name="hibernate.connection.password">12345678</property>
<!-- 数据库驱动 -->
<property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<!-- 数据库方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<!-- 控制台是否显示sql语句 -->
<!--show_sql: 是否把Hibernate运行时的SQL语句输出到控制台 -->
<property name="show_sql">true</property>
<!--format_sql 输出到控制台的SQL语句是否进行排版,便于阅读 -->
<property name="format_sql">true</property>
<!--hbm2ddl.auto 自动建表: 可以帮助由java代码生成数据库脚本,进而生成具体的表结构 -->
<property name="hbm2ddl.auto">update</property>
<!-- 二级缓存配置 -->
<!-- 默认是不使用二级缓存,设置使用二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!-- 开启查询缓存,如果不开启,每次查询完只存主键,开启后可以存其它字段,拿到一条完整的记录 -->
<property name="hibernate.cache.use_query_cache">true</property>
<!-- 配置谁来支撑 -->
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<!--引入映射文件-->
<mapping resource="com/xalo/model/ClassRoom.hbm.xml"/>
<mapping resource="com/xalo/model/Student.hbm.xml"/>
<!-- 设置使用二级缓存的对象并指定并发策略-->
<class-cache usage="read-only" class="com.xalo.model.ClassRoom"></class-cache>
</session-factory>
</hibernate-configuration>
<!-- 数据库方言 hibernate.dialect:配置Hibernate数据库方言
1、org.hibernate.dialect.MySQLDialect;
2、org.hibernate.dialect.MySQL5InnoDBDialect;
3、org.hibernate.dialect.MySQLMyISAMDialect -->
<!-- hbm2ddl.auto: 的值有一下四种:
1. create:每次加载hibernate时,都会删除上一个的生成的表,
然后根据你的model类,再重新生成新表,数据库表数据容易丢失
2. create-drop: 每次加载hibernate时根据model类生成类,但是sessionFactory一关闭,表就自动删除
3. update: 第一次加载hibernate时根据model类会自动建立起表结构,
以后加载hibernate时,根据model类自动更新表结构
当部署到服务器后,表结构不会被马上建立起来的,要等第一次运行起来后才会
4. validate:每次加载hibernate时,验证创建数据库表结构,
只会和数据库中的表进行比较,不会创建新表,但是会插入新值 -->
<!-- 开启查询缓存(一般配合二级缓存使用,两个都设置为true)
如果没有开启二级缓存,只开启了查询缓存,此时缓存中只存储查询出来的数据的id
如果后续再查询相同的数据,根据缓存中的id分条查询数据 -->
XXXX.hbm.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!--将实体类和数据库表建立映射关系, name:要建立映射的类 table:表中 的字段名-->
<class name = "com.xalo.model.ClassRoom" table="room">
<!--主键配置-->
<id name = "roomId" column ="rid">
<!--主键生成策略-->
<generator class = "native"></generator>
</id>
<!-- 字段映射 -->
<property name="roomName" column="name"></property>
</class>
</hibernate-mapping>
<!--主键配置 name:类中成员变量 column:表中的字段名
length:当前类的长度,默认数据库对于类型最大长度
type:当前类的类型,默认自动检测类型-->
<!--主键生成策略:
increment:先查询表中主键最大值,加1作为子女的主键值(其中最少有一条数据)
identity:依赖与数据库的主键自增
sequence:使用数据库中的列名
hilo: hibernate自己用于高低位算法完成主键自增
native: 相当于 auto_increment 自动递增 自动根据数据库三选一(identity/sequence/hilo)
uuid:生成随机字符串(长度应大于32位)
assigned: 自然主键,hibernate不生成主键,有开发人员自己设置主键值 -->
<!--字段映射
配置其它属性 name:类中成员变量
column:表中的字段名
length:当前列的长度,默认数据库对于类型最大长度
type:当前列的类型,默认自动检测属性
not-null:设置非空
unique:设置唯一-->
持久化操作:
Add:
Student student = new Student();
student.setName("碧瑶");
student.setAge(18);
student.setScore(86.9);
session.save(student);
Delete:
/*删除数据:
*delete方法只能按照id删除 session.delete(deleteStu);
*如果要批量删除(删除多条记录)
* 用HQL查询出要删除的数据
*/
Student deleteStu = new Student();
//第一种方式: 根据sid删除学生
String hql = "select sid from Student where name = ?0";
Query query = session.createQuery(hql).setParameter(0, "张小凡");
//将查询结果放在一个list集合中
List<Integer> deleteSid = query.list();
for (Integer sid : deleteSid) {
deleteStu.setSid(sid);
session.delete(deleteStu);
}
//第二种方式: 找出年龄是23的人,删除
String hql = "from Student where age = ?0";
Query query = session.createQuery(hql).setParameter(0, 23);
//将查询结果放在一个list集合中
List<Student> students = query.list();
for (Student student : students) {
session.delete(student);
}
query:
<!--查询数据:
*(1)查询单条记录:
* 1.get: 单条查询 通过get方式,只能通过主键(sid)查询.
* 第一个参数:类的class对象
* 第二个参数: 主键值
* 2.load:会延时查询,在查询时并没有直接去通过sql语句查询结果,
* 而是只得到要查询记录的sid,当我们要使用查询记录中的
* 其它字段的值,这时才会去表中查询
* 如果查询的数据不存在,报异常.get方法会返回一个null
*
* (2)查询多条记录:
* HQL语言:
* hibernate的查询语言,表名对应类名,字段名对应成员变量
* 与SQL相似,SQL中的语法基本上都可以直接使用.
* SQL查询的是表和表中的列,HQL查询的是对象和对象的属性.
* HQL的关键字不区分大小写,类名与属性名区分大小写
*
* select可以省略
* 直接from查询出来的是一个映射对象,即:查询的整个映射对象的字段
-->
<!--查询单条记录-->
Student student = session.get(Student.class, new Integer(2));
Student student = session.load(Student.class, new Integer(2));
System.out.println(student);
<!--查询多条记录-->
String hql = "from Student where name = ?0";
Query<Student> query = session.createQuery(hql).setParameter(0, "曾书书");
<!--将查询到的结果放到一个list集合中,需要在model层里面重写toString()方法,不然遍历出来的是内存地址-->
List<Student> list = query.list();
for (Student student2 : list) {
System.out.println(student2);
}
<!--查询其中某个字段-->
String hql = "select name from Student where name = ?0";
Query<String> query = session.createQuery(hql).setParameter(0, "曾书书");
//默认查询出来的list里存放的是一个Object数组
List<String> list = query.list();
for (String student2 : list) {
System.out.println(student2);
}
<!--查询其中某几个字段-->
String hql = "select name,age from Student where name = ?0";
Query<Object[]> query = session.createQuery(hql).setParameter(0, "曾书书");
//默认查询出来的list里存放的是一个Object数组
List<Object[]> list = query.list();
for (Object[] student2 : list) {
System.out.println(Arrays.toString(student2));
}
update:
<!--第一种方式:将所有的属性个必须写全才能修改-->
Student updateStu = new Student();
updateStu.setSid(9);
updateStu.setName("张小凡");
updateStu.setAge(20);
updateStu.setScore(86.0);
<!--第二种方式:根据sid取出一条信息,然后可以随意修改里面的任意属性-->
Student updateStu = session.get(Student.class, 7);
if (updateStu != null) {
updateStu.setName("毕燕");
session.update(updateStu);
}
Hibernate运行流程:
Hibernate五大核心接口:
Configuration接口:
加载配置文件,创建sessionFactory对象
SessionFactory接口:
初始化Hibernate,充当数据库存储源的代理,创建Session对象
SessionFactory特点:
1.它是线程安全的,同一个实例可以被应用的多个线程共享.
2.它是重量级的,不能随意创建或销毁它的实例.
3.如果应用只访问一个数据库,只需创建一个SessionFactory实例,
在应用初始化的时候创建该实例.
如果应用同时访问多个数据库,则需要为每一个数据库创建一个单独的 SessionFactory实例
4.SessionFactory需要一个很大的缓存,用来存放预定义的SQL语句以能映射元数据等.
Hibernate的第二级缓存: 用户可以为SessionFactory配置一个缓存插件,该缓存用来存放被工作单元过的数据,将来其它工作单元可能会重用这些数据,因此这个缓存中的数据能够被所有的工作单元共享.一个工作单元通常对应一个数据库事务.
SessionFactory的作用 :
1. 创建session对象
(1) openSession
(2)getCurrentSession,将session和线程绑定,需要在cfg的配置文件中将session和线程绑定
2. 在内置缓存中缓存了cfg hbm等配置文件
3. 外置缓存就是二级缓存
4. 会话工厂对象中缓存的hibernate运行了大部分资源,所以使用hibernate期间不要轻易的关闭会话工厂,因为每次加载太耗资源,当项目关闭之后,再关闭会话对象清空资源.
Session接口:
Session被称为持久化管理器,它提供了和持久化相关的操作,如:添加 删除 加载 查询对象.
Session特点:
1.不是线程安全的,因此在设计软件架构时,应该避免多个线程共享同一个Session实例.
2.Session实例时轻量级的,它的创建和销毁不需要消耗太多的资源.
在程序中可以经常创建和销毁Session对象
3.Hibernate的第一级缓存:存放被当前工作单元加载的对象.
每个Session实例都有自己的缓存,每个Session实例的缓存只能被当前工作单元访问.
Transaction接口:
1.Transaction接口是Hibernate数据库事务接口,它对底层的事务接口做了封装,
2.hibernate大大部分操作需要在事务中进行
3.开启事务,提交/回滚
Query和Criteria接口:
1.Hibernate的查询接口,用于向数据库查询对象,以及控制查询的过程.
2.Query实例包装了一个HQL查询语句,HQL查询语句是面向对象的,它引用类句及类的属性句,而不是表句及表的字段句.
3.Criteria接口完全的封装了基于字符串的查询语句,比Query接口更加面向对象,Criteria接口擅长执行动态查询.
Session接口的find()方法也具有数据查询功能,但它只是执行一些简单的HQL查询语句的快捷方法,它的功能远没有Query接口强大.