文章目录
前言
进去新公司,使用hibernate,因为之前都是使用mybatis的,所以需要快速补充功课,适应新环境。主要防止忘记某个方面,快速查看。内容肯定有错误,欢迎指正。
相关学习博客
实体配置xml
<!-- 配置表与实体对象的关系 -->
<!-- package属性:填写一个包名.在元素内部凡是需要书写完整类名的属性,可以直接写简答类名了. -->
<hibernate-mapping package="cn.itheima.domain" >
<!--
class元素: 配置实体与表的对应关系的
name: 完整类名
table:数据库表名
-->
<class name="Customer" table="cst_customer" >
<!-- id元素:配置主键映射的属性
name: 填写主键对应属性名
column(可选): 填写表中的主键列名.默认值:列名会默认使用属性名
type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
每个类型有三种填法: java类型|hibernate类型|数据库类型
not-null(可选):配置该属性(列)是否不能为空. 默认值:false
length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
-->
<id name="cust_id" >
<!-- generator:主键生成策略(明天讲) -->
<generator class="native"></generator>
</id>
<!-- property元素:除id之外的普通属性映射
name: 填写属性名
column(可选): 填写列名
type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
每个类型有三种填法: java类型|hibernate类型|数据库类型
not-null(可选):配置该属性(列)是否不能为空. 默认值:false
length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
-->
<property name="cust_name" column="cust_name" >
<!-- <column name="cust_name" sql-type="varchar" ></column> -->
</property>
<property name="cust_source" column="cust_source" ></property>
<property name="cust_industry" column="cust_industry" ></property>
<property name="cust_level" column="cust_level" ></property>
<property name="cust_linkman" column="cust_linkman" ></property>
<property name="cust_phone" column="cust_phone" ></property>
<property name="cust_mobile" column="cust_mobile" ></property>
</class>
</hibernate-mapping>
Configuration
创建
Configuration configuration = new Configuration();
加载主配置(空参加载方法,加载src下的hibernate.cfg.xml文件)
<!--读取指定配置文件==》 空参加载方法,加载src下的hibernate.cfg.xml文件-->
configuration.configure();
加载orm元数据(扩展|了解)
conf.addResource(resourceName);
conf.addClass(persistentClass);
创建sessionFactory对象
SessionFactory sf = conf.buildSessionFactory();
#### sessionFactory新建Session对象
//打开一个新的session对象
sf.openSession();
//获取一个与线程绑定的session对象
sf.getCurrentSession();
Session
- session对象功能:表达hibernate框架与数据库直接的链接(回话)
- session是hibernate操作数据库的核心对象
session事务—获得操作事务的Transaction对象
<!--获取操作事务的tx对象-->
Transaction tx = session.beginTransaction();
<!--开启事务并获得操作事务的tx对象(建议使用)-->
Transaction tx = session.beginTransaction();
基础增删改查
@Test
// 保存客户
public void fun1() {
Configuration conf = new Configuration().configure();
SessionFactory sessionFactory = conf.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
/* 增 */
Customer c = new Customer();
c.setCust_name("google");
session.save(c);/* 执行保存 */
/* 查 */
Customer customer = session.get(Customer.class, 1L);
System.out.println(customer.toString());
/* 改 */
customer.setCust_name("weiruan");
session.update(customer);/* 执行修改 */
/* 删除 */
session.delete(customer);
tx.commit();
session.close();
sessionFactory.close();
}
Hibernate之主键生成策略
https://blog.csdn.net/mmake1994/article/details/81506893
自然主键
表示该字段业务含义作为主键
代理主键
把不具备业务含义的字段为主键
主键生成策略
identity(主键自增)
适用于long、short或int类型主键,采用底层数据库本身提供的主键生成标识符。该生成器要求在数据库中把主键定义成为自增类型
sequence(序列)
适用于long、short或int类型主键,由Hibernate提供自动递增的方式生成唯一标识符,每次增量为1。只有当没有其他进程向同一张表中插入数据时才可以使用,不能再多线程环境下使用
hilo(主键自增,高低位算法)
hilo(高低位方式highlow)是hibernate中最常用的一种生成方式,需要一张额外的表保存hi的值。保存hi值的表至少有一条记录(只与第一条记录有关),否则会出现错误。跨数据库,hilo算法生成的标志只能在一个数据库中保证唯一
native(hilo+identity+sequence三选一)
根据底层数据库对自动生成标识符的能力来选择identity、sequence、hilo三种生成器中的一种,适合跨数据库平台开发
uuid(随机字符串作主键)
Hibernate采用128位的UUID算法来生成标识符。
assigned(用户手动录入)
由Java程序负责生成标识符,Hibernate不管理主键
Query–>HQL操作
@Test
public void test2() {
Configuration configure = new Configuration().configure();
SessionFactory sessionFactory = configure.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
/*查询所有*/
/*Query query = session.createQuery("from Customer ");*/
/*条件查询*/
/*Query query = session.createQuery("from Customer where cust_name = ?");
query.setString(0,"a");*/
/*多条件查询*/
/* Query query = session.createQuery("from Customer where cust_name = :aaa and cust_phone = :bbb");
query.setString("aaa","a");
query.setString("bbb","2");*/
/*分页查询*/
Query query = session.createQuery("from Customer ");
query.setFirstResult(1);
query.setMaxResults((3));
List<Customer> list = query.list();
tx.commit();
session.close();
sessionFactory.close();
}
Criteria(简称QBC)
是一个完全面向对象,不需要完全考虑数据库底层如何实现,以及编写sql,
是Hibernate框架的核心查询对象。
@Test
public void test3(){
Configuration configure = new Configuration().configure();
SessionFactory sessionFactory = configure.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Criteria criteria = session.createCriteria(Customer.class);
/*查询所有
List<Customer> list = criteria.list();*/
/*条件查询 第一个参数是对应数据库字段,第二个参数是需要查询的值
criteria.add(Restrictions.eq("cust_name","a"));
criteria.add(Restrictions.eq("cust_phone","2"));
List<Customer> list = criteria.list();*/
<!--分页查询-->
criteria.setFirstResult(1);
criteria.setMaxResults(3);
List<Customer> list = criteria.list();
transaction.commit();
session.close();
sessionFactory.close();
}
SQLQuery
用于接口接收一个sql语句进行查询,然后调用list()或uniqueResult()方法进行查询,sql不会直接封装到实体。需要手动写代码
@Test
public void test5() {
Configuration configure = new Configuration().configure();
SessionFactory sessionFactory = configure.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
/*基本查询*/
/*SQLQuery sqlQuery = session.createSQLQuery("SELECT * FROM cst_customer");
List<Object[]> list = sqlQuery.list();
for (Object[] object : list) {
System.out.println(Arrays.toString(object));
}*/
/*结果*/
/* [2, 爷爷, 1, null, null, null, null, null, null, null]
[3, 爸爸, 1, null, null, null, null, null, null, null]
[6, a, 1, null, null, null, null, null, 1, null]
[9, a, 2, null, null, null, null, null, 2, null]*/
/*封装对象中*/
/* SQLQuery sqlQuery = session.createSQLQuery("SELECT * FROM cst_customer WHERE cust_name = ? AND cust_phone = ?");
int i = 0 ;
sqlQuery.setParameter(i,"a");
sqlQuery.setParameter(1,"2");*/
/*分页*/
SQLQuery sqlQuery = session.createSQLQuery("SELECT * FROM cst_customer limit ?,?");
int a = 0;
int b = 1;
sqlQuery.setParameter(b,1);
sqlQuery.setParameter(a,0);
sqlQuery.addEntity(Customer.class);
List<Customer> list = sqlQuery.list();
for (Customer c : list) {
System.out.println(c);
}
transaction.commit();
session.close();
sessionFactory.close();
}
一对多
参考实体
public class Customer {
private Long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_linkman;
private String cust_phone;
private String cust_mobile;
// 一对多
private Set<LinkMan> linkMan = new HashSet<LinkMan>();
// get/set
public class LinkMan {
private Long lkm_id;
private Character lkm_gender;
private String lkm_name;
private String lkm_phone;
private String lkm_email;
private String lkm_qq;
private String lkm_mobile;
private String lkm_memo;
private String lkm_position;
//表达多对一关系
private Customer customer ;
//get/set
参考hbm.xml(重点)
Customer.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">
<!-- 配置表与实体对象的关系 -->
<!-- package属性:填写一个包名.在元素内部凡是需要书写完整类名的属性,可以直接写简答类名了. -->
<hibernate-mapping package="cn.itheima.domain" >
<!--
class元素: 配置实体与表的对应关系的
name: 完整类名
table:数据库表名
-->
<class name="Customer" table="cst_customer" >
<!-- id元素:配置主键映射的属性
name: 填写主键对应属性名
column(可选): 填写表中的主键列名.默认值:列名会默认使用属性名
type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
每个类型有三种填法: java类型|hibernate类型|数据库类型
not-null(可选):配置该属性(列)是否不能为空. 默认值:false
length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
-->
<id name="cust_id" >
<!-- generator:主键生成策略 -->
<generator class="native"></generator>
</id>
<!-- property元素:除id之外的普通属性映射
name: 填写属性名
column(可选): 填写列名
type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
每个类型有三种填法: java类型|hibernate类型|数据库类型
not-null(可选):配置该属性(列)是否不能为空. 默认值:false
length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
-->
<property name="cust_name" column="cust_name" >
<!-- <column name="cust_name" sql-type="varchar" ></column> -->
</property>
<property name="cust_source" column="cust_source" ></property>
<property name="cust_industry" column="cust_industry" ></property>
<property name="cust_level" column="cust_level" ></property>
<property name="cust_linkman" column="cust_linkman" ></property>
<property name="cust_phone" column="cust_phone" ></property>
<property name="cust_mobile" column="cust_mobile" ></property>
<set name="linkMan">
<key column="lkm_cust_id"></key>
<one-to-many class="cn.itheima.domain.LinkMan"/>
</set>
</class>
</hibernate-mapping>
LinkMan.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">
<!-- 配置表与实体对象的关系 -->
<!-- package属性:填写一个包名.在元素内部凡是需要书写完整类名的属性,可以直接写简答类名了. -->
<hibernate-mapping package="cn.itheima.domain" >
<!--
class元素: 配置实体与表的对应关系的
name: 完整类名
table:数据库表名
-->
<class name="Customer" table="cst_customer" >
<!-- id元素:配置主键映射的属性
name: 填写主键对应属性名
column(可选): 填写表中的主键列名.默认值:列名会默认使用属性名
type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
每个类型有三种填法: java类型|hibernate类型|数据库类型
not-null(可选):配置该属性(列)是否不能为空. 默认值:false
length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
-->
<id name="cust_id" >
<!-- generator:主键生成策略 -->
<generator class="native"></generator>
</id>
<!-- property元素:除id之外的普通属性映射
name: 填写属性名
column(可选): 填写列名
type(可选):填写列(属性)的类型.hibernate会自动检测实体的属性类型.
每个类型有三种填法: java类型|hibernate类型|数据库类型
not-null(可选):配置该属性(列)是否不能为空. 默认值:false
length(可选):配置数据库中列的长度. 默认值:使用数据库类型的最大长度
-->
<property name="cust_name" column="cust_name" >
<!-- <column name="cust_name" sql-type="varchar" ></column> -->
</property>
<property name="cust_source" column="cust_source" ></property>
<property name="cust_industry" column="cust_industry" ></property>
<property name="cust_level" column="cust_level" ></property>
<property name="cust_linkman" column="cust_linkman" ></property>
<property name="cust_phone" column="cust_phone" ></property>
<property name="cust_mobile" column="cust_mobile" ></property>
<set name="linkMan">
<key column="lkm_cust_id"></key>
<one-to-many class="cn.itheima.domain.LinkMan"/>
</set>
</class>
</hibernate-mapping>
test保存
@Test
public void test6(){
Configuration configure = new Configuration().configure();
SessionFactory sessionFactory = configure.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Customer customer = new Customer();
customer.setCust_name("a");
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("av");
LinkMan linkMan1 = new LinkMan();
linkMan1.setLkm_name("ab");
// 需要注意这个
customer.getLinkMan().add(linkMan);
customer.getLinkMan().add(linkMan1);
linkMan.setCustomer(customer);
linkMan1.setCustomer(customer);
session.save(customer);
session.save(linkMan);
session.save(linkMan1);
transaction.commit();
session.close();
sessionFactory.close();
}
级联保存更新cascade
- 指当主控方(一对多中的一)执行保存、更新或者删除操作,其关联对象(一对多中的多)也执行相同的操作。
- 级联是有方向性的,在保存一对多的一方,或者在一对多的多方。
一对多的多方案例:
一的一方
实体
public class Customer {
private Long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_linkman;
private String cust_phone;
private String cust_mobile;
//使用set集合,表达一对多关系
private Set<LinkMan> linkMens = new HashSet<LinkMan>();
}
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 package="cn.itcast.domain" >
<class name="Customer" table="cst_customer" >
<id name="cust_id" >
<generator class="native"></generator>
</id>
<property name="cust_name" column="cust_name" ></property>
<property name="cust_source" column="cust_source" ></property>
<property name="cust_industry" column="cust_industry" ></property>
<property name="cust_level" column="cust_level" ></property>
<property name="cust_linkman" column="cust_linkman" ></property>
<property name="cust_phone" column="cust_phone" ></property>
<property name="cust_mobile" column="cust_mobile" ></property>
<!-- 集合,一对多关系,在配置文件中配置 -->
<!--
name属性:集合属性名
column属性: 外键列名
class属性: 与我关联的对象完整类名
-->
<!--
级联操作: cascade
save-update: 级联保存更新
delete:级联删除
all:save-update+delete
级联操作: 简化操作.目的就是为了少些两行代码.
-->
<!-- inverse属性: 配置关系是否维护.
true: customer不维护关系
false(默认值): customer维护关系
inverse属性: 性能优化.提高关系维护的性能.
原则: 无论怎么放弃,总有一方必须要维护关系.
一对多关系中: 一的一方放弃.也只能一的一方放弃.多的一方不能放弃.
-->
<set name="linkMens" inverse="true" cascade="delete" >
<key column="lkm_cust_id" ></key>
<one-to-many class="LinkMan" />
</set>
</class>
</hibernate-mapping>
多的一方
实体
public class LinkMan {
private Long lkm_id;
private Character lkm_gender;
private String lkm_name;
private String lkm_phone;
private String lkm_email;
private String lkm_qq;
private String lkm_mobile;
private String lkm_memo;
private String lkm_position;
//表达多对一关系
private Customer customer ;
hbm.xml文件
<hibernate-mapping package="cn.itcast.domain" >
<class name="LinkMan" table="cst_linkman" >
<id name="lkm_id" >
<generator class="native"></generator>
</id>
<property name="lkm_gender" ></property>
<property name="lkm_name" ></property>
<property name="lkm_phone" ></property>
<property name="lkm_email" ></property>
<property name="lkm_qq" ></property>
<property name="lkm_mobile" ></property>
<property name="lkm_memo" ></property>
<property name="lkm_position" ></property>
<!-- 多对一 -->
<!--
name属性:引用属性名
column属性: 外键列名
class属性: 与我关联的对象完整类名
-->
<!--
级联操作: cascade
save-update: 级联保存更新
delete:级联删除
all:save-update+delete
级联操作: 简化操作.目的就是为了少些两行代码.
-->
<!-- 多的一方: 不能放弃维护关系的.外键字段就在多的一方. -->
<many-to-one name="customer" column="lkm_cust_id" class="Customer" >
</many-to-one>
</class>
</hibernate-mapping>
测试
多对多
User实体
public class User {
private Long user_id;
private String user_code;
private String user_name;
private String user_password;
private Character user_state;
//表达多对多
private Set<Role> roles = new HashSet<Role>();
User.hb.xml
<hibernate-mapping package="cn.itcast.domain" >
<class name="User" table="sys_user" >
<id name="user_id" >
<generator class="native"></generator>
</id>
<property name="user_code" ></property>
<property name="user_name" ></property>
<property name="user_password" ></property>
<property name="user_state" ></property>
<!-- 多对多关系表达 -->
<!--
name: 集合属性名
table: 配置中间表名
key
|-column:外键,别人引用"我"的外键列名
class: 我与哪个类是多对多关系
column:外键.我引用比人的外键列名
-->
<!-- cascade级联操作:
save-update: 级联保存更新
delete:级联删除
all:级联保存更新+级联删除
结论: cascade简化代码书写.该属性使不使用无所谓. 建议要用只用save-update.
如果使用delete操作太过危险.尤其在多对多中.不建议使用.
-->
<set name="roles" table="sys_user_role" cascade="save-update" >
<key column="user_id" ></key>
<many-to-many class="Role" column="role_id" ></many-to-many>
</set>
</class>
</hibernate-mapping>
Role实体
public class Role {
private Long role_id;
private String role_name;
private String role_memo;
//表达多对多
private Set<User> users = new HashSet<User>();
}
Role.hbm.xml
<hibernate-mapping package="cn.itcast.domain" >
<class name="Role" table="sys_role" >
<id name="role_id" >
<generator class="native"></generator>
</id>
<property name="role_name" ></property>
<property name="role_memo" ></property>
<!-- 使用inverse属性
true: 放弃维护外键关系
false(默认值):维护关系
结论: 将来在开发中,如果遇到多对多关系.一定要选择一方放弃维护关系.
一般谁来放弃要看业务方向. 例如录入员工时,需要为员工指定所属角色.
那么业务方向就是由员工维护角色. 角色不需要维护与员工关系.角色放弃维护
-->
<set name="users" table="sys_user_role" inverse="true" >
<key column="role_id" ></key>
<many-to-many class="User" column="user_id" ></many-to-many>
</set>
</class>
</hibernate-mapping>
test测试
添加
@Test
public void fun1(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 开启事务
Transaction tx = session.beginTransaction();
User user = new User();
user.setUser_name("小红");
User user1 = new User();
user1.setUser_name("小明");
Role role = new Role();
role.setRole_name("前台");
Role role1 = new Role();
role1.setRole_name("人事");
Role role2 = new Role();
role2.setRole_name("助理");
user1.getRoles().add(role);
user1.getRoles().add(role1);
user.getRoles().add(role2);
role.getUsers().add(user1);
role1.getUsers().add(user1);
role2.getUsers().add(user);
session.save(user);
session.save(user1);
/* session.save(role);
session.save(role1);
session.save(role2);*/
//4提交事务
tx.commit();
//5关闭资源
session.close();
}
删除
@Test
public void fun2(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 开启事务
Transaction tx = session.beginTransaction();
User user = session.get(User.class, 13l);
Role role = session.get(Role.class, 12L);
user.getRoles().remove(role);
tx.commit();
session.close();
}
Hibernate检索方式
对象图导航检索
Customer customer = session.get(Customer.class, 9l);
Set<LinkMan> linkMens = customer.getLinkMens();
OID检索
Customer customer = session.get(Customer.class, 9L);
Customer load = session.load(Customer.class, 9l);
HQL检索
@Test
public void fun4(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 开启事务
Transaction tx = session.beginTransaction();
/*基本查询*/
/*Query query = session.createQuery("from Customer ");*/
/*Query query = session.createQuery("from Customer c");*/
/*Query query = session.createQuery("select c from Customer c");*/
/*排序*/
/*Query query = session.createQuery("select cust_id from Customer order by cust_id desc ");*/
/*HQL条件查询*/
/*按位置绑定参数*/
/*Query query = session.createQuery("from Customer where cust_name = ?");
query.setString(0,"bbbb");
query.setParameter(0,"bbbb");*/
/*名称绑定参数*/
/*Query query = session.createQuery("from Customer where cust_name = :name");
query.setParameter("name","bbbb");
*/
/*分页查询*/
/*Query query = session.createQuery("from Customer");
query.setFirstResult(0);
query.setMaxResults(1);*/
/**********************获取查询结果************************************/
/*List<Customer> list = query.list();*/
/*统计查询*/
/*Query query = session.createQuery("SELECT COUNT(*) FROM Customer ");
Long o = (Long)query.uniqueResult();*/
/*投影查询一列字段*/
/*Query query = session.createQuery("SELECT cust_name FROM Customer ");
List<String> list = query.list();*/
/*投影查询多列*/
/*Query query = session.createQuery("SELECT cust_id,cust_name,cust_phone FROM Customer ");
List<Object[]> list = query.list();*/
/*构造方式不写,太乱七八糟了*/
//4提交事务
tx.commit();
//5关闭资源
session.close();
}
Hibernate注解
优势
- 使用注解方式注释类、属性、简化对象关系映射,省略表映射文件
- 通过注解方式可以自动生成数据表
使用步骤
- 为每一个实体bean使用
@Entity
注解 - 使用
@ID
指定实体Bean的标识属性 - 使用
@Table
指名当前实体Bean对应数据库表,是类级别的注解 - 使用
@GeneratedValue
指定主键生成类型,使用属性stategy
属性定义
/*根据不同的数据库选择不同策略*/
@GeneratedValue(strategy = GenerationType.AUTO)
/*使用表保存id值*/
@GeneratedValue(strategy = GenerationType.TABLE)
/*使用创建数据库的主键(mysql/sqlserver)*/
@GeneratedValue(strategy = GenerationType.IDENTITY)
/*使用序列创建主键(Oracle)*/
@GeneratedValue(strategy = GenerationType.SEQUENCE)