Hibernate开发步骤
1.导入Hibernate开发包中lib文件夹中required下的所有jar包
2.在src根目录建立hibernate主配置文件,hibernate.cfg.xml,cfg:configuration配置。
主配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<!--导入标签库:在Hibernate核心开发包中hibernate-configuration-3.0.dtd中-->
<!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:要配置的位置在:
hibernate解压缩后的文件/project/etc/hibernate.properties -->
<session-factory>
<!-- 数据库连接参数 -->
<!-- 使用property标签对SessionFactory属性进行配置 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 连接本地mysql可以省略地址 -->
<property name="hibernate.connection.url">jdbc:mysql:///servletdb</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">1234</property>
<!--配置currentSession:当前线程对应session-->
<propertyname="hibernate.current_session_context_class">thread</property>
<!-- hibernate自动生成sql,将sql展示出来 -->
<property name="show_sql">true</property>
<!-- 对sql格式化输出,将sql变美观 -->
<property name="hibernate.format_sql">true</property>
<!-- 配置hibernate方言:hibernate.dialect
因为Hibernate无需编写sql,但其底层需要把代码翻译成sql;方言也就是告知hibernate以何种sql语句进行翻译-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 配置hibernate映射文件地址,映射文件是实体类和数据库表中对应的表的配置。 -->
<mapping resource="entity/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
hibernate中的session相当于Connection,一个Session表示和数据库的一次会话。
Sessionfactory:创建session的一个工厂类,相当于DriverManager
3.编写实体类
4.编写实体映射文件:描述表和实体类之间的映射关系
一个表对应一个Java类,hbm:hibernate mapping
命名:类名.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>
<!-- 配置User类和t_user之间的映射关系
name:全限定名 -->
<class name="entity.User" table="t_user">
<!-- 配置字段名和属性名之间的映射关系
先配置主键
name:属性名
column:列名 -->
<id name="userId" column="user_id">
<!-- generator:配置主键生成策略
identity:自增mysql
sequence:序列oracle/DB2
uuid:32位全球唯一字符串
increment:自增,不建议使用
native:由hibernate生成主键,不建议使用
assigned:由程序生成主键
-->
<generator class="identity"/>
</id>
<!-- 使用property对普通列配置 -->
<property name="userName" column="user_name"/>
<property name="password" column="password"/>
<property name="age" column="age"/>
</class>
</hibernate-mapping>
5.在hibernate主配置文件中添加映射文件路径
6.编写代码
Hibernate对象状态:
三态:
初始态(Virgin):刚new出的对象 User user = new User();
初始态对象和hibernate无关联
持久态:调用hibernate save() update() load() get() Query对象的方法 等API时,对象会由初始态---->持久态
持久态的对象会被session进行管理,也就是和数据库建立了直接关联
游离态(处理后的状态):失去了session管理的对象
注意:
1.游离态对象仍然存在,等待被GC(Garbage Collection)垃圾回收线程回收
2.游离态对象有OID,主键值
3.游离态对象可以重新回到持久态 saveOrUpdate(Object)
Hibernate简单API
public class TestCRUD {
private SessionFactory sf;
@Before
public void testSessionFactory(){
//1.加载hibernate.cfg.xml
//默认加载src下根目录下的hibernate.cfg.xml
//为一个Configuration对象
Configuration cfg = new Configuration().configure();
//2.通过Configuration创建SessionFactory
sf = cfg.buildSessionFactory();
}
@Test
public void testAdd(){
//2.通过SessionFactory获取Session
Session session = sf.openSession();
//3.开启事务,hibernate默认不会自动提交事务
Transaction tx = session.beginTransaction();
//4.调用hibernateAPI完成CRUD
User user = new User();
user.setUserName("ss");
user.setPassword("ss");
user.setAge(10);
//session.save(Object):把该Java对象入库
session.save(user);
//5.操纵完毕后提交事务
tx.commit();
//6.关闭Session
session.close();
}
@Test
public void testDelete(){
//hibernate默认按主键删除,对象主键属性必须有值
Session session = sf.openSession();
Transaction tx = session.beginTransaction();
User user = new User();
user.setUserId(5);
//session.delete(Object):删除该对象对应的数据库记录
session.delete(user);
tx.commit();
session.close();
}
@Test
public void testQuery(){
//按主键查询:get/load
//使用openSession查询可以不开启事务
Session session = sf.openSession();
//session.get(类对象,主键值)
User user = session.load(User.class, 11);
System.out.println(user);
session.close();
}
@Test
public void testUpdate(){
//先查后改
Session session = sf.openSession();
Transaction tx = session.beginTransaction();
//查出一个User
User user = session.load(User.class, 11);
user.setUserName("GayP");
// session.update(user);
tx.commit();
session.close();
}
}
session.get/load(类对象,主键值)
get/load的区别:
1.get是立即加载,使用get会立刻向数据库发送sql语句
load是延迟加载,在调用对象的方法或者属性前不发送sql,当调用对象的方法或者属性时才发送sql
2.get不存在的主键,返回值为null
load会抛出ObjectNotFoundException
复杂查询:
1.按ID查:get/load
2.使用HQL进行查询
Hibernate Query Language:HQL
HQL是一种类SQL语句:
1.HQL没有表的概念,表名统一替换为类名
2.HQL没有列的概念,列名统一替换属性名
3.无select * from 类名:
from 类名 查询所有列
一个应用一般只需要一个SessionFactory
封装HibernateUtil工具类实现SessionFactory单例
先实现一个HibernateUtil类,并测试Query对象
public class HibernateUtil {
private static Configuration cfg;
private static SessionFactory sf;
//事务写成共有的,外界需要用
public static Transaction tx;
static{
cfg = new Configuration().configure();
sf = cfg.buildSessionFactory();
}
/**
* 获取Session对象
*/
public static Session getSession(){
Session session = sf.openSession();
tx = session.beginTransaction();
return session;
}
}
public class TestQuery {
@Test
public void testAllUser(){
Session session = HibernateUtil.getSession();
//1.编写HQL
String hql = "from User where userName =:username"
+ " and password =:password";
//2.通过session创建Query对象并传入HQL语句
Query query = session.createQuery(hql);
//3.调用Query对象的API完成查询
query.setParameter("username", "GayP");
query.setParameter("password", "ooxx1");
List<User> users = query.list();
System.out.println(users==null);
System.out.println(users.isEmpty());
for (User user : users) {
System.out.println(user);
System.out.println("-----------");
}
HibernateUtil.tx.commit();
session.close();
}
@Test
public void testFindAllUser2(){
Session session = HibernateUtil.getSession();
//1.编写HQL
String hql = "from User";
//2.通过HQL创建Query对象
Query query = session.createQuery(hql);
Iterator<User> it = query.iterate();
while(it.hasNext()){
User user = it.next();
System.out.println(user);
System.out.println("-----------");
}
}
@Test
public void testQueryUserByName(){
Session session = HibernateUtil.getSession();
String hql = "from User where userName = ?";
Query query = session.createQuery(hql);
//给占位符赋值
//注意HQL占位符从0开头
query.setParameter(0, "GayP");
//注意:返回值为单行记录才能使用uniqueResult()
//uniqueResult():Object
User user = (User) query.uniqueResult();
System.out.println(user);
HibernateUtil.tx.commit();
session.close();
}
@Test
public void testQueryUserByName2(){
Session session = HibernateUtil.getSession();
String hql = "from User where userName =:username"
+ " and password =:password";
Query query = session.createQuery(hql);
//给占位符赋值
query.setParameter("username", "GayP");
query.setParameter("password", "ooxx");
//注意:返回值为单行记录才能使用uniqueResult()
//uniqueResult():Object
User user = (User) query.uniqueResult();
System.out.println(user);
HibernateUtil.tx.commit();
session.close();
}
@Test
public void testQueryUserByName3(){
Session session = HibernateUtil.getSession();
String hql = "from User where userName =:username"
+ " and password =:password";
Query query = session.createQuery(hql);
//把参数封装为一个map:
//key:参数名
//value:参数值
Map<String, Object> parameters =
new HashMap<String,Object>();
parameters.put("username", "GayP");
parameters.put("password", "ooxx");
//给占位符赋值
query.setProperties(parameters);
//注意:返回值为单行记录才能使用uniqueResult()
//uniqueResult():Object
User user = (User) query.uniqueResult();
System.out.println(user);
HibernateUtil.tx.commit();
session.close();
}
@Test
public void testQueryUserByName4(){
Session session = HibernateUtil.getSession();
String hql = "from User where userName =:username"
+ " and password =:password";
Query query = session.createQuery(hql);
//把参数封装为一个JavaBean:
UserQueryBean qb = new UserQueryBean();
qb.setUsername("GayP");
qb.setPassword("ooxx");
//给占位符赋值
query.setProperties(qb);
//注意:返回值为单行记录才能使用uniqueResult()
//uniqueResult():Object
User user = (User) query.uniqueResult();
System.out.println(user);
HibernateUtil.tx.commit();
session.close();
}
//投影查询1:封装为JavaBean
@Test
public void testHeadHard1(){
Session session = HibernateUtil.getSession();
String hql = "select new entity.User(userName,password)"
+ " from User";
List<User> users = session.createQuery(hql).list();
for (User user : users) {
System.out.println(user);
System.out.println("----------");
}
HibernateUtil.tx.commit();
session.close();
}
@Test
public void testHeadHard2(){
Session session = HibernateUtil.getSession();
String hql = "select new Map(userName,password) from User";
//查询一行结果对应一个Map
//多个Map的集合就是一个List
List<Map<String, Object>> result =
session.createQuery(hql).list();
for (Map<String, Object> map : result) {
//遍历Map
for (Entry<String, Object> entry : map.entrySet()) {
System.out.println(entry.getKey() + ":"
+ entry.getValue());
}
//内层循环走完,一行遍历结束
System.out.println("-------------");
}
HibernateUtil.tx.commit();
session.close();
}
}
如何给hql中的占位符赋值:
参数较少时
1.query.setParameter(“参数名”,参数值);
参数较多时
2.把参数封装成Map
query.setProperties(map);
3.把参数封装为一个JavaBean
query.setProperties(Java对象);
投影查询
查询部分列:
1.select new entity.User(userName,password) from User
把查询结果封装成JavaBean
注意:该类中必须有相应的构造
2.select new Map(属性名1,属性名2…) from 类名
把查询结果封装成Map
Map的key是下标,value就是属性值
3.hql:select 属性名1,属性名2… from 类名
使用Object[]封装查询结果:
一行记录对应一个Object[],多行记录对应一个List<Object[]>
注意:只能封装查询结果,无法查询属性名或下标。
openSession和getCurrentSession的区别
1.openSession无需配置getCurrentSession需要配置
在主配置文件中添加 <propertyname=“hibernate.current_session_context_class”>thread
current:当前线程
一个事务对应一个线程 当前事务
CurrentSession:线程绑定session
1.当前事务对应的session
2.一个事务对应一个session
事务结束:commiy rollback
session对象自动销毁(不需要再调用session.close();方法)
3.CurrentSession在事务结束后,无需也不能close该session
注意:
CurrentSession是和事务绑定的,没有事务也就没有session
获取CurrentSession必须开启事务
openSession无需开启事务
4.CurrentSession是线程安全的
openSession是线程非安全的,有可能产生线程并发问题
加载方式
一.延迟加载的概念
当Hibernate从数据库中加载某个对象时,不加载关联的对象,
只是生成了代理对象,获取使用session中的load的方法(在没有
改变lazy属性为false的情况下)获取到的也是代理对象,所以在上
面这几种场景下就是延迟加载。
二.立即加载的概念
当Hibernate从数据库中加载某个对象时,加载关联的对象,
生成的实际对象,获取使用session中的get的方法获取到的是实际对象。
三.为什么要使用延迟加载
延迟加载策略能避免加载应用程序不需要访问的关联对象,以提高
应用程序的性能。
四.立即加载的缺点 Hibernate在查询某个对象时,立即查询与之关联的对象,我们
可以看出这种加载策略存在两大不足
1.select的语句数目太多,需要频繁的访问数据库,会影响查询的性能。
2.在应用程序只需要访问要的对象,而不需要访问与他关联的对象
的场景下,加载与之关联的对象完全是多余的操作,这些多余的操
作是会占内存,这就造成了内存空间的浪费。
Hibernate在对象-关系映射问价中配置加载策略(以文件形式映射)
I.类级别:
元素中lazy属性的可选值为true(延迟加载)和false(立即加载);
元素中的lazy属性的默认值为true
II.一对多关联级别:
元素中的lazy属性的可选值为:true(延迟加载),extra(增强延迟加载)和false(立即加载);
元素中的lazy属性的默认值为true
III.多对一关联级别:
元素中lazy属性的可选值为:proxy(延迟加载),no-proxy(无代理延迟加载)和false(立即加载)
元素中的lazy属性的默认值为proxy