1. 持久化类创建
1.1 注意事项
- 持久化类需提供无参构造
- 成员变量私有,提供公有的set/get方法访问
- 持久化类中的属性尽量使用包装类
- 持久化类需提供oid,与数据库中的主键列对应
- 不要用final修饰class,因为cglib代理(继承代理)
1.2 主键类型
自然主键(少见)
表的业务列中,有某业务列符合“必须有且不重复的特征”,该列可作为主键列使用。
assigned:自然主键生成策略。hibernate不会管理主键值,由开发人员自己录入代理主键
表的业务列中,没有有某业务列符合“必须有且不重复的特征”时,创建一个没有业务意义的列作为主键。
generator:主键生成策略,每条记录录入时,主键的生成规则
identity: 主键自增,由数据库维护主键值,录入时不需要指定主键
increment(存在线程安全问题): 主键自增,由hibernate维护,每次插入前会先查询表中id的最大值,+1作为新主键,开发时不使用
hilo:高低位算法,主键自增,由hibernate维护,开发时不使用
sequence:oracle中的主键生成策略
native:identity+ hilo + sequence 自动三选一策略
uuid:产生不重复的随机字符串作为主键,主键类型必须为string类型
2. hibernate中对象的状态
2.1 hibernate中对象的三种状态
- 瞬时状态:没有id,没有与session关联
- 持久化状态:有id,与session关联
3.游离状态|托管状态:有id,没有与session关联
@Test
public void testFunc02(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer c = new Customer(); // 没有id,没有与session关联,瞬时状态
c.setCust_name("lisi"); // 没有id,没有与session关联,瞬时状态
session.save(c); // 有id,与session关联,持久化状态
// 提交事务
transaction.commit();
// 释放资源
session.close(); // 有id,没有与session关联,游离状态
}
2.2 hibernate中状态的特点
持久化状态特点:持久化状态对象的任何变化都会自动同步到数据库中
这个时候,不需要调用session.update方法,数据库中的数据依然会更新
@Test
public void testFunc(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer c = session.get(Customer.class, 1l); // 持久化状态
c.setCust_name("lisi");
// 提交事务
transaction.commit();
// 释放资源
session.close(); // 游离状态
}
2.3 状态转换图
结论:将对象的数据同步到数据库中,对象转化为持久化状态
3. hibernate中的一级缓存
缓存:提高操作数据库的效率
3.1 提高查询效率
3.2 减少不必要的修改语句执行
@Test
public void testFunc(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Customer c1 = new Customer();
c1.setCust_name("wangwu"); // 托管|游离
session.update(c1); // c1被放入到session缓存了
Customer c2 = session.get(Customer.class, 1l); // 从缓存中取出
// 在提交之前是没有sql语句执行的,
// 在提交之前会对比session的缓存和快照,这里并没有从数据库中取出对象,所以快照是空的,缓存和快照是不一致的,会执行一次update操作
// 提交事务
transaction.commit();
// 释放资源
session.close(); // 游离状态
}
4. hibernate中的事务
4.1 事务的特性
a:原子性
c:一致性
i:隔离性
d:持久性
4.2 事务并发问题
- 脏读:读到了别人正在修改但是并未提交的数据,导致读取的数据并不是最终确定的数据
- 不可重复读:两次连续的读取,数据不一致。可能是有人在第一次读取之后,将数据进行修改并提交了,导致第二次读取的数据和第一次的不同
- 虚|幻读:一般是整表操作。在删除整张表的过程中,有人向表中写入数据,在删完之后发现表中竟然还有数据
4.3 事务的隔离级别
读未提交-可能出现的问题 1.2.3
读已提交-可能出现的问题 2.3
可重复读(mysql默认隔离级别)-可能出现的问题 3
串行化-可能出现的问题 无,但是效率太低
4.4 如何在hibernate中指定隔离级别
4
4.5 在项目中如何管理事务
- 业务开始之前打开事务,业务执行之后提交事务,执行过程中出现异常回滚事务
2.在dao层操作数据库需要用到session,在service层操作数据库也需要用到session,我们需要确保两个session是同一个对象 - 在hibernate中确保使用同一个session,只需要调用sessionFactory.getCurrentSession(),底层也是使用的ThreadLocal,绑定线程
thread
public class HibernateUtils {
private static SessionFactory sessionFactory;
/// 只能有一个sessionFactory
static {
Configuration conf = new Configuration().configure();
sessionFactory = conf.buildSessionFactory();
}
/// 返回不同的session
public static Session openSession() {
Session session = sessionFactory.openSession();
return session;
}
/// 返回同一个与线程绑定的session
public static Session getCurrentSession() {
Session session = sessionFactory.getCurrentSession();
return session;
}
}
@Test
public void testFunc03() {
Session session1 = HibernateUtils.getCurrentSession();
Session session2 = HibernateUtils.getCurrentSession();
System.out.println(session1 == session2); // true
}
注意:通过getCurrentSession()获得的session对象,当事务提交时,session会自动关闭,不需要手动调用session.close()
4.6 修改01中的项目
将事务的操作从dao层,转到service层
public class CustomerDaoImpl implements CustomerDao {
@Override
public void save(Customer customer) {
Session session = HibernateUtils.getCurrentSession();
session.save(customer);
}
}
public class CustomerServiceImpl implements CustomerService {
private CustomerDao serviceDao = new CustomerDaoImpl();
@Override
public void save(Customer customer) {
Session session = HibernateUtils.getCurrentSession();
// 打开事务
Transaction transaction = session.beginTransaction();
try {
serviceDao.save(customer);
} catch (Exception e) {
e.printStackTrace();
// 异常,回滚事务
transaction.rollback();
}
// 提交事务
transaction.commit();
}
}
5. 批量查询
5.1 HQL查询
- 查全部
@Test
public void testFunc() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
// 1.书写HQL语句
String hql = "from Customer ";
// String hql = "from Customer where cust_id = 1";
// 2.根据HQL语句创建查询对象
Query query = session.createQuery(hql);
// 根据查询对象,获得查询结果
List list = query.list(); // 返回list结果
// 接收唯一的查询结果
// Customer customer = (Customer) query.uniqueResult();
System.out.println(list);
// 提交事务
transaction.commit();
// 释放资源
session.close();
}
- 设置参数,使用 ? 做占位符 查某一条数据
@Test
public void testFunc() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
// 1.书写HQL语句
// String hql = "from Customer ";
String hql = "from Customer where cust_id = ?";
// 2.根据HQL语句创建查询对象
Query query = session.createQuery(hql);
query.setParameter(0, 2l);
// 根据查询对象,获得查询结果
// List list = query.list(); // 返回list结果
// 接收唯一的查询结果
Customer customer = (Customer) query.uniqueResult();
System.out.println(customer);
// 提交事务
transaction.commit();
// 释放资源
session.close();
}
- 使用hibernate的命名占位符,查询某一条数据
@Test
public void testFunc() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
// 1.书写HQL语句
// String hql = "from Customer ";
String hql = "from Customer where cust_id = :cust_id";
// 2.根据HQL语句创建查询对象
Query query = session.createQuery(hql);
query.setParameter("cust_id", 2l);
// 根据查询对象,获得查询结果
// List list = query.list(); // 返回list结果
// 接收唯一的查询结果
Customer customer = (Customer) query.uniqueResult();
System.out.println(customer);
// 提交事务
transaction.commit();
// 释放资源
session.close();
}
- 设置分页
@Test
public void testFunc() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
// 1.书写HQL语句
// String hql = "from Customer ";
String hql = "from Customer where cust_id = :cust_id";
// 2.根据HQL语句创建查询对象
Query query = session.createQuery(hql);
// 设置分页,相当于limit ?, ?
query.setFirstResult(0);
query.setMaxResults(1);
// 根据查询对象,获得查询结果
List list = query.list(); // 返回list结果
System.out.println(list);
// 提交事务
transaction.commit();
// 释放资源
session.close();
}
5.2 criteria查询
- 查询全部
@Test
public void testFunc() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
Criteria criteria = session.createCriteria(Customer.class);
// 根据查询对象,获得查询结果
List list = criteria.list(); // 返回list结果
System.out.println(list);
// 提交事务
transaction.commit();
// 释放资源
session.close();
}
- 条件查询
@Test
public void testFunc() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
// 创建 Criteria 对象
Criteria criteria = session.createCriteria(Customer.class);
// 添加查询条件
criteria.add(Restrictions.eq("cust_id", 1l));
// 根据查询对象,获得查询结果
Customer customer = (Customer) criteria.uniqueResult(); // 返回list结果
System.out.println(customer);
// 提交事务
transaction.commit();
// 释放资源
session.close();
}
- 分页查询
@Test
public void testFunc05() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
// 创建 Criteria 对象
Criteria criteria = session.createCriteria(Customer.class);
// 添加查询条件
criteria.setFirstResult(0); // 从第0条开始查
criteria.setMaxResults(1); // 每页一条
// 根据查询对象,获得查询结果
Customer customer = (Customer) criteria.uniqueResult(); // 返回list结果
System.out.println(customer);
// 提交事务
transaction.commit();
// 释放资源
session.close();
}
- 查询总行数
@Test
public void testFunc() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
// 创建 Criteria 对象
Criteria criteria = session.createCriteria(Customer.class);
// 设置查询的聚合函数,总行数
criteria.setProjection(Projections.rowCount());
// 根据查询对象,获得查询结果
Long rowCount = (Long) criteria.uniqueResult();
System.out.println(rowCount);
// 提交事务
transaction.commit();
// 释放资源
session.close();
}
5.3 原生sql查询
- 查询全部
@Test
public void testFunc() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
String sql = "select * from t_customer";
SQLQuery sqlQuery = session.createSQLQuery(sql);
// sqlQuery.list();默认返回的是object[]
// 指定将结果集封装到哪个对象当中
sqlQuery.addEntity(Customer.class);
// 根据查询对象,获得查询结果
List list = sqlQuery.list();
System.out.println(list);
// 提交事务
transaction.commit();
// 释放资源
session.close();
}
- 条件查询
@Test
public void testFunc() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
String sql = "select * from t_customer where cust_id = ?";
SQLQuery sqlQuery = session.createSQLQuery(sql);
sqlQuery.setParameter(0, 1l);
// 指定将结果集封装到哪个对象当中
sqlQuery.addEntity(Customer.class);
// 根据查询对象,获得查询结果
Customer customer = (Customer) sqlQuery.uniqueResult();
System.out.println(customer);
// 提交事务
transaction.commit();
// 释放资源
session.close();
}
- 分页查询
@Test
public void testFunc() {
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
String sql = "select * from t_customer limit ?, ?";
SQLQuery sqlQuery = session.createSQLQuery(sql);
sqlQuery.setParameter(0,0);
sqlQuery.setParameter(1, 1);
// 指定将结果集封装到哪个对象当中
sqlQuery.addEntity(Customer.class);
// 根据查询对象,获得查询结果
List list = sqlQuery.list();
System.out.println(list);
// 提交事务
transaction.commit();
// 释放资源
session.close();
}