一、Hibernate中实体规则
1、实体类创建的注意事项
(1)持久化类提供无参构造
(2)成员变量私有,提供共有的get/set方法访问,需提供属性
(3)持久化类中的属性,应尽量使用包装类
(4)持久化类需要提供oid,与数据库当中的主键对应
(5)不要使用final修饰class-Hinbernate使用cglib代理生成代理对象,代理是继承被代理对象,如果被final修饰,将无法生成代理
2、主键类型
自然主键(少见):表的业务列中,有某业务符合,必须有,并且不重复的特征时,该列可以作为主键使用
代理主键(常见):表的业务列中,没有某业务符合,必须有,并且不重复的特征时,创建一个没有业务意义的列作为主键
3、主键生成策略
<!-- generator 主键生成策略
1.increment 由hibernate自己维护自动增长
底层通过先查询max值,再+1策略
不建议使用,存在线程并发问题
2.identity hibernate底层采用数据库本身自动增长列(mysql)
例如:mysql auto_increment
3.sequence hibernate底层采用数据库序列 ()
例如:oracle 提供序列
4.hilo(了解) 底层算法生成的主键,开发时不使用
5.native 根据底层数据库的能力选择 identity、sequence 或者 hilo 中的一个。
##以上策略使用整型,long, short 或者 int 类型
6.uuid 采用字符串唯一值 主键类型必须为String类型
##以上策略 代理主键,有hibernate维护。
7.assigned 自然主键,由程序员自己维护。
-->
二、Hibernate中的对象状态
1、对象分为三种状态
2、三种状态的转换
/**
* 测试对象的三种状态
* @author Administrator
*
*/
public class Demo {
@Test
//查看三种状态
public void fun1() {
//1.获得Session
Session session = HibernateUtils.openSession();
//2.控制事务
Transaction tx = session.beginTransaction();
//3.执行操作
Customer c = new Customer();//没有id,没有与session关联=>瞬时状态
c.setCust_phone("联想");//瞬时状态
session.save(c);//持久化状态,有id,有关联
//4.提交事务,关闭资源
tx.commit();
session.close();//游离\托管状态 有id 没有关联
}
@Test
/**
* 三种状态特点
* save方法:其实不能理解为保存,理解成将瞬时转态转换为持久状态
* 主键自增:执行save方法时,为了将对象转化为持久化状态,必须生成id值,所有需执行insert语句执行
* increment:执行save方法,为了生成id,会执行查询id最大的sql语句
*/
public void fun2() {
//1.获得Session
Session session = HibernateUtils.openSession();
//2.控制事务
Transaction tx = session.beginTransaction();
//3.执行操作
Customer c = new Customer();//没有id,没有与session关联=>瞬时状态
c.setCust_name("联想");//瞬时状态
session.save(c);//持久化状态,有id,有关联
//4.提交事务,关闭资源
tx.commit();
session.close();//游离\托管状态 有id 没有关联
}
@Test
/**
* 三种状态特点
* 持久化状态特点:持久化状态对象的任何变化都会同步到数据库中
*/
public void fun3() {
//1.获得Session
Session session = HibernateUtils.openSession();
//2.控制事务
Transaction tx = session.beginTransaction();
//3.执行操作
Customer c = session.get(Customer.class, 1l);
c.setCust_name("阿里云");
//4.提交事务,关闭资源
tx.commit();
session.close();//游离\托管状态 有id 没有关联
}
}
三、Hibernate进阶-一级缓存
缓存:提高效率,Hibernate中的一级缓存也是为了提高操作数据库的效率
提高效率手段1:提高查询效率
提高效率手段2:减少不必要的修改语句的发送
public class Demo {
@Test
//证明一级缓存存在
public void fun1() {
//1.获得Session
Session session = HibernateUtils.openSession();
//2.控制事务
Transaction tx = session.beginTransaction();
//3.执行操作
Customer c1 = session.get(Customer.class, 1L);
Customer c2 = session.get(Customer.class, 1L);
Customer c3 = session.get(Customer.class, 1L);
Customer c4 = session.get(Customer.class, 1L);
Customer c5 = session.get(Customer.class, 1L);
//4.提交事务,关闭资源
tx.commit();
session.close();//游离\托管状态 有id 没有关联
}
@Test
//
public void fun2() {
//1.获得Session
Session session = HibernateUtils.openSession();
//2.控制事务
Transaction tx = session.beginTransaction();
//3.执行操作
Customer c1 = session.get(Customer.class, 1L);
c1.setCust_name("网易");
//4.提交事务,关闭资源
tx.commit();
session.close();//游离\托管状态 有id 没有关联
}
@Test
//持久化状态对象就是放入session中的对象
public void fun3() {
//1.获得Session
Session session = HibernateUtils.openSession();
//2.控制事务
Transaction tx = session.beginTransaction();
//3.执行操作
Customer c1 = new Customer();
c1.setCust_id(1l);
session.update(c1);//将c1放入session
Customer C2 = session.get(Customer.class, 1l);
//4.提交事务,关闭资源
tx.commit();
session.close();//游离\托管状态 有id 没有关联
}
}
四、Hibernate中的事务
1、什么是事务
逻辑上的一组操作,组成这组操作的各个单元,要么一起成功,要么一起失败
2、事务的特性(ACID)
3、事务的并发问题
4、事务的隔离级别
5、如何在Hibernate中配置指定数据库的隔离级别?
在hibernate.cfg.xml中配置:
<!-- 指定Hibernate操作数据库时的隔离级别
## specify a JDBC isolation level
#hibernate.connection.isolation 1|2|4|8
0001 1 读未提交
0010 2 读已提交
0100 4 可重重复读
1000 8 串行化
-->
<property name="hibernate.connection.isolation">4</property>
6、在项目中如何管理事务
业务开始之前打开事务 ,业务执行之后提交事务,执行过程中出现异常,回滚事务
在dao层操作数据库需要用到session对象,在service控制事务,也是使用session对象完成,所以我们要确保dao层和service层使用的是同一个对象
在Hibernate中,确保同一个session的问题,Hibernate已经帮我们解决了,我们只需要调用sf.getCurrentSessin方法即可获得当前线程绑定的session对象
注意:调用getCurrentSession方法必须配合主配置当中的一段配置
<!-- 指定session与当前线程绑定 -->
<property name="hibernate.current_session_context_class">thread</property>
注意2:通过getCurrentSession方法获得的session对象当事务提交时,session会自动关闭,不要手动关闭
7、丢失更新的问题
1. 如果不考虑隔离性,也会产生写入数据的问题,这一类的问题叫丢失更新的问题。
2. 例如:两个事务同时对某一条记录做修改,就会引发丢失更新的问题。
* A事务和B事务同时获取到一条数据,同时再做修改
* 如果A事务修改完成后,提交了事务
* B事务修改完成后,不管是提交还是回滚,如果不做处理,都会对数据产生影响
解决方案有两种
* 悲观锁
* 采用的是数据库提供的一种锁机制,如果采用做了这种机制,在SQL语句的后面添加 for update 子句
* 当A事务在操作该条记录时,会把该条记录锁起来,其他事务是不能操作这条记录的。
* 只有当A事务提交后,锁释放了,其他事务才能操作该条记录
* 乐观锁
* 采用版本号的机制来解决的。会给表结构添加一个字段version=0,默认值是0
* 当A事务在操作完该条记录,提交事务时,会先检查版本号,如果发生版本号的值相同时,才可以提交事务。同时会更新版本号version=1.
* 当B事务操作完该条记录时,提交事务时,会先检查版本号,如果发现版本不同时,程序会出现错误。
4. 使用Hibernate框架解决丢失更新的问题
* 悲观锁(少)
* 使用session.get(Customer.class, 1,LockMode.UPGRADE); 方法
* 乐观锁(比较多)
* 1.在对应的JavaBean中添加一个属性,名称可以是任意的。例如:private Integer version; 提供get和set方法
* 2.在映射的配置文件中,提供<version name="version"/>标签即可。
四、Hibernate中的批量查询
1、HQL查询(Hibernate Query Language)
Hibernate独家查询语言,属于面向对象的查询语言
/**
* hql查询
*
* @author Administrator
*
*/
public class Demo {
@Test
// 基本查询
public void fun1() {
// 1.获得Session
Session session = HibernateUtils.openSession();
// 2.控制事务
Transaction tx = session.beginTransaction();
// 3.执行操作
//hql操作-------------------------------
//1>书写hql语句
//String hql = "from com.sh.domain.Customer";
String hql = "from Customer";
//2>根据hql语句创建查询对象
Query query = session.createQuery(hql);
//3>根据查询对象获得查询结果
List<Customer> list = query.list();
//Object uniqueResult = query.uniqueResult();
//Object result = query.getSingleResult();
System.out.println(list);
//-------------------------------------
// 4.提交事务,关闭资源
tx.commit();
session.close();// 游离\托管状态 有id 没有关联
}
@Test
// 条件查询
//hql语句,不可能出现任何数据库相关的信息的
public void fun2() {
// 1.获得Session
Session session = HibernateUtils.openSession();
// 2.控制事务
Transaction tx = session.beginTransaction();
// 3.执行操作
//hql操作-------------------------------
//1>书写hql语句
//String hql = "from com.sh.domain.Customer";
String hql = "from Customer where cust_id=1";
//2>根据hql语句创建查询对象
Query query = session.createQuery(hql);
//3>根据查询对象获得查询结果
Customer result = (Customer) query.getSingleResult();
System.out.println(result);
//-------------------------------------
// 4.提交事务,关闭资源
tx.commit();
session.close();// 游离\托管状态 有id 没有关联
}
@Test
// 条件查询
// 问号占位符的使用
public void fun3() {
// 1.获得Session
Session session = HibernateUtils.openSession();
// 2.控制事务
Transaction tx = session.beginTransaction();
// 3.执行操作
//hql操作-------------------------------
//1>书写hql语句
//String hql = "from com.sh.domain.Customer";
String hql = "from Customer where cust_id=?";
//2>根据hql语句创建查询对象
Query query = session.createQuery(hql);
//设置参数
query.setParameter(0,1l);
//3>根据查询对象获得查询结果
Customer result = (Customer) query.getSingleResult();
System.out.println(result);
//-------------------------------------
// 4.提交事务,关闭资源
tx.commit();
session.close();// 游离\托管状态 有id 没有关联
}
@Test
// 条件查询
// 命名占位符的使用
public void fun4() {
// 1.获得Session
Session session = HibernateUtils.openSession();
// 2.控制事务
Transaction tx = session.beginTransaction();
// 3.执行操作
//hql操作-------------------------------
//1>书写hql语句
//String hql = "from com.sh.domain.Customer";
String hql = "from Customer where cust_id=:cust_id";
//2>根据hql语句创建查询对象
Query query = session.createQuery(hql);
//设置参数
query.setParameter("cust_id",1l);
//3>根据查询对象获得查询结果
Customer result = (Customer) query.getSingleResult();
System.out.println(result);
//-------------------------------------
// 4.提交事务,关闭资源
tx.commit();
session.close();// 游离\托管状态 有id 没有关联
}
@Test
// 分页查询
// 命名占位符的使用
public void fun5() {
// 1.获得Session
Session session = HibernateUtils.openSession();
// 2.控制事务
Transaction tx = session.beginTransaction();
// 3.执行操作
//hql操作-------------------------------
//1>书写hql语句
//String hql = "from com.sh.domain.Customer";
String hql = "from Customer";
//2>根据hql语句创建查询对象
Query query = session.createQuery(hql);
//设置分页信息
query.setFirstResult(0);
query.setMaxResults(1);
//3>根据查询对象获得查询结果
List<Customer> list = query.list();
System.out.println(list);
//-------------------------------------
// 4.提交事务,关闭资源
tx.commit();
session.close();// 游离\托管状态 有id 没有关联
}
}
2、原生SQL查询
/**
* 原生sql查询
*
* @author Administrator
*
*/
public class Demo {
@Test
// 基本查询
public void fun1() {
// 1.获得Session
Session session = HibernateUtils.openSession();
// 2.控制事务
Transaction tx = session.beginTransaction();
// 3.执行操作
// sql操作-------------------------------
// 1>书写sql语句
String sql = "select * from cst_customer";
// 2>根据sql语句创建查询对象
NativeQuery query = session.createNativeQuery(sql, Customer.class);
// 3>根据查询对象获得查询结果
List<Customer> list = query.list();
// Object uniqueResult = query.uniqueResult();
// Object result = query.getSingleResult();
System.out.println(list);
// -------------------------------------
// 4.提交事务,关闭资源
tx.commit();
session.close();// 游离\托管状态 有id 没有关联
}
@Test
// 条件查询
public void fun2() {
// 1.获得Session
Session session = HibernateUtils.openSession();
// 2.控制事务
Transaction tx = session.beginTransaction();
// 3.执行操作
// sql操作-------------------------------
// 1>书写sql语句
String sql = "select * from cst_customer where cust_id=?";
// 2>根据sql语句创建查询对象
NativeQuery query = session.createNativeQuery(sql, Customer.class);
//设置参数
query.setParameter(1,1);
// 3>根据查询对象获得查询结果
List<Customer> list = query.list();
// Object uniqueResult = query.uniqueResult();
// Object result = query.getSingleResult();
System.out.println(list);
// -------------------------------------
// 4.提交事务,关闭资源
tx.commit();
session.close();// 游离\托管状态 有id 没有关联
}
@Test
// 分页查询
public void fun3() {
// 1.获得Session
Session session = HibernateUtils.openSession();
// 2.控制事务
Transaction tx = session.beginTransaction();
// 3.执行操作
// hql操作-------------------------------
// 1>书写hql语句
// String hql = "from com.sh.domain.Customer";
String sql = "select * from cst_customer limit ?,?";
// 2>根据sql语句创建查询对象
NativeQuery query = session.createNativeQuery(sql, Customer.class);
//设置分页信息
query.setParameter(1, 1);
query.setParameter(2, 1);
// 3>根据查询对象获得查询结果
List<Customer> list = query.list();
System.out.println(list);
// -------------------------------------
// 4.提交事务,关闭资源
tx.commit();
session.close();// 游离\托管状态 有id 没有关联
}
}
Don't make promises you can't keep.But those are the best kind.
不轻许做不到的承诺,但做不到的承诺往往最美好。