一、Session对象
1.Hibernate最重要的对象,只用使用hibernate与数据库操作,都用到这个对象
2.该对象维护了一个Connection对象。代表了与数据库连接的会话。
3.该对象实质上是对Connection对象的包装,
在Connection对象基础之上,封装了一些方法。
4.使用hibernate操作数据库时,执行更新操作(增、删、改)必须在事务中进行。
1.1 session对象的创建
Session session= new Configuration().configure()
.addClass(DeveloperEnTity.class)
.addClass(ProjectEntity.class)
.buildSessionFactory()
.openSession();
1.2 session对象的作用
Session代表的是Hibernate与数据库的链接对象,是与数据库交互的桥梁。
它是从持久化服务中剥离出来的一个非常重要的API接口。
Session的内部维护了一个Connection对象。
它实质上是对Connection对象的包装,在Connection基础上进行了加强。
他的主要功能是负责执行被持久化对象的CRUD操作。
1.3 session对象的生命周期(Session对象只能定义为局部变量)
//读取配置文件,创建SessionFactory的工厂。该工厂在java应用中是单实例。
Confiuration cf=new Configuration();
cf.configure();
SessionFactpry sf=cf.buildSessionFactory;
//获取session
Session session=sf.openSession();
//开启事务
session.beginTransiction();
...
...
//事务提交
session.getTransaction().commit();
//关闭session
session.close();
Hibernate中Session对象是非线程安全的 ,不能定义成全局变量,
只能定义成局部变量。因此session作用时间短。
session的声明周期:
sf.openSession() session的创建
session.close() session的销毁
1.4 session对象内部维护的session缓存
session对象内部维护了一个缓存对象,其作用就是提高程序的效率。
它随着session对象的创建而存在,随着session对象的关闭而销毁。
1.5 session对象的生命周期与session缓存的安全问题
session对象内部维护了一个一级缓存。首先session对象是线程非安全的。
如果我们在创建session对象时,把sesison对象作为成员变量。那么,
由于session是非线程安全的,那么sesson对象内部维护的一级缓存也是线
程非安全的。所以我们在创建session对象,都会把它作为局部变量。局部
变量,自带线程安全属性。
二、Session对象API – 事务
2.1 开启事务以及提交事务
使用hibernate执行新增或修改操作时,必须要在事务环境下执行。
session.beginTransaction();
开启一个事务;
hibernate要求所有的与数据库的操作
必须有事务的环境,否则报错!
...
session.getTransaction().commit();
提交事务。
2.2 事务的作用流程
public static void main(String[] args) {
UserEntity user=new UserEntity();
user.setId(1212);
session.beginTransaction();
System.out.println("...1");
session.save(user);
System.out.println("...2");
session.flush();
System.out.println("...3");
session.getTransaction().commit();
System.out.println("...4");
}
三、Session对象API – 更新操作(更新/新增/删除)
更新:
session.delete(obj); 删除一个对象
session.save(obj); 保存一个对象
session.update(emp); 更新一个对象
session.saveOrUpdate(emp); 保存或者更新的方法:
没有设置主键,执行保存;
有设置主键,执行更新操作;
如果设置主键不存在报错!
public class Demo2 {
private static SessionFactory sf;
static {
Configuration cf=new Configuration();
cf.configure();
sf=cf.buildSessionFactory();
}
@Test
public void testUpdate() {
//创建对象
UserEntity u=new UserEntity();
u.setId("366cbb16-7c1ce-4b23-9b5a-bd34a0583d20");
u.setName("666");
u.setBirth(new Date());
//1.创建会话连接
Session session = sf.openSession();
//1.如果数据库有该主键,则更新,如果没有,则新增
// Transaction tr = session.beginTransaction();
// session.saveOrUpdate(u);
// tr.commit();
//2.如果数据有该主键,则更新。如果没有,则报错
Transaction tr = session.beginTransaction();
session.update(u);
tr.commit();
}
3.1 save()
注意事项:
1.对象被保存后,对象的ID会自动赋值。
2.对象设置主键,在save方法保存之后,会被自动刷新成数据库中的存储的主键。(对象单独设置的主键无效)
>>> 3.1.1 对象被保存后,ID会自动赋值
public static void main(String[] args) {
session.beginTransaction();
//先根据ID去缓存中查找是否有该对象,如果没有就去数据库中查找。找到后放入到缓存中
ProjectEntity pro=new ProjectEntity();
pro.setpDesc("111");
System.out.println("保存前打印:"+pro);
session.save(pro);
session.getTransaction().commit();
System.out.println("保存后打印:"+pro);
session.close();
}
>>> 3.1.2 ID在save方法前设置,保存无效。
public static void main(String[] args) {
session.beginTransaction();
//先根据ID去缓存中查找是否有该对象,如果没有就去数据库中查找。找到后放入到缓存中
ProjectEntity pro=new ProjectEntity();
pro.setpDesc("111");
pro.setpId(111);
System.out.println("保存前打印:"+pro);
session.save(pro);
session.getTransaction().commit();
System.out.println("保存后打印:"+pro);
session.close();
}
3.2 update()
>>> 3.2.1 session关闭后,持久化对象变游离对象
关闭session。重新打开的时候。不会执行update语句。
因为news对象是查询出来了。放在session缓存中。
然后关闭了。又重新打开了一个session中。
但是新打开的session中没有news对象。
所以修改对象不会执行update。需要显示的调用update方法。
@org.junit.Test
public void testUpdate(){
News news =(News) session.get(News.class, 1);
transaction.commit();
session.close();
session=sessionFactory.openSession();
transaction=session.beginTransaction();
news.setAuthor("YI");
}
>>> 3.2.2 若数据表中没有对应的记录。但还调用了update方法。会抛出异常。
查询一个news对象。然后修改ID 。抛出StaleObjectStateException 异常
@org.junit.Test
public void testUpdate(){
News news =(News) session.get(News.class, 1);
transaction.commit();
session.close();
session=sessionFactory.openSession();
transaction=session.beginTransaction();
news.setId(10);
session.update(news);
}
>>> 3.2.3 当update()方法关联一个游离对象时。如果session的缓存中已经存在相同OID的持久化对象。会抛出异常。因为在Session缓存中不能有两个相同OID的对象。
@org.junit.Test
public void testUpdate(){
News news =(News) session.get(News.class, 1);
transaction.commit();
session.close();
session=sessionFactory.openSession();
transaction=session.beginTransaction();
News news2 =(News) session.get(News.class, 1);
session.update(news);
}
3.3 delete()
>>> 3.3.1 只要OID和数据表中一条记录对应。就删除。若OID没有对应的。抛出异常。
public void testDelete(){
News news =(News) session.get(News.class, 1);
session.delete(news);
System.out.println(news);
}
>>> 3.3.2 由于使用delete()删除时,如果数据库中没有该数据,就会报错,常使用 经常是先查询在删除。
public void testDelete(){
News news =(News) session.get(News.class, 1);
session.delete(news);
System.out.println(news);
}
>>> 3.3.3 删除数据时,上述操作会操作两次,也可以使用hql删除。hql删除无上述弊端。
public void delete(String id) {
Session session = sf.getCurrentSession();
session.createQuery("delete from EmpEntity where id=?")
.setParameter(1, id)
.executeUpdate();
}
3.4
3.4 saveOrUpdate()
四、Session对象API - 查询操作
4.1 主键查询
4.1.1 get查询、load查询
主键查询:
session.get(Employee.class, 1); 主键查询,即时加载
session.load(Employee.class, 1); 主键查询 (支持懒加载)
public class Demo2 {
private static SessionFactory sf;
static {
Configuration cf=new Configuration();
cf.configure();
sf=cf.buildSessionFactory();
}
/**
* 主键查询
*/
@Test
public void testGetByKey() {
Session session = sf.openSession();
UserEntity user=(UserEntity) session.get(UserEntity.class, "366cbb16-7cce-4b23-9b5a-bd34a0583d20");
System.out.println(user);
}
4.2 HQL查询(Query对象)
创建Query对象
Query query = session.createQuery("from UserEntity where id=12 ");
设置参数
query.setParameter(0,"xxx");
query.setString(1,"xxx");
设置分页
query.setFirstResult((page-1)*count);//查询的起始行
query.setMaxResults(count);//每页显示的条数
执行
List<UserEntity> list = query.list(); 获取列表
UserEntity user = query.uniqueResult(); 获取唯一结果
Iterator<UserEntity> it = query.iterate();获取迭代器
query.executeUpdate() ; 执行sql语句(hql可以执行增删改操作)
HQL查询与SQL查询区别:
SQL: (结构化查询语句)查询的是表以及字段; 不区分大小写。
HQL: hibernate query language 即hibernate提供的面向对象的查询语言
查询的是对象以及对象的属性。
区分大小写。
这种方式适合没有数据库基础的程序员使用。
4.1.1 基础案例
>>>>>> hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<!-- 通常,一个session-factory节点代表一个数据库 -->
<session-factory >
<!-- 1. 数据库连接配置 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!--
数据库方法配置, hibernate在运行的时候,会根据不同的方言生成符合当前数据库语法的sql
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- 2. 其他相关配置 -->
<!-- 2.1 显示hibernate在运行时候执行的sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 2.2 格式化sql -->
<property name="hibernate.format_sql">false</property>
<!-- 2.3 自动建表 -->
<property name="hibernate.hbm2ddl.auto">create</property>
<!-- 3. 加载所有映射
<mapping resource="org/jsoft/demo/EmpEntity.hbm.xml"/>
-->
</session-factory>
</hibernate-configuration>
public class Demo2 {
private static SessionFactory sf;
static {
Configuration cf=new Configuration();
cf.configure();
sf=cf.buildSessionFactory();
}
/**
* HQL查询
*/
@Test
public void testHQL() {
Session session = sf.openSession();
//查询全部
Query query = session.createQuery("from UserEntity where id=12 ");
List<UserEntity> list = query.list();
System.out.println(list);
}
>>>>>> UserEntity.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.jsoft.f_search" >
<class name="UserEntity" table="t_user">
<id name="id" column="id">
</id>
<!-- 非主键,映射 -->
<property name="age" column="age"></property>
<property name="birth" column="birth" type="java.util.Date"></property>
</class>
</hibernate-mapping>
>>>>>> UserEntity.java
public class UserEntity {
private int id;
private String name;
private int age;
private Date birth;
public int getId() {
return id;
}
public void setId(int 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 Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
}
>>>>>> App.java
public class App {
private static Session session;
static {
SessionFactory sf = new Configuration()
.configure()
.addClass(UserEntity.class)
.buildSessionFactory();
session=sf.openSession();
}
public static void main(String[] args) {
HQL_iterator();
}
/**
* HQL的iterator查询
*/
private static void HQL_iterator() {
session.beginTransaction();
Query qr = session.createQuery(" from UserEntity");
Iterator<UserEntity> it = qr.iterate();
while(it.hasNext()) {
System.out.println(it.next());
}
}
/**
* HQL的list查询
*/
private static void HQL_list() {
session.beginTransaction();
Query qr = session.createQuery(" from UserEntity");
List<UserEntity> list = qr.list();
for(UserEntity u:list) {
System.out.println(u);
}
}
}
4.1.2 HQL语句
HQL是面向对象的查询。其HQL语句也是面向对象的。
如:select * from t_user where t_name='hlp'
创建HQL语句:
Query query = session.createQuery(" from UserEntity where name='hlp' ");
>>>>>> UserEntity.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.jsoft.f_search" >
<class name="UserEntity" table="t_user1">
<id name="id" column="id">
</id>
<!-- 非主键,映射 -->
<property name="name" column="t_nam"></property>
<property name="age" column="t_age"></property>
<property name="birth" column="birth" type="java.util.Date"></property>
</class>
</hibernate-mapping>
>>>>>> App.java
private static void page() {
//hql语句
Query query = session.createQuery(" from UserEntity where name='hlp' ");
int page=1;
int count=4;
//设置分页参数
query.setFirstResult((page-1)*count);//查询的起始行
query.setMaxResults(count);//每页显示的条数
List<UserEntity> list = query.list();
System.out.println(list);
}
4.1.3 条件查询
设置参数从0开始。
/**
* HQL的条件查询.设置参数从0开始
*/
private static void HQL_condititon() {
session.beginTransaction();
Query qr = session.createQuery(" from UserEntity where id=?");
qr.setParameter(0, 1);
List<UserEntity> list = qr.list();
System.out.println(list);
}
4.1.4 分页查询
/**
* 分页查询
*/
private static void page() {
Query query = session.createQuery(" from UserEntity ");
int page=1;
int count=4;
//设置分页参数
query.setFirstResult((page-1)*count);//查询的起始行
query.setMaxResults(count);//每页显示的条数
List<UserEntity> list = query.list();
System.out.println(list);
}
4.3 Criteria查询(完全面向对象的查询)
创建Criteria 对象
Criteria criteria = session.createCriteria(UserEntity.class);
设置参数
criteria.add(Restrictions.eq("id", "12"));
执行
List<UserEntity> list = criteria.list(); 获取列表
UserEntity user = criteria.uniqueResult(); 获取唯一结果
本地SQL查询:
完全面向对象的查询。
这种方式适合有数据库基础的程序员使用。
public class Demo2 {
private static SessionFactory sf;
static {
Configuration cf=new Configuration();
cf.configure();
sf=cf.buildSessionFactory();
}
/**
* Criterial查询
*/
@Test
public void testCriterial() {
Session session = sf.openSession();
Criteria criteria = session.createCriteria(UserEntity.class);
criteria.add(Restrictions.eq("id", "12"));
List<UserEntity> list = criteria.list();
System.out.println(list);
}
4.4 原生SQL查询(SqlQuery对象 - 本地SQL查询)
创建SQLQuery 对象
SQLQuery sqlQuery = session.createSQLQuery("select * from user");
设置参数
sqlQuery .setParameter(0,"xxx");
sqlQuery .setString(1,"xxx");
设置分页
sqlQuery .setFirstResult((page-1)*count);//查询的起始行
sqlQuery .setMaxResults(count);//每页显示的条数
执行
List<UserEntity> list = sqlQuery .list(); 获取列表
UserEntity user = sqlQuery .uniqueResult(); 获取唯一结果
Iterator<UserEntity> it = sqlQuery .iterate();获取迭代器
sqlQuery .executeUpdate() ; 执行sql语句(可以执行增删改操作)
复杂的查询,就要使用原生态的sql查询,也可以,就是本地sql查询的支持!
(缺点: 不能跨数据库平台!)
public class Demo2 {
private static SessionFactory sf;
static {
Configuration cf=new Configuration();
cf.configure();
sf=cf.buildSessionFactory();
}
/**
* 原生SQL查询
*/
@Test
public void testSql() {
Session session = sf.openSession();
SQLQuery sqlQuery = session.createSQLQuery("select * from user");
sqlQuery.addEntity(UserEntity.class);
List<UserEntity> list = sqlQuery.list();
System.out.println(list);
}
}
五、Session对象API - 查询操作,细节分析
5.1 list 查询和 iterator 查询的区别
5.1.1 HQL查询、Criteial查询、本地sql查询对这个方法是否支持
1.HQL查询 -- list()
iterator()
uniqueResult()
2.Criterial查询 -- list()
uniqueResult()
3.本地SQL查询 -- list()
iterator()
uniqueResult()
public static void main(String[] args) {
// ---------------> 1.HQL
//list查询
Query qr = session.createQuery(" from UserEntity ");
List<ProjectEntity> list = qr.list();
System.out.println(list);
//iterator
Iterator iterate = qr.iterate();
// ---------------> 2.Criteal
Criteria ct = session.createCriteria(UserEntity.class);
List<ProjectEntity> list2 = ct.list();
System.out.println(list2);
//iterator ==== Criteal没有iterator方法
// ---------------> 3.原生sql
SQLQuery sql = session.createSQLQuery("from t_user");
List<ProjectEntity> list3 = sql.list();
System.out.println(list3);
//iterator
Iterator iterate3 = sql.iterate();
}
5.1.2 list查询 和iterator的区别
>>>>>> 一次查询与多次查询
list与iterator查询的区别?
list()
一次把所有的记录都查询出来,
会放入缓存,但不会从缓存中获取数据
Iterator()
N+1查询; N表示所有的记录总数
即会先发送一条语句查询所有记录的主键(1),
再根据每一个主键再去数据库查询(N)!
会放入缓存,也会从缓存中取数据!
- 案例1
public static void main(String[] args) {
session.beginTransaction();
Query qr = session.createQuery("from ProjectEntity");
List<ProjectEntity> list = qr.list();
for(ProjectEntity p:list) {
System.out.println(p.getpId()+" "+p.getpName());
}
session.close();
}
2. 案例2
public static void main(String[] args) {
session.beginTransaction();
Query qr = session.createQuery("from ProjectEntity");
Iterator<ProjectEntity> it = qr.iterate();
while(it.hasNext()) {
ProjectEntity p = it.next();
System.out.println(p.getpId()+" "+p.getpName());
}
session.close();
}
>>>>>> 是否放入缓存、是否从缓存取数据
list查询过程:
只会生成一条sql。
它会将查询的数据放入缓存中,但不会从缓存中取数据。
iterator查询过程:
首先会生成一条sql查询符合条件的数据ID。
然后根据迭代器,即 it.next()。通过ID一条条查询。
它会从缓存中数据,也会将数据放入到缓存缓存中。
public static void main(String[] args) {
session.beginTransaction();
//第一次
Query qr = session.createQuery("from ProjectEntity");
List<ProjectEntity> list = qr.list();
for(ProjectEntity p:list) {
System.out.println(p.getpId()+" "+p.getpName());
}
System.out.println("======");
//第二次
Query qr2 = session.createQuery("from ProjectEntity");
List<ProjectEntity> list2 = qr2.list();
for(ProjectEntity p:list2) {
System.out.println(p.getpId()+" "+p.getpName());
}
session.close();
}
iterator查询会从缓存中取数据
public static void main(String[] args) {
session.beginTransaction();
//第一次
Query qr = session.createQuery("from ProjectEntity");
Iterator<ProjectEntity> it = qr.iterate();
while(it.hasNext()) {
ProjectEntity p = it.next();
System.out.println(p.getpId()+" "+p.getpName());
}
System.out.println("======");
//第二次
Query qr2 = session.createQuery("from ProjectEntity");
Iterator<ProjectEntity> it2 = qr.iterate();
while(it2.hasNext()) {
ProjectEntity p = it2.next();
System.out.println(p.getpId()+" "+p.getpName());
}
session.close();
}
5.2 get查询和load查询的区别
1.get会立即加载对象。返回的是类本身。
2.load不会。只是去使用的时候才会执行查询语句。返回的是一个代理对象。代理对象就是别人让你做一件事。先答应下来。然后他需要的时候去帮他做。
===> get立即检索。load延迟检索。
public void testGet(){
News news =(News) session.get(News.class, 1);
System.out.println(news);
}
@org.junit.Test
public void testLoad(){
News news =(News) session.load(News.class, 1);
System.out.println(news);
}
>>>>>> get立即检索。load延迟检索
@org.junit.Test
public void testGet(){
News news =(News) session.get(News.class, 1);
// System.out.println(news);
}
@org.junit.Test
public void testLoad(){
News news =(News) session.load(News.class, 1);
// System.out.println(news);
}
get方法会有查询语句。load方法不会执行查询语句。
>>>>>> get直接获取对象。load延迟获取的是代理对象
@org.junit.Test
public void testGet(){
News news =(News) session.get(News.class, 1);
System.out.println(news.getClass());
// System.out.println(news);
}
@org.junit.Test
public void testLoad(){
News news =(News) session.load(News.class, 1);
System.out.println(news.getClass());
// System.out.println(news);
}
>>>>>> session关闭后,第一次打开load查询的对象会报错
load可能抛出一个 LazyInitializationException 异常: could not initialize proxy - no Session
因为get是先加载。然后会打印出来。 load是答应了别人。
别人需要了去帮他做的时候。发现session已经关闭了。
然后抛出一个懒加载异常。
@org.junit.Test
public void testGet(){
News news =(News) session.get(News.class, 1);
session.close();
System.out.println(news);
}
@org.junit.Test
public void testLoad(){
News news =(News) session.load(News.class, 1);
session.close();
System.out.println(news);
}
get会打印出来。load抛出一个懒加载异常。
>>>>>> 查询数据库中没有的对象。get返回一个null。load会抛出一个ObjectNotFoundException 异常
@org.junit.Test
public void testGet(){
News news =(News) session.get(News.class, 10);
System.out.println(news);
}
@org.junit.Test
public void testLoad(){
News news =(News) session.load(News.class, 10);
System.out.println(news);
}
5.3 查询区别
+++ Hibernate查询支持以下几种方式:
1.主键查询
2.HQL查询
3.Criterial查询
4.原生SQL查询。
+++ HQL查询与SQL查询的区别?
HQL查询查询的是对象以及属性,HQL语句区分大小写
SQL查询查询的是数据库表以及字段,不区分大小写。
+++ HQL查询和Criterial查询的区别?
HQL查询适合具有数据库经验的开发者使用。
Criterial是完全面向对象的,适合不具备数据库经验的开发者使用。
+++ 原生SQL查询与非原生SQL查询的优缺点?
原生SQL查询:
1.可以查询复杂的SQL语句。
2.不能跨数据库,
即如果底层的数据库切换了,sql语句还需要作出相应的变化。
非原生SQL查询(主键查询/HQL查询/Criterial查询):
1.不能查询复杂的SQL语句。
2.可以跨数据库。
非原生SQL查询,底层是有Hibernate生成的SQL语句,
如果底层切换了数据库,代码不需要改变。
用户只需配置数据库方言即可。
六、懒加载
6.1 get和load的区别
get :及时加载。只要调用get方法立刻向数据库查询。
load:默认使用懒加载,当用到数据时才向数据库查询。
>>>>>> get查询
hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<!-- 通常,一个session-factory节点代表一个数据库 -->
<session-factory >
<!-- 1. 数据库连接配置 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!--
数据库方法配置, hibernate在运行的时候,会根据不同的方言生成符合当前数据库语法的sql
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- 2. 其他相关配置 -->
<!-- 2.1 显示hibernate在运行时候执行的sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 2.2 格式化sql -->
<property name="hibernate.format_sql">false</property>
<!-- 2.3 自动建表 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 3. 加载所有映射
<mapping resource="org/jsoft/demo/EmpEntity.hbm.xml"/>
-->
</session-factory>
</hibernate-configuration>
Person.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.jsoft.h_lazy" >
<class name="Person" table="t_p">
<id name="id" column="id">
</id>
<!-- 非主键,映射 -->
<property name="name" column="name"></property>
<property name="age" column="age"></property>
</class>
</hibernate-mapping>
App.java
public class App {
private static SessionFactory sf;
static {
sf=new Configuration().configure()
.addClass(Person.class)
.buildSessionFactory();
}
public static void get() {
Session sesison = sf.openSession();
Person p=(Person) sesison.get(Person.class, 12);
}
}
>>>>>> load查询
hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<!-- 通常,一个session-factory节点代表一个数据库 -->
<session-factory >
<!-- 1. 数据库连接配置 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!--
数据库方法配置, hibernate在运行的时候,会根据不同的方言生成符合当前数据库语法的sql
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- 2. 其他相关配置 -->
<!-- 2.1 显示hibernate在运行时候执行的sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 2.2 格式化sql -->
<property name="hibernate.format_sql">false</property>
<!-- 2.3 自动建表 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 3. 加载所有映射
<mapping resource="org/jsoft/demo/EmpEntity.hbm.xml"/>
-->
</session-factory>
</hibernate-configuration>
Person.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.jsoft.h_lazy" >
<class name="Person" table="t_p">
<id name="id" column="id">
</id>
<!-- 非主键,映射 -->
<property name="name" column="name"></property>
<property name="age" column="age"></property>
</class>
</hibernate-mapping>
App.java
public class App {
private static SessionFactory sf;
static {
sf=new Configuration().configure()
.addClass(Person.class)
.buildSessionFactory();
}
@Test
public static void load() {
Session session = sf.openSession();
Person p=(Person) session.load(Person.class, 12);
System.out.println(p);
}
}
6.2 懒加载
概念:当用到数据的时候,才会总数据库查询。。否则不会查询数据库。
目的:提高程序执行效率。
实际意义:在项目中,我们如果使用hibernate作为底层。
由于映射配置较多,当我们查询一个简单实体数据时,结果把简单实体映射的其他关联数据也查询出来了。这样肯定是浪费资源。
所以懒加载的最终意义是在于集合映射时的懒加载。
6.2.1 懒加载异常
1. Session关闭后,不能使用懒加载数据!
2. 如果session关闭后,使用懒加载数据报错:
org.hibernate.LazyInitializationException: could not initialize
proxy - no Session
>>>>>> 懒加载异常:实例代码,运行报错
@Test
public static void load() {
Session session = sf.openSession();
Person p=(Person) session.load(Person.class, 12);
session.close();
System.out.println(p);
}
>>>>>> 懒加载异常解决方式
如何解决session关闭后不能使用懒加载数据的问题?
方式1: 先使用一下数据
dept.getDeptName();
方式2:强迫代理对象初始化
Hibernate.initialize(dept);
方式3:关闭懒加载
设置lazy=false;
方式4: 在使用数据之后,再关闭session!
6.2.2 懒加载的使用与配置
lazy 值
false 关闭懒加载
true 使用懒加载
extra 使用懒加载,比true更智能。
(在集合数据懒加载时候提升效率)
在真正使用数据的时候才向数据库发送查询的sql;
如果调用集合的size()/isEmpty()方法,
只是统计,不真正查询数据!
配置示范:
<class name="Dept" table="l_dept" lazy="true">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<!-- 非主键,映射 -->
<property name="name" column="name"></property>
<set name="emps" table="l_emp" lazy="true">
<key column="deptId"></key>
<!-- 映射外键表。class指定外键表对应的java类型。由于package指定了包,所以可以简写类名。否则,写完整类名 -->
<one-to-many class="Emp"></one-to-many>
</set>
</class>
>>>>>> 懒加载配置
集合标签(Set标签、List标签等都可以)可以配置懒加载:
<set name="emps" table="l_emp" lazy="true">
<key column="deptId"></key>
<!-- 映射外键表。class指定外键表对应的java类型。由于package指定了包,所以可以简写类名。否则,写完整类名 -->
<one-to-many class="Emp"></one-to-many>
</set>
多对一标签可以配置懒加载:
<many-to-one name="dept" column="deptId" class="Dept" lazy="true"></many-to-one>
>>>>>> 所有配置的映射默认为lazy = true
基本映射配置和集合属性映射配置,都默认lazy =true。
hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<!-- 通常,一个session-factory节点代表一个数据库 -->
<session-factory >
<!-- 1. 数据库连接配置 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!--
数据库方法配置, hibernate在运行的时候,会根据不同的方言生成符合当前数据库语法的sql
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- 2. 其他相关配置 -->
<!-- 2.1 显示hibernate在运行时候执行的sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 2.2 格式化sql -->
<property name="hibernate.format_sql">false</property>
<!-- 2.3 自动建表 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 3. 加载所有映射
<mapping resource="org/jsoft/demo/EmpEntity.hbm.xml"/>
-->
</session-factory>
</hibernate-configuration>
Emp.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.jsoft.h_lazy2" >
<class name="Emp" table="l_emp" >
<id name="id" column="id">
<generator class="native"></generator>
</id>
<!-- 非主键,映射 -->
<property name="name" column="name"></property>
<property name="age" column="age"></property>
<many-to-one name="dept" column="deptId" class="Dept" lazy="true"></many-to-one>
</class>
</hibernate-mapping>
Dept.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.jsoft.h_lazy2" >
<class name="Dept" table="l_dept" lazy="true">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<!-- 非主键,映射 -->
<property name="name" column="name"></property>
<set name="emps" table="l_emp" lazy="true">
<key column="deptId"></key>
<!-- 映射外键表。class指定外键表对应的java类型。由于package指定了包,所以可以简写类名。否则,写完整类名 -->
<one-to-many class="Emp"></one-to-many>
</set>
</class>
</hibernate-mapping>
实体类
public class Emp {
private int id;
private String name;
private int age;
private Dept dept;
}
public class Dept {
private int id;
private String name;
private Set<Emp> emps;
}
App.java
public class App {
private static SessionFactory sf;
static {
sf=new Configuration().configure()
.addClass(Person.class)
.buildSessionFactory();
}
@Test
public static void load() {
Session session = sf.openSession();
Person p=(Person) session.load(Person.class, 12);
System.out.println(p);
}
}
>>>>>> 集合映射,默认为懒加载。在获取映射数据时,集合数据默认为懒加载数据。即如果不使用,则不会查询。
+++ 没有使用集合数据,只生成一条sql
public class App {
private static SessionFactory sf;
static {
sf=new Configuration().configure()
.addClass(Emp.class)
.addClass(Dept.class)
.buildSessionFactory();
}
public static void main(String[] args) {
Session session = sf.openSession();
//虽然配置了集合映射,但是由于没有使用集合数据。即使是get查询,
//也不会主动查询集合数据。
Dept dept=(Dept) session.get(Dept.class, 1);
System.out.println(dept.getName());
}
}
+++ 使用集合数据,生成两条sql
public class App {
private static SessionFactory sf;
static {
sf=new Configuration().configure()
.addClass(Emp.class)
.addClass(Dept.class)
.buildSessionFactory();
}
public static void main(String[] args) {
Session session = sf.openSession();
Dept dept=(Dept) session.get(Dept.class, 1);
System.out.println(dept.getEmps());
}
}
>>>>>> 集合映射,默认为懒加载。当设置为lazy=extra时,也是懒加载,只不过比lazy=true更高级。
extra 使用懒加载,比true更智能。
(在集合数据懒加载时候提升效率)
在真正使用数据的时候才向数据库发送查询的sql;
如果调用集合的size()/isEmpty()方法,
只是统计,不真正查询数据!
+++ lazy=true。调用集合的size()/isEmpty()方法,都会查询数据明细。
Dept.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.jsoft.h_lazy2" >
<class name="Dept" table="l_dept" >
<id name="id" column="id">
<generator class="native"></generator>
</id>
<!-- 非主键,映射 -->
<property name="name" column="name"></property>
<set name="emps" table="l_emp" lazy="true">
<key column="deptId"></key>
<!-- 映射外键表。class指定外键表对应的java类型。由于package指定了包,所以可以简写类名。否则,写完整类名 -->
<one-to-many class="Emp"></one-to-many>
</set>
</class>
</hibernate-mapping>
App.java
public class App {
private static SessionFactory sf;
static {
sf=new Configuration().configure()
.addClass(Emp.class)
.addClass(Dept.class)
.buildSessionFactory();
}
public static void main(String[] args) {
Session session = sf.openSession();
Dept dept=(Dept) session.get(Dept.class, 1);
System.out.println(dept.getEmps().isEmpty());
}
}
+++ lazy=extra。调用集合的size()/isEmpty()方法,不会查询数据,而是对数据统计。
Dept.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.jsoft.h_lazy2" >
<class name="Dept" table="l_dept" >
<id name="id" column="id">
<generator class="native"></generator>
</id>
<!-- 非主键,映射 -->
<property name="name" column="name"></property>
<set name="emps" table="l_emp" lazy="true">
<key column="deptId"></key>
<!-- 映射外键表。class指定外键表对应的java类型。由于package指定了包,所以可以简写类名。否则,写完整类名 -->
<one-to-many class="Emp"></one-to-many>
</set>
</class>
</hibernate-mapping>
App.java
public class App {
private static SessionFactory sf;
static {
sf=new Configuration().configure()
.addClass(Emp.class)
.addClass(Dept.class)
.buildSessionFactory();
}
public static void main(String[] args) {
Session session = sf.openSession();
Dept dept=(Dept) session.get(Dept.class, 1);
System.out.println(dept.getEmps().isEmpty());
}
}
6.3 懒加载的作用
在实际开发过程中,我们都是一个对象关联另外一个对象,如果我们查询一个对象时,把其他对象也查询出来,肯定是影响效率的,所以HIbnernate引入了懒加载特性。
六、其他细节
4.1 拼接SQL,设置参数(从0开始)
public List<UserEntity> findByName(String name) {
Session session =null;
Transaction tr=null;
try {
session = HibernateUtils.getSession();
tr = session.beginTransaction();
Query query = session.createQuery("from UserEntity where name=?");
query.setParameter(0, name);
return query.list();
} catch (HibernateException e) {
e.printStackTrace();
}finally {
tr.commit();
session.close();
}
return null;
}
4.2 分页
public List<UserEntity> getAllByPage(int page,int count) {
Session session =null;
Transaction tr=null;
try {
session = HibernateUtils.getSession();
tr = session.beginTransaction();
Query query = session.createQuery("from UserEntity ");
//设置分页参数
query.setFirstResult((page-1)*count);//查询的起始行
query.setMaxResults(count);//每页显示的条数
return query.list();
} catch (HibernateException e) {
e.printStackTrace();
}finally {
tr.commit();
session.close();
}
return null;
}
4.3 hibernate的一级缓存特性
4.3.1 只有当事务提交或者session关闭时,才会生成sql语句并执行。
4.3.2 只有当事务被提交,执行的sql语句才会被持久化到数据库。
4.3.3 保存方法会直接生成一条sql语句。但是修改方法会累加,只会生成一条sql。
七、CRUD 模板代码 – 综合案例
UserEntity.java
public class UserEntity {
private String id;
private String name;
private Date birth;
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 Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
@Override
public String toString() {
return "UserEntity [id=" + id + ", name=" + name + ", birth=" + birth + "]";
}
}
src/hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<!-- 通常,一个session-factory节点代表一个数据库 -->
<session-factory>
<!-- 1. 数据库连接配置 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/jsoft</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!--
数据库方法配置, hibernate在运行的时候,会根据不同的方言生成符合当前数据库语法的sql
-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- 2. 其他相关配置 -->
<!-- 2.1 显示hibernate在运行时候执行的sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 2.2 格式化sql -->
<property name="hibernate.format_sql">true</property>
<!-- 2.3 自动建表 -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 3. 加载所有映射 -->
<mapping resource="UserEntity.hbm.xml"/>
</session-factory>
</hibernate-configuration>
src/org/jsoft/demo/UserEntity.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.jsoft.demo">
<class name="UserEntity" table="USER">
<!-- 主键 ,映射 -->
<id name="id" column="u_id">
</id>
<!-- 非主键,映射 -->
<property name="name" column="u_name"></property>
<property name="birth" column="u_birth"></property>
</class>
</hibernate-mapping>
HibernateUtils.java (工具类)
public class HibernateUtils {
private static SessionFactory sf;
static {
Configuration cf=new Configuration();
cf.configure();
sf = cf.buildSessionFactory();
}
/**
* 获取Sessio
* @return
*/
public static Session getSession() {
return sf.openSession();
}
}
UserDao.java(CRUD)
public class UserDao {
public void save(UserEntity user) {
Session session =null;
Transaction tr=null;
try {
session = HibernateUtils.getSession();
tr = session.beginTransaction();
session.save(user);
} catch (HibernateException e) {
e.printStackTrace();
}finally {
tr.commit();
session.close();
}
}
public void delete(Serializable id) {
Session session =null;
Transaction tr=null;
try {
session = HibernateUtils.getSession();
tr = session.beginTransaction();
UserEntity user=(UserEntity) session.get(UserEntity.class, id);
if(user!=null) {
session.delete(user);
}
} catch (HibernateException e) {
e.printStackTrace();
}finally {
tr.commit();
session.close();
}
}
public void update(UserEntity user) {
Session session =null;
Transaction tr=null;
try {
session = HibernateUtils.getSession();
tr = session.beginTransaction();
session.update(user);
} catch (HibernateException e) {
e.printStackTrace();
}finally {
tr.commit();
session.close();
}
}
public UserEntity findById(String id) {
Session session =null;
Transaction tr=null;
try {
session = HibernateUtils.getSession();
tr = session.beginTransaction();
return (UserEntity) session.get(UserEntity.class, id);
} catch (HibernateException e) {
e.printStackTrace();
}finally {
tr.commit();
session.close();
}
return null;
}
public List<UserEntity> getAll() {
Session session =null;
Transaction tr=null;
try {
session = HibernateUtils.getSession();
tr = session.beginTransaction();
Query query = session.createQuery("from UserEntity");
return query.list();
} catch (HibernateException e) {
e.printStackTrace();
}finally {
tr.commit();
session.close();
}
return null;
}
public List<UserEntity> getAllByPage(int page,int count) {
Session session =null;
Transaction tr=null;
try {
session = HibernateUtils.getSession();
tr = session.beginTransaction();
Query query = session.createQuery("from UserEntity ");
//设置分页参数
query.setFirstResult((page-1)*count);//查询的起始行
query.setMaxResults(count);//每页显示的条数
return query.list();
} catch (HibernateException e) {
e.printStackTrace();
}finally {
tr.commit();
session.close();
}
return null;
}
public List<UserEntity> findByName(String name) {
Session session =null;
Transaction tr=null;
try {
session = HibernateUtils.getSession();
tr = session.beginTransaction();
Query query = session.createQuery("from UserEntity where name=?");
query.setParameter(0, name);
return query.list();
} catch (HibernateException e) {
e.printStackTrace();
}finally {
tr.commit();
session.close();
}
return null;
}
public List<UserEntity> findByDate(Date date) {
Session session =null;
Transaction tr=null;
try {
session = HibernateUtils.getSession();
tr = session.beginTransaction();
Query query = session.createQuery("from UserEntity where birth > ?");
query.setParameter(0, date.toString());
return query.list();
} catch (HibernateException e) {
e.printStackTrace();
}finally {
tr.commit();
session.close();
}
return null;
}
@Test
public void testAll() {
List<UserEntity> findByDate = findByDate(new Date());
System.out.println(findByDate);
}
}
八、hibernate中数据操作层的优美写法(管道式编程)
hibernate中的对象通常是以管道的形式设计的。
public class EmpDao {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
/**
* 新增
* @param empEntity
*/
public void save(EmpEntity empEntity) {
sessionFactory.getCurrentSession().save(empEntity);
}
/**
* 修改
* @param empEntity
*/
public void update(EmpEntity empEntity) {
sessionFactory.getCurrentSession().update(empEntity);
}
/**
* 删除
* @param emp
*/
public void delete(int id) {
sessionFactory.getCurrentSession().createQuery("delete from EmpEntity where id=?")
.setParameter(0, id)
.executeUpdate();
}
public EmpEntity findById(int id){
return (EmpEntity) sessionFactory.getCurrentSession().get(EmpEntity.class, id);
}
}