Hibernate入门(2)
1.Hibernate中的实体详解
Hibernate是持久层的ORM映射框架,将内存中的数据永久存储到关系型数据库中.
Hibernate中的实体又称为Hibernate的持久化类,是指一个java类与数据库表建立了映射关系.
1.1编写规则:
1).需要提供无参的构造方法(底层使用反射创建对象)
2).属性要私有,对私有属性提供共有get和set方法
javaBean中的成员变量并不是属性,get和set方法才是属性
3).持久化类的属性尽量使用包装类的类型
包装类可以多表达一个数据NULL; 0 != NULL;
hibernate中很多非必填数据默认为NULL,取出时进行转化会出现错误
4).持久化类要有一个唯一的OID与表的主键对应,Hibernate中不允许出现两个OID相同的持久化类,没有主键的表无法映射到hibernate
5).持久化类尽量不要使用final修饰class
hibernate使用延迟加载进行,结合了 Javassist 或 CGLIB 来动态地生成代理对象,所以继承class,所以不能使用final修饰class,否则无法生成代理对象.
1.2 主键类型:
1.2.1 自然主键(少见)
把表的业务列中有某一项符合必须有且不能重复的特征的业务作为主键
1.2.2 代理主键(常见)
额外添加没有任何意义的一列且符合必须有且不能重复的特征作为主键
1.3 主键生成策略
每条记录录入时主键的生成规则 位置 在中间
a).identity (auto_increment): 主键自增长,有数据库维护主键,录入时不需要指定主键
<id name="cust_id" >
<generator class="identity"></generator>
</id>
运行结果打印:
cust_id bigint not null auto_increment,
Hibernate:
insert
into
cst_customer
(cust_name, cust_source, cust_industry, cust_level, cust_linkman, cust_phone, cust_mobile)
values
(?, ?, ?, ?, ?, ?, ?)`
b).increment:主键自增,由hibernate维护,每次插入前先查询id最大值.+1作为主键(一般不使用,存在线程安全问题).
运行结果:
cust_id bigint not null,
Hibernate:
select
max(cust_id)
from
cst_customer
Hibernate:
insert
into
cst_customer
(cust_name, cust_source, cust_industry, cust_level, cust_linkman, cust_phone, cust_mobile, cust_id)
values
(?, ?, ?, ?, ?, ?, ?, ?)
c).sequence:Orcale中的主键生成策略
d).hilo:高低位算法,也是主键自增的一种算法,由hibernate维护(一般开发不使用)
e).native:hilo+sequence+identiy 自动三选一
f).uuid:产生随机字符串作为主键,必须选择String做为主键
g).assigned:自然主键生成策略,hibernate不处理主键,由开发人员处理
2.hibernate中的对象状态
对象分为3种状态:瞬时态,持久态,脱管态
id指与数据库对应
================================================================================
问:new 一个对象,给他一个id,是什么状态?
答:这要看给的id的形式,给的这个id是数据库中存在的,为脱管|游离态,如果数据库中不存在相应的id,则为瞬时态
================================================================================
2.1瞬时态
没有id,没有与session关联,在sessuin缓存中
2.2持久态
有id,与session有关
2.3托管态
某个持久化状态的实例与session的关联被关闭
有id,不在session缓存中
Customer c = new Customer();//瞬时态
c.setCust_name("阿里巴巴公司");
session.save(c);//持久态
//----------------------------------------------
tx.commit();
session.close();
//session关闭后就是托管态
特点:
save方法:将瞬时态转化为持久态,save方法并不是插入数据库,而是给瞬时态实例主键赋值
update方法:将托管态转化为持久态
get:直接得到持久态\
delete:将持久态转化为瞬时态
2.4持久化状态的特点:
持久化状态对象的任何变化都会同步导数据库中
Session session = HibernateUtils.getOpenSession();
Transaction tx = session.beginTransaction();
Customer c = new Customer();
c.setCust_name("阿里巴巴公司");
session.save(c);//执行保存
c.setCust_name("baidu公司");
tx.commit();
session.close();
最终存储结果为:baidu公司
2.5 hibernate一级缓存与快照
hibernate 获取数据之后,将数据封装成对象,而且封装成了两个对象,一个放入缓存中,一个放入快照中,将缓存中的数据提供给用户,供用户使用就修改,当用户提交事务时,会将用户提交的对象与快照中的对象进行比较,当两者不同时,才会执行更新操作.
当用户第二次准备获取数据时,会先从缓存中查找,缓存中存在就直接提供,不存在就连接数据库查询
作用:提高效率
提高查询效率,减少不必要的更新语句
hibernate中session缓存中的对象是持久态对象,持久态对象就是放在缓存中的对象
方法:
clear:清楚全部缓存
evict(object obj):清楚指定对象的缓存
3. hibernate中的事务
特点?️原子性 c : 一致性(数据总量) i : 隔离性(并发时) d : 持久性
事务并发问题:
1.脏读 ,2.不可重复读, 3.虚|幻读
解决的办法(隔离级别):
read uncommitted,read committed,recpeatable read ,serialiable
隔离级别: 读未提交(1,2,3) ,读已提交(2,3),可重复读(3)(MySQL默认级别),串行化
3.1指定隔离级别
在配置文件中指定
# 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” > 1|2|4|8 </property>
3.2 管理事务
在业务开始之前打开事务,业务执行之后提交事务
业务过程中出现异常,回滚事务
可以使用getCurrrentSesson获得当前线程的Session对象
注意1:但是要配合一段配置文件使用
<!--指定session与当前线程绑定-->
<property name="hibernate.current_session_context_class">thread</property>
注意2:通过getCurrentSession方法获得session对象,事务提交时,session会自动关闭,不能手动关闭
4.hibernate中的批量查询
3种:HQL,criteria,原生SQL
4.1.HQL:(多表但不复杂)
hibernate独家查询语言,面向对象的查询语言(不会出现数据库中的属性,只会出现对象名和属性名)
基本查询:
HQL:语句 String hql = "select * from 对象的完整类名" String hql = "from 对象的完整类名" //当类是唯一时,可以不用填写完整类名 Query query = session.createQuery(hql); List<类名> list = query.list();//结果为很多个 类名 对象 = query.uniqueResult();//结果为一个
条件查询
2String hql = "from 完整类名 where 属性名 = 属性值";
//属性名并不是数据库中的列名
Query query = session.createQuery(hql);
对象 = query.uniqueResult();
//?占位符的使用
String hql = "from 完整类名 where 属性名 = ?";
//属性名并不是数据库中的列名
Query query = session.createQuery(hql);
//query.setLong("参数位置(从0开始)","参数值");
//query.setXxx("参数位置(从0开始)","参数值");
query.setParameter("参数位置(从0开始)","参数值");//会自动选取类型
对象 = query.uniqueResult();
//命名占位符 :占位符名称
String hql = "from 完整类名 where 属性名 = :占位符名称";
Query query = session.createQuery(hql);
query.setParameter("占位符名称","参数值");//会自动选取类型;
对象 = query.uniqueResult();
//分页查询
String hql ="from 完整类名";
Query query = session.createQuery(hql);
//调用方法设置分页信息
query.setFirstResult(first);
query.maxResult(num);
List<类名> list = query.list();
4.2.criteria(单表)
hibernate创建的一种查询语句,不会出现任何SQL语句,只调用方法就查询数据库
基本查询
Criteria criteria = session.createCriteria(字节码对象);
List<类名> list = criteria.list();
条件查询
Criteria criteria = session.createCriteria(字节码对象);
criteria.add(Restrictions.方法名("属性名",属性值);
criteria.uniqueResult();
Restrictions里面存在很多方法表示数据库中的判断语句
allEq:使用map表示多个相等
>:gt >=:ge <:lt <=:le ==:eq !=:ne in:in
between and:between like:like is not null:isNotNull
is null:isNull or:or and:and
查询分页
Criteria criteria = session.createCriteria(字节码对象);
criteria.setFirstResult(first);
criteria.maxResult(num);
List<类名> list = criteria.list();
查询聚合函数:
Criteria criteria = session.createCriteria(字节码对象);
//设置查询聚合函数
criteria.setProjection(Projection.XXX);
criteria.uniqueResult();//查询返回值
rowCount:总行数
4.3.原生SQL语句(复杂的业务查询)
基本查询
String sql = .............. (原生sql语句)
SQLQuery query = session.createSQLQuery(sql);
List<object[]> list = query.list();
//默认返回的是object数组集合的形式
封装:
String sql = .............. (原生sql语句)
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(字节码对象);
List<类名> list = query.list();
条件查询
//只支持?索引
String sql = ............. where 数据库列名 = ?,.....
SQLQuery query = session.createSQLQuery(sql);
query.setParameter(0,属性值);//从零开始
query.addEntity(字节码对象);
List<类名> list = query.list();
分页查询
String sql = "............limit ?,?"
query.setparameter(0,属性值);
query.setparameter(1,属性值);
query.addEntity(字节码对象);
List<类名> list = query.list();