封装一个方法 获取session对象
hibernate通过session对象操作数据库,封装成方法方便使用
public class HibernateUitl {
private static SessionFactory sessionFactory;
static {
// 读文件
Configuration configuration = new Configuration().configure();
// 创建session工厂
sessionFactory = configuration.buildSessionFactory();
}
// 获取session的方法
// 创建一个全新的session
public static Session getOpenSession() {
return sessionFactory.openSession();
}
// 获取当前使用的session
// 注意: 使用该方法 必须在主配置文件中配置一下
public static Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
}
在主文件中配置getCurrentsession
<!--
注意: 使用getCurrentsession方法 必须配置
配置的是 让当前的session与线程绑定
-->
<property name="hibernate.current_session_context_class">thread</property>
Java开发中的模拟MVC的开发模式:
分层思想: 1.web层 2.逻辑层 3.数据层
使用Hibernate写项目与JDBC连接池的不同之处在于:
1.需要搭建主配置文件 和 实体类的映射文件
2.DAO层中操作数据库sql语句的对象
Hibernate通过获取session对象来操作数据库
JDBC通过QueryRunner获取数据库连接对象操作数据库
Ensample:
// Hibernate插入customer到数据库
@Override
public boolean addCustomer(Customer customer) throws SQLException {
// 获取session
// (要获取同一个session来操作数据库)
Session session = HibernateUitl.getCurrentSession();
Serializable id = session.save(customer);
if (id != null) {
return true;
}
return false;
}
// JDBC插入sort到数据库
// 获取数据库连接对象
private QueryRunner queryRunner = new QueryRunner(DataSourceUtil.getDataSource());
// 添加商品
@Override
public boolean addSort(Sort sort) throws SQLException {
String sql = "insert into sort values(null,?,?,?)";
Object[] obj = {sort.getSname(),sort.getSprice(),sort.getSdesc()};
int row = queryRunner.update(sql,obj);
if (row > 0) {
return true;
}
return false;
}
在Service层开启事务的方法
Ensample: 注册操作
1.首先查询数据库中有没有这个人
2.判断没这个人再插入数据
这两个操作应该放入同一个事务中执行
事务中 可以包裹 多个对数据库的操作
Session在Service层开启更合适
注意: 为保证调用的方法处在同一个事务中
需要使用getCurrentSession()方法获取session对象(Service层和DAO层都要使用)
使用getCurrentSession()方法时,事务提交后系统会自动为你释放Session
@Test
public void fun2() {
// 注意: 使用getCurrentSession()方法 session1和session2是同一个对象
Session session1 = HibernateUitl.getCurrentSession();
Session session2 = HibernateUitl.getCurrentSession();
System.out.println(session1==session2);
}
在DAO层中添加customer的方法
@Override
public boolean addCustomer(Customer customer) {
// 应该在service层中开启事务
// 来处理调用数据方法的逻辑
// 注意: 保证调用的dao层中方法
// 处在同一个事务当中
Session session = HibernateUitl.getCurrentSession();
Transaction transaction = session.beginTransaction();
boolean isAdd = false;
// try--catch处理异常
// 在操作数据库失败时 来进行回滚
try {
isAdd = dao.addCustomer(customer);
} catch (SQLException e) {
// 注意: 打印出错误信息
e.printStackTrace();
// 失败后进行回滚
transaction.rollback();
isAdd = false;
}
transaction.commit();
return isAdd;
}
数据库的隔离级别
在主配置文件中设置数据库的隔离级别
(etc/hibernate.properties文件)
默认的隔离级别 4 (1|2|4|8)
#hibernate.connection.isolation 4
1.脏读 一个事务读取了另一个事务的
2.不可重复读
3.幻读(虚读)
隔离级别:
READ UNCOMMITED 读未提交 1 2 3 1
READ COMMITED 读已提交 2 3 2
REPEATABLE READ 可重复读 3 4
Serializable 串行化 都能避免 8
隔离级别使用1个字节来存储的
// 设置隔离级别
<property name="hibernate.connection.isolation">4</property>
主键的分类与配置(使用Hibernate 数据库中必须要有主键)
主键的分类:
1.自然主键
表里面有一个字段符合主键的规则 就直接用这个字段作为主键
2.代理主键
表里面没有一个字段符合主键的规则 可以自己创建一个id作为主键 这个键就叫代理主键
主键生成策略(7种)
identity
主键自增 使用数据库当中的主键自增
插入时 打印sql 不会插入id
increment
主键自增 由hibernate来管理
插入数据时 会先去数据库中查询当前的最大id
然后 把查出来的id+1 在插入数据
guid
全球不重复的唯一标识32位的字符串
注意: id必须使用字符串类型
native(最常用 三合一)
根据你使用的数据库类型 来选择使用
下面三个策略之一:
所有数据库不是支持identity
就是支持 序列
identity + 序列 + hilo
hilo(高低位算法)
将主键交给hibernate处理
使用自己的算法 帮你维护主键
assigned
由你自己维护主键 插入数据时需要有主键
使用的是代理主键
sequence序列 oracle数据库默认使用
配置主键
<generator class="native"></generator>
hibernate操作对象的三种状态
1.瞬时态 没有id 与session没有产生关系(还没有调用session方法)
2.持久态 有id 已跟session产生关系
3.游离态 有id 与session没有产生关系
User user = new User(); // 瞬时态(创建对象)
user.setUsername("wanglong");
user.setPassword("66666");
session.save(user); // 持久态(按id存的 已有id) 调用方法
transaction.commit();
session.close(); // 游离态(session释放)
注意: hibernate会在提交事务之后 把持久态的对象 同步到数据库中
@Test
public void fun3() {
// 保存一个用户
Session session = HibernateUitl.getOpenSession();
Transaction transaction = session.beginTransaction();
User user1 = session.get(User.class, 1);
User user2 = session.get(User.class, 1);
User user3 = session.get(User.class, 1);
User user4 = session.get(User.class, 1);
User user5 = session.get(User.class, 1);
// 思考: 打印几条sql语句? 为什么?
System.out.println(user2 == user5);
transaction.commit();
session.close();
}
打印结果 只有一条sel查询语句(可自行测试)
原因:
当调用get方法去数据库查询时
数据库返回的结果集 会被hibernate封装成对象
并且保存一份在缓存当中,还会将对象保存到快照中一份,返回缓存中的对象
再次查询get方法时
hibernate会先到缓存中查找有没有该id的对象(通过id比对)
有就直接返回缓存中的对象(不会去数据库中查询,没有使用sql语句)
没有 就用sql去查询数据库
@Test
public void fun2() {
Session session = HibernateUitl.getOpenSession();
Transaction transaction = session.beginTransaction();
// 总结: hibernate会在你提交事务之后 把持久态的对象 同步到数据库中
// 使用get方法查询一个对象
User user = session.get(User.class, 1);
user.setUsername("kunner");
transaction.commit();
session.close();
}
会打印两条sql语句 get方法时运行了一次select语句
commit提交时 运行了一次update语句(setUsername)
/*
* 快照
* get方法查询时
* hibernate会把返回的结果集 保存到缓存中一份 快照中一份
* 当你最终提交事务操作数据库的时候
* hibernate会对比缓存与快照中的数据
* 一样就不存 反之 同步到数据库
*/
@Test
public void fun4() {
Session session = HibernateUitl.getOpenSession();
Transaction transaction = session.beginTransaction();
User user = session.get(User.class, 1);
user.setUsername("penger11");
user.setUsername("ruier11");
session.update(user);
// 最终同步到数据库时 会将缓存中的对象 和 快照中的对象进行对比 一样 就不同步到数据库中,反之同步缓存中的到数据库
transaction.commit();
session.close();
}
同样打印了两条sql语句 get方法时的select 和 提交时的update语句
// 测试 new对象 瞬时态 -> 游离态->持久态
@Test
public void fun5() {
Session session = HibernateUitl.getOpenSession();
Transaction transaction = session.beginTransaction();
User user = new User(); // 瞬时态
user.setId(1); // 游离态
user.setUsername("haier");
// update方法 hibernate会把该对象 保存到缓存中
session.update(user); // 持久态
User user2 = session.get(User.class, 1);
transaction.commit();
session.close();
}