目录
- 目录
- 实体类持久化类的编写规则
- Hibernate主键生成策略
- 实体类操作
- 案例准备
- 对实体类CRUD操作
- 添加操作
- 查询操作
- 修改操作
- 删除操作
- saveOrUpdate方法
- 实体类对象状态
- Hibernate一级缓存
- Hibernate事务操作
- 规范写法
- 案例
- Hibernate中session绑定本地线程
- 实现session与本地线程当前线程绑定
- Hibernate的其他API
- Query对象
- Criteria对象
- SQLQuery对象
实体类(持久化类)的编写规则
- 属性私有化,即private修饰;
- 属性提供getter和setter方法;
- 要求实体类提供一个属性,并作为唯一值(一般使用ID值);
- 实体类属性建议使用基本数据类型对应的包装类,而不使用基本数据类型。
为什么“实体类属性建议使用基本数据类型对应的包装类,而不使用基本数据类型。”?
假设存在这么一个实体类Student类,具有int score属性,那么:
当学生分数为0时,score = 0;当学生没有参加考试时,int类型的score属性就无法表示这个含义了。
但是如果score为Integer类型,则可以以 score = null 进行表示。
Hibernate主键生成策略
实体类被要求提供一个属性作为唯一值,该属性就对应数据库表中的主键。在Hibernate中主键由配置好的策略进行生成。
(主键生成策略在对应的实体类映射配置文件中进行设置)
如:
<!--
id标签
name属性:实体类中作为唯一标识的属性的名称
column属性:生成的表字段名称
-->
<id name="uid" column="uid">
<!--
设置数据库表中ID的增长策略
native:生成表的id是主键自动增长的。
-->
<generator class="native"/>
</id>
主键生成策略有:(列举出几个常见的)
1. increment:用于long、short或int类型,由Hibernate自动以递增的方式生成唯一标识符,每次增量为1。只有当没有其他进程向同一张表中插入数据时才可以使用,不能在集群环境下使用。适用于代理主键。
2. identity:采用底层数据库本身提供的主键生成标识符,条件是数据库支持自动增长数据类型。在MySQL数据库中可以使用该生成器,该生成器要求在数据库中把主键定义成自增长类型。适用于代理主键。Oracle数据库并不适用。
3. sequence:Hibernate根据底层数据库序列生成标识符。条件是数据库之间序列。适用于代理主键。在Oracle数据库中可以使用该生成器。
4. native:根据底层数据库对自动生成表示符的能力来选择identity、sequence、hilo三种生成器中的一种,适合跨数据库平台开发。适用于代理主键。
5. uuid:使用128位的UUID算法计算一个唯一的值,会使用IP地址及相关的计算机硬件信息。计算结果位32位的16进制数,对应的主键类型必须为String。
注:
increment和identity的区别:这两种主键生成方式都是提供自增长策略,但是原理并不一样。increment的主键自增长由Hibernate维护,而identity的主键自增长由底层数据库维护。如果采用MySQL的自增长(这里假设使用MySQL数据库,且主键生成策略设置为identity),插入数据时Hibernate生成的SQL语句中将不包含id主键列数据。该主键的当前值、下一个值由数据库自己维护。如果使用Hibernate的自增长(即设置了increment主键生成策略),插入数据时Hibernate生成的SQL语句将包含id主键列,并由Hibernate维护该主键的当前值以及下一个值。
increment,自增长类型,由Hibernate而不是数据库维护,因此即使Oracle等不支持自增长类型的数据库也可以使用。
实体类操作
案例准备
(以下说明均基于该案例进行说明)
实体类 User.java
package com.wm103.entity;
import java.io.Serializable;
public class User implements Serializable {
/*Hibernate要求实体类有一个属性是唯一的。*/
private int uid;
private String username;
private String password;
private String address;
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"uid=" + uid +
", username='" + username + '\'' +
", password='" + password + '\'' +
", address='" + address + '\'' +
'}';
}
}
实体类的映射文件 User.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>
<class name="com.wm103.entity.User" table="t_user">
<id name="uid" column="uid">
<generator class="native"/>
</id>
<property name="username" column="username"></property>
<property name="password" column="password"></property>
<property name="address" column="address"></property>
</class>
</hibernate-mapping>
核心配置文件 hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.username">root</property>
<property name="connection.password"></property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql:///hibernate_day01?useUnicode=true&characterEncoding=UTF-8</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="hbm2ddl.auto">update</property>
<mapping resource="com/wm103/entity/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Hibernate工具类 HibernateUtil.java
package com.wm103.utils;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/**
* Created by DreamBoy on 2017/5/19.
*/
public class HibernateUtil {
// 单态模式的SessionFactory
private static final SessionFactory sessionFactory;
static {
// 采用默认的hibernate.cfg.xml来启动一个Configuration的实例
Configuration cfg = new Configuration().configure();
sessionFactory = cfg.buildSessionFactory();
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void main(String[] args) {
System.out.println(getSessionFactory());
}
}
测试类 HibernateDemo.java
package com.wm103.hibernatetest;
import com.wm103.entity.User;
import com.wm103.utils.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
/**
* Created by DreamBoy on 2017/5/19.
*/
public class HibernateDemo {
public void test() {
// 1. 调用工具类得到sessionFactory
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
// 2. 获取session
Session session = sessionFactory.openSession();
// 3. 开启事务
Transaction tx = session.beginTransaction();
// 4. 具体逻辑
// 后续提及的案例代码放在这里!!!
// 5. 提交事务
tx.commit();
// 6. 关闭资源
session.close();
sessionFactory.close();
}
}
对实体类CRUD操作
添加操作
调用session里面的save方法,如:
User user = new User();
user.setUsername("梦小白");
user.setPassword("123");
user.setAddress("China");
session.save(user);
查询操作
调用session里面的get方法,如:
User user = session.get(User.class, 2);
System.out.println(user);
修改操作
调用session里面的update方法,如:
User user = session.get(User.class, 1);
user.setUsername("DreamBoy");
session.update(user);
删除操作
第一种 根据ID查询到的对象
User user = session.get(User.class, 2);
session.delete(user);
第二种 创建新对象设置主键ID值
User user = new User();
user.setUid(3);
session.delete(user);
saveOrUpdate方法
既能实现添加操作,又能实现修改操作。如:
实现添加操作
User user = new User();
user.setUsername("User007");
user.setPassword("007");
user.setAddress("地下城");
// 实体类对象状态是瞬时态时,saveOrUpdate执行的是添加操作
session.saveOrUpdate(user);
实现修改操作
User user = session.get(User.class, 1);
user.setUsername("DreamBoy");
// 实体类对象状态是持久态时,saveOrUpdate执行的是修改操作
session.saveOrUpdate(user);
实体类对象状态
实体类对象有三种状态:
(1)瞬时态:对象里面没有ID值,对象与session没有关联。如:
User user = new User();
user.setUserName("haha");
user.setPassword("1234");
user.setAddress("China");
session.save(user);
在这里添加user记录以前,user对象既没有ID值也没有与session关联,此时user对象处于瞬时态。
(2)持久态:对象里面有ID值,且与session有关联。如:
User user = session.get(User.class, 1);
(3)托管态:对象里面有ID值,但是与session没有关系。
User user = new User();
user.setUid(3);
session.delete(user);
在这里执行delete方法之前user对象处于托管态。
Hibernate一级缓存
(1)Hibernate一级缓存的特点:
- Hibernate的一级缓存是默认打开的
- Hibernate的一级缓存使用范围,是session范围,即从session创建到session关闭
- Hibernate的一级缓存中,存储数据必须是持久态数据
(2)特性:持久态下修改实体类对象属性会自动更新数据库,如:
User user = session.get(User.class, 1);
user.setUsername("DreamBoy");
// session.update(user); // 这里不调用,同样在提交事务的时候,也会进行更新操作
Hibernate事务操作
规范写法
try {
// 开启事务
// ...
// 提交事务
} catch() {
// 回滚事务
} finally {
// 关闭资源
}
案例
@Test
public void testTx() {
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try {
sessionFactory = HibernateUtil.getSessionFactory();
session = sessionFactory.openSession();
tx = session.beginTransaction();
User user = new User();
user.setUsername("1530");
user.setPassword("0521");
user.setAddress("guangzhou");
session.save(user);
tx.commit();
} catch (Exception e) {
tx.rollback();
} finally {
session.close();
sessionFactory.close();
}
}
Hibernate中session绑定本地线程
SessionFactory负责创建Session,SessionFactory是线程安全的,多个并发线程可以同时访问一个SessionFactory 并从中获取Session实例。而Session并非线程安全,也就是说,如果多个线程同时使用一个Session实例进行数据存取,则将会导致 Session 数据存取逻辑混乱.因此创建的Session实例必须在本地线程上运行,使之总与当前的线程相关。
参考:
http://blog.sina.com.cn/s/blog_7ffb8dd5010146i3.html
http://www.cnblogs.com/shipengzhi/articles/2102055.html
实现session与本地线程(当前线程)绑定
(1)在Hibernate的核心配置文件中配置
<property name="hibernate.current_session_context_class">thread</property>
(2)调用sessionFactory的getCurrentSession方法得到当前线程相关的sessio对象
public static Session getSession() {
return sessionFactory.getCurrentSession();
}
注:获取与本地线程绑定的session对象后,手动关闭session会报错:org.hibernate.SessionException: Session was already closed
。因为与本地线程绑定的session,在本地线程结束后就会被关闭,我们不需要在手动session.close()
。
HibernateUtil.java
package com.wm103.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/**
* Created by DreamBoy on 2017/5/19.
*/
public class HibernateUtil {
// 单态模式的SessionFactory
private static final SessionFactory sessionFactory;
static {
// 采用默认的hibernate.cfg.xml来启动一个Configuration的实例
Configuration cfg = new Configuration().configure();
sessionFactory = cfg.buildSessionFactory();
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Session getSession() {
return sessionFactory.getCurrentSession();
}
public static void main(String[] args) {
System.out.println(getSessionFactory());
}
}
测试案例:
@Test
public void testGetSession() {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtil.getSession();
tx = session.beginTransaction();
User user = new User();
user.setUsername("1654");
user.setPassword("0521");
user.setAddress("guangzhou");
session.save(user);
tx.commit();
} catch (Exception e) {
tx.rollback();
}
}
Hibernate的其他API
(这里只演示查询表中所有数据的功能)
Query对象
使用Query对象,我们不需要编写SQL语句,但是需要写HQL(HQL,Hibernate Query Language)语句。HQL语法类似于SQL,不同的是HQL是一种完全面向对象的语言,能够直接查询实体类及属性。而SQL语句操作的是数据库中的表和表中的字段。
查询表中所有数据的HQL:from 实体类名称。如:
@Test
public void testQuery() {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtil.getSession();
tx = session.beginTransaction();
Query query = session.createQuery("from User");
List<User> list = query.list();
for (User user : list) {
System.out.println(user);
}
tx.commit();
} catch (Exception e) {
tx.rollback();
}
}
Criteria对象
@Test
public void testCriteria() {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtil.getSession();
tx = session.beginTransaction();
Criteria criteria = session.createCriteria(User.class);
List<User> list = criteria.list();
for (User user : list) {
System.out.println(user);
}
tx.commit();
} catch (Exception e) {
tx.rollback();
}
}
SQLQuery对象
@Test
public void testSQLQuery() {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtil.getSession();
tx = session.beginTransaction();
SQLQuery sqlQuery = session.createSQLQuery("SELECT * FROM t_user");
// list方法默认返回的是一个List集合,且集合中的元素为对象数组Object[]
/*List<Object[]> list = sqlQuery.list();
for (Object[] obj : list) {
System.out.println(Arrays.toString(obj));
}*/
// 返回一个List集合,且集合中的元素为实体类对象
sqlQuery.addEntity(User.class);
List<User> list = sqlQuery.list();
for (User user : list) {
System.out.println(user);
}
tx.commit();
} catch (Exception e) {
tx.rollback();
}
}