hibernate配置文件:
hibernate.cfg.xml
示例代码:(连接的是MySQL数据库)
<!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 name="foo">
<!-- 配置数据库信息 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="connection.url">jdbc:mysql:///hibernate_20120328</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!-- 其他配置 -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">false</property>
<!--
create:先删除,再创建
update:如果表不存在就创建,不一样就更新,一样就什么都不做。
create-drop:初始化时创建表,SessionFactory执行close()时删除表。
validate:验证表结构是否一致,如果不一致,就抛异常。
-->
<property name="hbm2ddl.auto">update</property>
<!-- 导入映射文件
<mapping resource="cn/dyb/a_helloworld/User.hbm.xml"/>
-->
</session-factory>
</hibernate-configuration>
User.hbm.xml:(实体数据库映射文件)
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.dyb.a_helloworld">
<class name="User" table="t_user">
<id name="id" type="int" column="id">
<generator class="native"/>
</id>
<property name="name" type="string" column="name" length="20"/>
</class>
</hibernate-mapping>
对应的类:
User.java
package cn.dyb.a_helloworld;
/**
* ΚµΜε
*
* @author tyg
*
*/
public class User {
private int id;
private String name;
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;
}
@Override
public String toString() {
return "[User: id=" + id + ", name=" + name + "]";
}
}
Hibernate连接数据库测试:
示例代码:
private static SessionFactory sessionFactory;
static {
Configuration cfg = new Configuration();
cfg.configure("hibernate.cfg.xml"); // 读取指定的主配置文件
sessionFactory = cfg.buildSessionFactory(); // 根据生成Session工厂
}
@Test
public void testSave() throws Exception {
User user = new User();
user.setName("张三");
// 保存
Session session = sessionFactory.openSession(); // 打开一个新的Session
Transaction tx = session.beginTransaction(); // 开始事务
session.save(user);
tx.commit(); // 提交事务
session.close(); // 关闭Session,释放资源
}
@Test
public void testGet() throws Exception {
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
User user = (User) session.get(User.class, 1); // 获取
System.out.println(user);
tx.commit();
session.close();
}
Hibernate分页:
firstResult--开始取数据索引;maxResult--每页查询数据条数
封装到QueryResult类中:
QueryResult:
package cn.dyb.b_dao;
import java.util.List;
public class QueryResult {
private int count; // 总记录数
private List list; // 一页的数据
public QueryResult(int count, List list) {
this.count = count;
this.list = list;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
}
分页简单代码参考:
小型案例:
HibernateUtils工具类:
package cn.dyb.b_dao;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import cn.dyb.a_helloworld.User;
public class HibernateUtils {
// SessionFactory全局只需要有一个就可以了
private static SessionFactory sessionFactory;
static {
Configuration cfg = new Configuration();
// cfg.configure(); // 读取默认的配置文件(hibernate.cfg.xml)
// // cfg.configure("hibernate.cfg.xml"); // 读取指定位置的配置文件
// sessionFactory = cfg.buildSessionFactory();
// cfg.addResource("cn/dyb/a_helloworld/User.hbm.xml");
// cfg.addClass(User.class); // 去User类所在的包中查找名称为User,后缀为.hbm.xml的文件
// 初始化SessionFactory
sessionFactory = new Configuration()//
.configure()//
.buildSessionFactory();
}
/**
* 获取全局唯一的SessionFactory
*
* @return
*/
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
/**
* 从全局唯一的SessionFactory中打开一个Session
*
* @return
*/
public static Session openSession() {
return sessionFactory.openSession();
}
}
Dao层类:
UserDao.java
package cn.dyb.b_dao;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import cn.dyb.a_helloworld.User;
public class UserDao {
/**
* 保存
*
* @param user
*/
public void save(User user) {
Session session = HibernateUtils.openSession();
try {
Transaction tx = session.beginTransaction(); // 开始事务
session.save(user);
tx.commit(); // 提交事务
} catch (RuntimeException e) {
session.getTransaction().rollback(); // 回滚事务
throw e;
} finally {
session.close(); // 关闭Session
}
}
/**
* 更新
*
* @param user
*/
public void update(User user) {
Session session = HibernateUtils.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
session.update(user); // 操作
tx.commit();
} catch (RuntimeException e) {
tx.rollback();
throw e;
} finally {
session.close();
}
}
/**
* 删除
*
* @param id
*/
public void delete(int id) {
Session session = HibernateUtils.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Object user = session.get(User.class, id); // 要先获取到这个对象
session.delete(user); // 删除的是实体对象
tx.commit();
} catch (RuntimeException e) {
tx.rollback();
throw e;
} finally {
session.close();
}
}
/**
* 根据id查询一个User数据
*
* @param id
* @return
*/
public User getById(int id) {
Session session = HibernateUtils.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
User user = (User) session.get(User.class, id); // 操作
tx.commit();
return user;
} catch (RuntimeException e) {
tx.rollback();
throw e;
} finally {
session.close();
}
}
/**
* 查询所有
*
* @return
*/
public List<User> findAll() {
Session session = HibernateUtils.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
// 方式一:使用HQL查询
// List<User> list = session.createQuery("FROM User").list();
// 方式二:使用Criteria查询
Criteria criteria = session.createCriteria(User.class);
List<User> list = criteria.list();
tx.commit();
return list;
} catch (RuntimeException e) {
tx.rollback();
throw e;
} finally {
session.close();
}
}
* * 分页的查询数据列表
*
* @param firstResult
* 从结果列表中的哪个索引开始取数据
* @param maxResults
* 最多取多少条数据
* @return 一页的数据列表 + 总记录数
*/
@SuppressWarnings("unchecked")
public QueryResult findAll(int firstResult, int maxResults) {
Session session = HibernateUtils.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
// 查询一页的数据列表
// 方式一:
// Query query = session.createQuery("FROM User");
// query.setFirstResult(firstResult);
// query.setMaxResults(maxResults);
// List<User> list = query.list();
// 方式二:方法链
List<User> list = session.createQuery(//
"FROM User")//
.setFirstResult(firstResult)//
.setMaxResults(maxResults)//
.list();
// 查询总记录数
Long count = (Long) session.createQuery(//
"SELECT COUNT(*) FROM User")//
.uniqueResult();
tx.commit();
// 返回结果
return new QueryResult(count.intValue(), list);
} catch (RuntimeException e) {
tx.rollback();
throw e;
} finally {
session.close();
}
}
}
测试代码:
UserDaoTest.java
package cn.dyb.b_dao;
import java.util.List;
import org.junit.Test;
import cn.dyb.a_helloworld.User;
public class UserDaoTest {
private UserDao userDao = new UserDao();
@Test
public void testSave_1() {
User user = new User();
user.setName("张三");
// 保存
userDao.save(user);
}
@Test
public void testGetById() {
User user = userDao.getById(1);
System.out.println(user);
}
@Test
public void testUpdate() {
// 从数据库获取一条存在的数据
User user = userDao.getById(1);
user.setName("李四");
// 更新
userDao.update(user);
}
@Test
public void testDelete() {
userDao.delete(1);
}
// ------------
@Test
public void testSave_25() {
for (int i = 1; i <= 25; i++) {
User user = new User();
user.setName("test_" + i);
userDao.save(user); // 保存
}
}
@Test
public void testFindAll() {
List<User> list = userDao.findAll();
for (User user : list) {
System.out.println(user);
}
}
@Test
public void testFindAllIntInt() {
// 查询
// QueryResult qr = userDao.findAll(0, 10); // 第1页,每页10条
// QueryResult qr = userDao.findAll(10, 10); // 第2页,每页10条
QueryResult qr = userDao.findAll(20, 10); // 第3页,每页10条
// 显示结果
System.out.println("总记录数:" + qr.getCount());
for (User user : (List<User>) qr.getList()) {
System.out.println(user);
}
}
}
根据配置生成表结构
根据配置文件生成相应的数据库代码。
示例代码:
package cn.dyb.a_helloworld;
import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.junit.Test;
public class CreateSchema {
// 根据配置生成表结构
@Test
public void test() throws Exception {
Configuration cfg = new Configuration().configure();
SchemaExport schemaExport = new SchemaExport(cfg);
// 第一个参数script的作用: print the DDL to the console
// 第二个参数export的作用: export the script to the database
schemaExport.create(true, true);
}
}
配置文件扩展
通过addClass添加实体类
private static SessionFactory sessionFactory = new Configuration()//
.configure()//
.addClass(User.class)// 添加Hibernate实体类(加载对应的映射文件)
.buildSessionFactory();
数据库中保存头像(小图片)
实体类中定义
private byte[] photo; // 头像图片
映射文件中的定义
<!-- 头像,二进制类型,最好指定长度 -->
<property name="photo" type="binary" length="102400"></property>
测试类中的图片存储与读取
// 读取图片文件
InputStream in = new FileInputStream( "c:/test.png");
byte[] photo = new byte[in.available()];
in.read(photo);
in.close();
//输出图片
OutputStream out = new FileOutputStream("c:/copy.png");
out.write(user.getPhoto());
out.close();
大文本数据保存
实体类中定义
private String desc; // 一大段说明
映射关系中定义(text)
<property name="desc" type="text" length="5000" column="t_desc" ></property>
Hibernate主键生成策略
<generator class="?"/>
identity
<generator class="identity"/>
使用数据库的自动增长策略,不是所有数据库都支持,比如oracle就不支持
sequence
<generator class="sequence"/>
在 DB2,PostgreSQL,Oracle,SAP DB,McKoi 中使用序列(sequence),在使用Oracle数据库时可以使用这一个
hilo
<generator class="hilo">
<param name="table">hi_value</param>
<param name="column">next_value</param>
<param name="max_lo">100</param>
</generator>
使用高低位算法生成主键值。只需要一张额外表,所有的数据都支持。
native
<generator class="native"></generator>
根据底层数据库的能力选择 identity、sequence 或者 hilo中的一个。
increment
<generator class="increment"></generator>
由Hibernate维护的自动增长。先查询当前最大的id值,再加1使用,不推荐使用,因为在多线程下会问题。
assigned
<generator class="assigned"></generator>
手工指定主键值
uuid
<generator class="uuid"></generator>
可以添加:user.setId(UUID.randomUUID().toString()),否则自动生成。
由Hibernate自动生成UUID并指定为主键值。
映射集合属性
set
在实体类中的定义:
private Set<String> addressSet = new HashSet<String>(); // Set集合
在映射文件中的定义:
addressSet属性,Set集合
table属性:集合表的名称
key子元素:集合外键的列名
element子元素:存放集合元素的列的信息
sort属性:"unsorted|natural|comparatorClass" 默认为:unsorted
order-by属性:写的是order by 子句,是SQL语句,是操作的集合表。这是在查询数据时指定orderby子句。
<set name="addressSet" table="user_addressSet" order-by="address ASC">
<key column="userId"></key>
<element type="string" column="address"></element>
</set>
list
在实体类中的定义:
private List<String> addressList = new ArrayList<String>(); // List集合
在映射文件中的定义:
addressList属性,List集合
list-index:用于存放索引的列
<list name="addressList" table="user_addressList">
<key column="userId"></key>
<list-index column="idx"></list-index>
<element type="string" column="address"></element>
</list>
Array数组
在实体类中的定义:
private String[] addressArray; // 数组
在映射文件中的定义:
addressArray属性,数组。与List的映射基本一致
<array name="addressArray" table="user_addressArray">
<key column="userId"></key>
<list-index column="idx"></list-index>
<element type="string" column="address"></element>
</array>
map
在实体类中的定义:
private Map<String, String> addressMap = new HashMap<String, String>();
在映射文件中的定义:
addressMap属性,Map集合
<map name="addressMap" table="user_addressMap">
<key column="userId"></key>
<map-key type="string" column="key_"></map-key>
<element type="string" column="address"></element>
</map>
bag
在实体类中的定义:
private List<String> addressBag = new ArrayList<String>();
在映射文件中的定义:
addressBag属性,Bag集合:无序,可重复。与Set集合的映射基本一致
<bag name="addressBag" table="user_addressBag">
<key column="userId"></key>
<element type="string" column="address"></element>
</bag>
一对多多对一映射
例子:部门和员工的对应关系(部门员工一对多)
部门
private Set<Employee> employees = new HashSet<Employee>(); // 关联的很多员工
employees属性,Set集合,表达的是本类与Employee的一对多
class属性:关联的实体类型
key子元素:对方表中的外键列(多方的那个表)
inverse属性:
默认为false,表示本方维护关联关系。
如果为true,表示本方不维护关联关系。
只是影响是否能设置外键列的值(设成有效值或是null值),对获取信息没有影响。
cascade属性:
默认为none,代表不级联。
级联是指操作主对象时,对关联的对象也做相同的操作。
可设为:delete, save-update, all, none ...
<set name="employees" cascade="all">
<key column="departmentId"></key>
<one-to-many class="Employee"/>
</set>
员工
private Department department; // 关联的部门对象
department属性,表达的是本类与Department的多对一
class属性:关联的实体类型
column属性:外键列(引用关联对象的表的主键)
<many-to-one name="department" class="Department" column="departmentId"></many-to-one>
关联关系inverse
从部门方解除(与inverse有关系,为false时可以解除)
Department department = (Department) session.get(Department.class, 1);
department.getEmployees().clear();
删除部门方(一方)
A.如果没有关联的员工:能删除。
B.如果有关联的员工且inverse=true,由于不能维护关联关系,所以会直接执行删除,就会有异常
C.如果有关联的员工且inverse=false,由于可以维护关联关系,他就会先把关联的员工的外键列设为null值,再删除自己。
多对多
学生和教师例子(多对多关系)
学生
private Set<Teacher> teachers = new HashSet<Teacher>(); // 关联的老师们
teachers属性,Set集合。
表达的是本类与Teacher的多对多。
table属性:中间表(集合表)
key子元素:集合外键(引用当前表主键的那个外键)
<set name="teachers" table="teacher_student" inverse="false">
<key column="studentId"></key>
<many-to-many class="Teacher" column="teacherId"></many-to-many>
</set>
教师
private Set<Student> students = new HashSet<Student>(); // 关联的学生们
students属性,Set集合。
表达的是本类与Student的多对多。
<set name="students" table="teacher_student" inverse="true">
<key column="teacherId"></key>
<many-to-many class="Student" column="studentId"></many-to-many>
</set>
inverse
a, 如果没有关联的对方:能删除。
b, 如果有关联的对方且inverse=false,由于可以维护关联关系,他就会先删除关联关系,再删除自己。
c, 如果有关联的对方且inverse=true,由于不能维护关联关系,所以会直接执行删除自己,就会有异常。
对象状态
Evict
session.evict(user); // 清除Session中一个指定的对象
将持久化状态转成游离状态
save():
把临时状态变为持久化状态(交给Sessioin管理)
会生成:insert into ...
update():
把游离状态变为持久化状态
会生成:update ...
在更新时,对象不存在就报错
saveOrUpdate():
把临时或游离状态转为持久化状态
会生成:insert into 或 update ...
在更新时,对象不存在就报错
本方法是根据id判断对象是什么状态的:如果id为原始值(对象的是null,原始类型数字是0)就是临时状态,如果不是原始值就是游离状态。
delete():
把持久化或游离转为删除状态
会生成:delete ...
如果删除的对象不存在,就会抛异常
get():
获取数据,是持久化状态
会生成:select ... where id=?
会马上执行sql语句
如果数据不存在,就返回null
load():
获取数据,是持久化状态
会生成:select ... where id=?
load()后返回的是一个代理对象,要求类不能是final的,否则不能生成子类代理,就不能使用懒加载功能了。
让懒加载失效的方式:一、把实体写成final的;二、在hbm.xml中写<class ... lazy="false">
不会马上执行sql语句,而是在第1次使用非id或class属性时执行sql。
如果数据不存在,就抛异常:ObjectNotFoundException
| 加载方式 | 返回值 | 如果值不存在 |
get | 立即加载 | 真是对象或null | 返回null |
load | 延迟加载 | 代理对象 | 抛异常 |
Session保存内存溢出
当保存多条数据或者数据过大时,会造成数据溢出,要先刷出(存入数据库)然后清空再继续执行。
for (int i = 0; i < 30; i++) {
User user = new User();
user.setName("测试");
session.save(user);
if (i % 10 == 0) {
session.flush(); // 先刷出
session.clear(); // 再清空
}
}
一对一映射
基于外键的方式
人和身份证(身份证里面有一个关联人的外键,不能重复)
Person.java
private IdCard idCard; // 关联的身份证
映射文件:
idCard属性,IdCard类型。
表达的是本类与IdCard的一对一。
采用基于外键的一对一映射方式,本方无外键方。
property-ref属性:
写的是对方映射中外键列对应的属性名。
<one-to-one name="idCard" class="IdCard" property-ref="person"/>
IdCare.java
private Person person; // 关联的公民
映射文件:
person属性,Person类型。
表达的是本类与Person的一对一。
采用基于外键的一对一映射方式,本方有外键方。
(多对一的特殊方式)
<many-to-one name="person" class="Person" column="personId" unique="true"></many-to-one>
关联关系
解除关联关系:一对一中,只能有外键方可以维护关联关系。
从有外键方解除关系,可以。
IdCard idCard = (IdCard) session.get(IdCard.class, 1);
idCard.setPerson(null);
从无外键方解除关系,不可以。
Person person = (Person) session.get(Person.class, 1);
person.setIdCard(null);
a, 如果没有关联的对方:能删除。
b, 如果有关联的对方且可以维护关联关系(有外键方),他就会先删除关联关系,再删除自己。
c, 如果有关联的对方且不能维护关联关系(无外键方),所以会直接执行删除自己,就会有异常。
基于主键的方式
Person实体类中定义:
private IdCard idCard; // 关联的身份证
映射文件定义:
<!-- idCard属性,IdCard类型。
表达的是本类与IdCard的一对一。
采用基于主键的一对一映射方式,本方无外键方。
-->
<one-to-one name="idCard" class="IdCard"></one-to-one>
IdCard实体类中定义:
private Person person; // 关联的公民
映射文件定义:
<class name="IdCard" table="idCard2">
<id name="id">
<!-- 当使用基于主键的一对一映射时,
有外键方的主键生成策略一定要是foreign。
参数property:
生成主键值时所根据的对象。
-->
<generator class="foreign">
<param name="property">person</param>
</generator>
</id>
<property name="number"/>
<!-- person属性,Person类型。
表达的是本类与Person的一对一。
采用基于主键的一对一映射方式,本方有外键方。 -->
<one-to-one name="person" class="Person" constrained="true"></one-to-one>
</class>
关联关系:
解除关联关系:使用基于主键的一对一映射方式:双方都不可以解除关联关系。
如果没有关联的对方:能删除。
如果有关联的对方:因为会直接执行删除自己,所以无外键方会有异常,有外键方没有异常。
继承映射
用一张表的方式
使用论坛主题和回复为例:
Article.java
private Integer id;
private String title;
private String content;
private Date postTime;
Reply.java
private int floor; // 楼层
Topic.java
private int type; // 精华、置顶...
Article.hbm.xml使用父类的映射:
<!--
discriminator-value属性:
用于鉴别是哪个类的一个值,表示这个值就是这个类。
如果不写,默认为类的全限定名。
-->
<class name="Article" table="article" discriminator-value="Aticle">
<id name="id">
<generator class="native"/>
</id>
<!-- 用于鉴别是什么类型的一个列 -->
<discriminator type="string" column="class_"></discriminator>
<property name="title"/>
<property name="content" type="text" length="10000"/>
<property name="postTime" type="timestamp"/>
<!-- 子类:Topic -->
<subclass name="Topic" discriminator-value="Topic">
<property name="type"></property>
</subclass>
<!-- 子类:Reply -->
<subclass name="Reply" discriminator-value="Reply">
<property name="floor"></property>
</subclass>
</class>
每个类对应一张表
<!-- 采用每个类一张表的方式,抽象类也对应表。 -->
<class name="Article" table="article2">
<id name="id">
<generator class="native"/>
</id>
<property name="title"/>
<property name="content" type="text" length="10000"/>
<property name="postTime" type="timestamp"/>
<!-- 子类:Topic -->
<joined-subclass name="Topic" table="topic2">
<key column="id"></key>
<property name="type"></property>
</joined-subclass>
<!-- 子类:Reply -->
<joined-subclass name="Reply" table="reply2">
<key column="id"></key>
<property name="floor"></property>
</joined-subclass>
</class>
具体类一张表,抽象类不对应表
<!-- 采用每个具体类一张表的方式,抽象类不对应表。 -->
<class name="Article" abstract="false" table="article3">
<id name="id">
<!--
当使用每个具体类一张表的方式时,主键生成策略不能是identity。
因为在整个继承结构中,主键值是不能重复的。
-->
<generator class="hilo">
<param name="table">hi_value</param>
<param name="column">next_value</param>
<param name="max_lo">100</param>
</generator>
</id>
<property name="title"/>
<property name="content" type="text" length="10000"/>
<property name="postTime" type="timestamp"/>
<!-- 子类:Topic -->
<union-subclass name="Topic" table="topic3">
<property name="type"></property>
</union-subclass>
<!-- 子类:Reply -->
<union-subclass name="Reply" table="reply3">
<property name="floor"></property>
</union-subclass>
</class>
事务隔离级别
例如:
在hibernate.cfg.xml中配置
<!--
设置默认的事务隔离级别:
隔离级别 对应的整数表示
READ UNCOMMITED 1
READ COMMITED 2
REPEATABLE READ 4
SERIALIZEABLE 8
-->
<property name="connection.isolation">2</property>
HQL
简单示例
使用HQL查询
HQL: Hibernate Query Language.
特点:
>> 1,与SQL相似,SQL中的语法基本上都可以直接使用。
>> 2,SQL查询的是表和表中的列;HQL查询的是对象与对象中的属性。
>> 3,HQL的关键字不区分大小写,类名与属性名是区分大小写的。
>> 4,SELECT可以省略.
1,简单的查询
hql = "FROM Employee";
hql = "FROM Employee AS e"; // 使用别名
hql = "FROM Employee e"; // 使用别名,as关键字可省略
2,带上过滤条件的(可以使用别名):Where
hql = "FROM Employee WHERE id<10";
hql = "FROM Employee e WHERE e.id<10";
hql = "FROM Employee e WHERE e.id<10 AND e.id>5";
3,带上排序条件的:Order By
hql = "FROM Employee e WHERE e.id<10 ORDER BY e.name";
hql = "FROM Employee e WHERE e.id<10 ORDER BY e.name DESC";
hql = "FROM Employee e WHERE e.id<10 ORDER BY e.name DESC, id ASC";
4,指定select子句(不可以使用select *)
hql = "SELECT e FROM Employee e"; // 相当于"FROM Employee e"
hql = "SELECT e.name FROM Employee e"; // 只查询一个列,返回的集合的元素类型就是这个属性的类型
hql = "SELECT e.id,e.name FROM Employee e"; // 查询多个列,返回的集合的元素类型是Object数组
hql = "SELECT new Employee(e.id,e.name) FROM Employee e"; // 可以使用new语法,指定把查询出的部分属性封装到对象中
5,执行查询,获得结果(list、uniqueResult、分页 )
Query query = session.createQuery("FROM Employee e WHERE id<3");
query.setFirstResult(0);
query.setMaxResults(10);
// List list = query.list(); // 查询的结果是一个List集合
Employee employee = (Employee) query.uniqueResult();// 查询的结果是唯一的一个结果,当结果有多个,就会抛异常
System.out.println(employee);
QBC
简单示例
// 创建Criteria对象
Criteria criteria = session.createCriteria(Employee.class);
// 增加过滤条件
criteria.add(Restrictions.ge("id", 1));
criteria.add(Restrictions.le("id", 5));
// 增加排序条件
criteria.addOrder(Order.desc("name"));
criteria.addOrder(Order.desc("id"));
// 执行查询
// criteria.setFirstResult(0);
// criteria.setMaxResults(100);
// criteria.uniqueResult();
// criteria.list()
List list = criteria.list();
懒加载
懒加载
也叫延迟加载,不是在执行获取操作时马上生成SQL,而是在第一次使用时生成SQL。
分成两种:
类级别的:
<class ... lazy="true/false">
属性级别的:
<set/list/map/bag ... lazy="...">
<many-to-one ... lazy="...">
<one-to-one ... lazy="...">
在使用懒加载特性时,可能会有LazyInitializationException异常:
原因:
真正的去获取数据时,Session已经没有了。
解决办法:
方式一:让Session在真正加载后再关闭。
方式二:或是在Sessoin关闭前执行Hibernate.initialize(department.getEmployees());
extra策略
与 lazy=“true” 类似. 主要区别是增强延迟检索策略能进一步延迟 Customer 对象的 orders 集合代理实例的初始化时机:
• 当程序第一次访问 orders 属性的 iterator() 方法时, 会导致 orders 集合代理类实例的初始化
• 当程序第一次访问 order 属性的 size(), contains() 和 isEmpty() 方法时, Hibernate 不会初始化 orders 集合类的实例, 仅通过特定的 select 语句查询必要的信息, 不会检索所有的 Order 对象
C3P0连接池设定
在hibernate.cfg.xml中的配置
需要导包:(例如c3p0-0.9.1.jar)
<!-- 使用c3p0连接池 配置连接池提供的供应商-->
<property name="connection.provider_class">
<!--在连接池中可用的数据库连接的最少数目 -->
<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>
二级缓存
配置示例
<!-- 使用二级缓存,默认是未打开的。 -->
<!-- 指定要使用的缓存的提供商,这也就打开了二级缓存 ,不同的提供商需要不同jar包支持需要手动添加
<property name="cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
-->
<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<!-- 开启使用查询缓存 -->
<property name="cache.use_query_cache">true</property>
<!-- 指定要使用二级缓存的实体类 -->
<class-cache usage="read-write" class="cn.dyb.l_second_cache.Employee"/>
<collection-cache usage="read-write" collection="cn.dyb.l_second_cache.Department.employees" />
对应提供二级缓存的EhCacheProvider参考文档
它有自己的默认配置文件(ehcache.xml),可以直接复制到src目录
例如:ehcache.xml
<ehcache>
<diskStore path="d:/cache/"/>
<defaultCache
maxElementsInMemory="10"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
</ehcache>
不管是一级缓存,还是二级缓存,都地在使用OID的获取对象时才有效。
get()
load()
对于Query.list()默认不会使用缓存,哪怕写成where id=1也不会使用缓存。
Update \____ 不会通知Session缓存。
Delete / 通知二级缓存