Hibernate是开源的全自动的ORM(对象关系映射)框架,它对JDBC进行封装,将实体类与数据库表建立映射关系.Hibernate可以自动生成SQL语句,可以使用对象编程思维来操纵数据库。
ORM,即Object-Relational Mapping,它的作用就是在关系型数据库和对象之间做了一个映射。从对象(Object)映射到关系(Relation),再从关系映射到对象。这样,我们在操作数据库的时候,不需要再去和复杂SQL打交道,只要像操作对象一样操作它就可以了(把关系数据库的字段在内存中映射成对象的属性)。
注:由于使用到mysql数据库,需要导入mysql的驱动jar文件
org.hibernate
hibernate-core
5.1.10.Final
mysql
mysql-connector-java
5.1.39
public class Person {
private Integer id;
private String name;
private Integer age;
get & set……
}
在resource资源目录下创建名为 Person.hbm.xml 的配置文件
com.mysql.jdbc.Driver
jdbc:mysql://localhost:3306/mydb
root
root
org.hibernate.dialect.MySQLDialect
true
update
执行完这段代码之后,数据库的表中会多出一个Hibernate创建的数据库表
public class Demo {
public static void main(String[] args) {
Configuration config = new Configuration();
//读取resource下的hibernate.cfg.xml文件
config.configure();
// 创建SessionFactory对象
SessionFactory sessionFactory = config.buildSessionFactory();
//获取一个Session对象
Session session = sessionFactory.openSession();
Person p = new Person();
p.setName("haha");
p.setAge(20);
//开启事务
Transaction transaction = session.beginTransaction();
//添加数据
session.save(p);
transaction.commit();//提交事务
//关闭
session.close();
sessionFactory.close();
}
}
identity | 采用数据库生成的主键,用于为long、short、int类型生成唯一标识, Oracle 不支持自增字段. | |
---|---|---|
sequence | DB2、Oracle均支持的序列,用于为long、short或int生成唯一标识。需要oracle创建sequence。 | seq_name |
native | 根据底层数据库的能力,从identity、sequence、hilo中选择一个,灵活性更强。 | |
increment | 个是由Hibernate在内存中生成主键,每次增量为1,不依赖于底层的数据库,因此所有的数据库都可以使用 | |
uuid | 使用一个128-bit的UUID算法生成字符串类型的标识符 |
public class Demo2 {
public static void main(String[] args) {
Configuration config = new Configuration();
//读取resource下的hibernate.cfg.xml文件
config.configure();
// 创建SessionFactory对象
SessionFactory sessionFactory = config.buildSessionFactory();
//获取一个Session对象
Session session = sessionFactory.openSession();
Person2 p = new Person2();
p.setName("xuanxuan");
p.setAge(20);
//开启事务
Transaction transaction = session.beginTransaction();
//添加数据
//session.save(p);
//关闭
session.close();
sessionFactory.close();
}
}
public class Demo2 {
public static void main(String[] args) {
Configuration config = new Configuration();
//读取resource下的hibernate.cfg.xml文件
config.configure();
// 创建SessionFactory对象
SessionFactory sessionFactory = config.buildSessionFactory();
//获取一个Session对象
Session session = sessionFactory.openSession();
Person2 p = new Person2();
p.setName("xuanxuan");
p.setAge(20);
//开启事务
Transaction transaction = session.beginTransaction();
//p.setId("8a881eb66b77d154016b77d159900000");
//根据主键删除
session.delete(p);
//关闭
session.close();
sessionFactory.close();
}
}
public class Demo2 {
public static void main(String[] args) {
Configuration config = new Configuration();
//读取resource下的hibernate.cfg.xml文件
config.configure();
// 创建SessionFactory对象
SessionFactory sessionFactory = config.buildSessionFactory();
//获取一个Session对象
Session session = sessionFactory.openSession();
Person2 p = new Person2();
p.setName("xuanxuan");
p.setAge(20);
//开启事务
Transaction transaction = session.beginTransaction();
//根据id更新数据
p.setId("8a881eb66b77ea13016b77ea17700000");
session.update(p);
//关闭
session.close();
sessionFactory.close();
}
}
public class Demo2 {
public static void main(String[] args) {
Configuration config = new Configuration();
//读取resource下的hibernate.cfg.xml文件
config.configure();
// 创建SessionFactory对象
SessionFactory sessionFactory = config.buildSessionFactory();
//获取一个Session对象
Session session = sessionFactory.openSession();
Person2 p = new Person2();
p.setName("xuanxuan");
p.setAge(20);
//开启事务
Transaction transaction = session.beginTransaction();
//根据主键进行查询
Person2 p2 = session.get(Person2.class, "8a881eb66b77ea13016b77ea17700000");
System.out.println(p2.getName());
//关闭
session.close();
sessionFactory.close();
}
}
部门和员工关系:
一对多:一个部门有多个员工
多对一:多个员工属于一个部门
创建实体类对象:
//部门类
public class Department {
private Integer did;
private String dname;
//private List//Hibernate使用list集合数据库中会多出一个序号字段
private Set empSet;
get & set ……
}
//员工类
public class Employee {
private Integer eid;
private String ename;
//员工属于一个部门
private Department dept;
get & set ……
}
注:加入inverse = true 后,类不维护表关系
以下为部门类的映射配置:
以下为员工类的映射配置:
例子:
一个学生有多个课程
一个课程有多个学生
学生class
public class Student {
private Integer sid;
private String sname;
private Set courseSet;
get & set ……
}
课程class
public class Course {
private Integer cid;
private String cname;
private Set stuSet;
get & set ……
}
学生映射文件配置
课程映射文件配置
Hibernate中默认是懒加载的,例子如下
Session session = sessionFactory.openSession();
Employee employee = session.get(Employee.class, 1);
//输出员工的名字
System.out.println(employee.getEname());
System.out.println("________________________________");
//输出部门名称
System.out.println(employee.getDept().getDname());
输出结果和sql语句
Hibernate: select employee0_.eid as eid1_2_0_, employee0_.ename as ename2_2_0_, employee0_.deptId as deptId3_2_0_ from t_emp employee0_ where employee0_.eid=?
张三
________________________________
Hibernate: select department0_.did as did1_1_0_, department0_.dname as dname2_1_0_ from t_dept department0_ where department0_.did=?
开发部门
如果想要取消懒加载,在对应实体的映射文件 **** 标签中添加 属性 **lazy="false"** 可以取消懒加载取消懒加载后,两句sql语句一起进行查询了
Hibernate: select employee0_.eid as eid1_2_0_, employee0_.ename as ename2_2_0_, employee0_.deptId as deptId3_2_0_ from t_emp employee0_ where employee0_.eid=?
Hibernate: select department0_.did as did1_1_0_, department0_.dname as dname2_1_0_ from t_dept department0_ where department0_.did=?
张三
________________________________
开发部门
注:在Hibernate中sql语句不可以写 slecte * from 表名,如果只要想表中的一些字段,可以给类起别名。(AS 不能省略)
Query query = session.createQuery("select p from Person as p");
public class Demo {
private static SessionFactory sessionFactory = null;
public static void main(String[] args) {
Configuration config = new Configuration();
// 读取resource下的hibernate.cfg.xml文件
config.configure();
// 创建SessionFactory对象
sessionFactory = config.buildSessionFactory();
//获取一个Session对象
Session session = sessionFactory.openSession();
//sql"select * from t_person
//hql中使用的都是类名和类中的属性名
Query query = session.createQuery("from Person");
//查询的记录,放到列表中
List list = query.list();
String name = list.get(1).getName();
System.out.println(name);
System.out.println(list);
System.out.println(list.size());
}
}
需要取出某个表中的单个列的数据时,可以在**query.list()**使用 list 进行接受返回值。
public class Demo {
public static void main(String[] args) {
Configuration config = new Configuration();
// 读取resource下的hibernate.cfg.xml文件
config.configure();
// 创建SessionFactory对象
SessionFactory sessionFactory = config.buildSessionFactory();
//获取一个Session对象
Session session = sessionFactory.openSession();
//sql"select * from t_person
//hql中使用的都是类名和类中的属性名
//Query query = session.createQuery("select p from Person as p");
Query query = session.createQuery("select p.name from Person as p");
List list = query.list();
//查询的记录,放到列表中
//List list = query.list();
System.out.println(list.get(1);
System.out.println(list);
System.out.println(list.size());
}
}
查询某个表中的多个字段,封装到数组中
public class Demo {
public static void main(String[] args) {
Configuration config = new Configuration();
// 读取resource下的hibernate.cfg.xml文件
config.configure();
// 创建SessionFactory对象
SessionFactory sessionFactory = config.buildSessionFactory();
//获取一个Session对象
Session session = sessionFactory.openSession();
//sql"select * from t_person
//hql中使用的都是类名和类中的属性名
//Query query = session.createQuery("select p from Person as p");
Query query = session.createQuery("select p.name, p.age from Person as p");
List
注:要在实体类中创建有参构造方法(最好无参也要创建),根据有参构造的参数,在sql语句中 **new 实体(别名.参数)**来映射为实体类
public class Demo {
public static void main(String[] args) {
Configuration config = new Configuration();
// 读取resource下的hibernate.cfg.xml文件
config.configure();
// 创建SessionFactory对象
SessionFactory sessionFactory = config.buildSessionFactory();
//获取一个Session对象
Session session = sessionFactory.openSession();
Query query = session.createQuery("select new Person(p.id ,p.name, p.age) from Person as p");
List list = query.list();
System.out.println(list);
}
}
注:语句中的 age 是实体中的属性名, 不是数据库中的字段
public void query2(){
Configuration config = new Configuration();
// 读取resource下的hibernate.cfg.xml文件
config.configure();
// 创建SessionFactory对象
SessionFactory sessionFactory = config.buildSessionFactory();
//获取一个Session对象
Session session = sessionFactory.openSession();
Query query = session.createQuery("from Person where age<30 ");
List list = query.list();
System.out.println(list);
}
//? 占位符
Query query = session.createQuery("from Person where age ");
//占位符设置值,第一个参数表示占位符的索引,第二个参数,设置的值
query.setInteger(0,30);
/**
* query.setParameter("age",30);可以使用索引来赋值,也可以使用名称来赋值
*/
Query query = session.createQuery("from Person where age <:age");
//占位符设置值,按照名称来赋值
query.setInteger("age",30);
/**
* query.setParameter("age",30);可以使用索引来赋值,也可以使用名称来赋值
*/
注:模糊查询时候,可以直接写 query.setParameter(0,"%内容%");,如果查询用到是传过来的字符串,则需要使用+号 把String类型的字符串拼接进去
public void query3(){
Configuration config = new Configuration();
// 读取resource下的hibernate.cfg.xml文件
config.configure();
// 创建SessionFactory对象
SessionFactory sessionFactory = config.buildSessionFactory();
//获取一个Session对象
Session session = sessionFactory.openSession();
String name = "轩";
Query query = session.createQuery("from Person where name like ?");
//占位符设置值,按照名称来赋值
query.setParameter(0,"%"+ name +"%");
List list = query.list();
System.out.println(list);
}
public void query4(){
Configuration config = new Configuration();
// 读取resource下的hibernate.cfg.xml文件
config.configure();
// 创建SessionFactory对象
SessionFactory sessionFactory = config.buildSessionFactory();
//获取一个Session对象
Session session = sessionFactory.openSession();
String name = "轩";
Query query = session.createQuery("select p.age, count(*) from Person p group by p.age");
//占位符设置值,按照名称来赋值
List
public void query5(){
Configuration config = new Configuration();
// 读取resource下的hibernate.cfg.xml文件
config.configure();
// 创建SessionFactory对象
SessionFactory sessionFactory = config.buildSessionFactory();
//获取一个Session对象
Session session = sessionFactory.openSession();
String name = "轩";
Query query = session.createQuery("from Person order by age");
//占位符设置值,按照名称来赋值
List list = query.list();
System.out.println(list);
}
public void query6(){
Configuration config = new Configuration();
// 读取resource下的hibernate.cfg.xml文件
config.configure();
// 创建SessionFactory对象
SessionFactory sessionFactory = config.buildSessionFactory();
//获取一个Session对象
Session session = sessionFactory.openSession();
String name = "轩";
Query query = session.createQuery("from Person");
//占位符设置值,按照名称来赋值
query.setFirstResult(0);//分页数据开始的索引
query.setMaxResults(2);//每页显示的记录数
List list = query.list();
System.out.println(list);
}
注:hibernate的sql语句中:
/**
* fetch 迫切连接会把查询到的数据直接赋值在实体中,相当于mybatis的嵌套查询,一次查询把所有数据封装到实体中,不用额外再执行一次sql语句。
*/
Query query = session.createQuery(" select d from Department d inner join fetch d.empSet where d.did = 1");
public static void query(){
Configuration config = new Configuration();
//读取resource下的hibernate.cfg.xml文件
config.configure();
// 创建SessionFactory对象
SessionFactory sessionFactory = config.buildSessionFactory();
//获取一个Session对象
Session session = sessionFactory.openSession();
/**
* 多表查询进行关联时,使用对象中包含的另一个对象进行关联,不用写on
*/
Query query = session.createQuery(" select d from Department d inner join d.empSet where d.did = 1");
//查询一条记录使用query.uniqueResult();
Department d = (Department)query.uniqueResult();
System.out.println(d);
//关闭
session.close();
sessionFactory.close();
}
数据库中借助for update对查询到的数据加锁
注:锁需要先开启事务。在sql中运行 start transaction; 开启事务
mysql> start transaction;
Query OK, 0 rows affected
mysql> select * from user where name='wangwu' for update;
mysql> update user set age=20 where name='wangwu';
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
概念:是数据被外界修改保持保守状态,因此,再整个数据处理过程中,将数据牌锁定状态。悲观所的实现,往往依靠数据提供的锁机制(也只有再数据库层的锁机制才能保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。实际开发中悲观锁不经常使用。
String hqlStr = "from Account where name='zhangsan'";
Query query = session.createQuery(hqlStr);
//for update
query.setLockOptions(LockOptions.UPGRADE);//加锁
List list = query.list();
相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制,以操作最大程度的独占性。但随之而来的就是数据库性能的降低,特别是对长事务而言。乐观锁大多是基于数据版本(Version)记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于库表的版本解决方案中,一般是通过为数据库增加 version 字段来实现。
public class Account {
private Integer id;
private String name;
private Integer money;
private Integer version;//版本号
get & set ……
}
注:使用 来标注版本编号,一定要把这个标签放最前面(主键字段的后面)。
session1修改之后,数据库中的版本号(version字段)会自动加1,
会导致sssion2因版本号不一致无法修改,导致报错
public static void demoLock1(){
Configuration config = new Configuration();
config.configure();
SessionFactory sessionFactory = config.buildSessionFactory();
//创建2个session对象
Session session1 = sessionFactory.openSession();
Session session2 = sessionFactory.openSession();
//开启两个session的事务
Transaction transaction1 = session1.beginTransaction();
Transaction transaction2 = session2.beginTransaction();
//根据id查询映射出2个相同的实体
Account account1 = session1.get(Account.class, 1);
Account account2 = session2.get(Account.class, 1);
//set账户1实体的钱,并进行更新
account1.setMoney(10000);
session1.update(account1);
transaction1.commit();
session1.close();//关闭
//set账户1实体的钱,并进行更新
account2.setMoney(20000);
session2.update(account1);
transaction2.commit();
session2.close();//关闭
}
JPA全称 Java Persistence API,是sun公司针对ORM技术提出的技术规范,用来将POJO按照标准的方式进行持久化,很雷士于JDNC规范。Hibernate最早是以ORM框架形式出来的,用来解决JDBC存在的问题。随着JPA标准的发展和完善,hibernate到后来也开始支持JPA规范,并且能够完全兼容JPA规范。也就说,hibernate是JPA标准的一个实现,还在此基础上增加了一些自己特有的功能。Hibernate 的注解相当对JPA的扩充。简称:Java持久化API
@Entity 注解将一个类声明为实体类,
@Table 为实体类指定对应数据库表
@Id 注解指定主键
@EmbeddedId 指定复合主键
@GenerateValue注解可以定义该标识符的生成策略
GenerationType.AUTO 自增,根据数据库,自动选择自增策略
GenerationType.IDENTITY 自增,针对mysql/sqlserver等数据库
GenerationType.SEQUENCE 针对oracle
例如:
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Version 注解用于支持乐观锁版本控制。
@Column 注解将属性映射到列
name属性允许将显式指定列的名称。
length 属性允许用于映射一个value尤其是对一个字符串值的列的大小。
nullable 属性允许该列被标记为NOT NULL生成架构时。
unique 属性允许被标记为只包含唯一值的列。
@JoinColumn注解定义关联关系
@GenericGenerator hibernate特有的注解,使用hibernate的主键生成策略
@Entity //实体类
@Table(name = "t_person") //设置映射的表名
public class Person {
@Id //对应表中的主键
@GeneratedValue(strategy = GenerationType.IDENTITY) //主键值的生成方式 IDENTITY:自增
@Column(name = "id") //如果字段名和属性值一致,可以不写
private Integer id;
@Column(name = "pname")
private String name;
private Integer age;
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
public Person() {
}
public Person(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
get & set ……
}
注:如果想实现xml中invser = true 的功能,在关系注解里,需要配置mapperBy
mappedBy的值来自Employee(员工)类中的 Department(部门) 对象的属性值
@OneToMany:一对多
@ManyToMany:多对多
@ManyToOne:多对一关系注解中没有 mappedBy 属性。
部门实体类:
@Entity//实体类
@Table(name = "dept")//设置映射的表名
public class Department {
@Id//主键
//hibernate 扩展的注解
// name:生成器的名称
// strategy:生成器的策略
@GenericGenerator(name = "mygen" , strategy = "native" )
@GeneratedValue(generator = "mygen")//根据name值指定一个生成器
private Integer did;
private String dname;
@OneToMany//一对多关系使用次注解
@JoinColumn(name = "deptId")//指定关联关系中的外键(员工 Employee 实体中的外键)
/**
* 如果想实现xml中invser = true 的功能,注解里,需要配置mappedBy
* mappedBy的值来自Employee(员工)类中的 Department(部门) 对象的属性值
* 注:使用mappedBy , 就不能使用@JoinColumn
* @OneToMany(mappedBy = "dept")
*/
private Set empSet;// 一个部门下有多个员工
get and set ……
}
package com.qfedu.many2many;
import javax.persistence.*;
@Entity//实体
@Table(name = "emp")
public class Employee {
@Id//主键
@GeneratedValue(strategy = GenerationType.IDENTITY) //主键值的生成方式 IDENTITY:自增
private Integer eid;
private String ename;
@ManyToOne//多对一使用次注解
@JoinColumn(name = "deptId")//指定关联关系中的外键
private Department dept;// 员工属于一个部门
get & set ……
}
一个学生有多个课程,一个课程有多个学生
@Entity//实体类
@Table(name = "student")//映射的表名
public class Student {
@Id//主键
@GeneratedValue(strategy = GenerationType.IDENTITY)//主键自增
private Integer sid;
private String sname;
@ManyToMany//多对多映射
/**
* @JoinTable:配置中间表的表名
* JoinColumns:和本类中设置的表的关联的外键
* inverseJoinColumns:和另外一个类中的表关联外键(这里指的是Student类)
* @JoinColumn:对应的字段
*/
@JoinTable(name = "stu_course" ,
joinColumns = {@JoinColumn (name = "sId")},
inverseJoinColumns = {@JoinColumn(name = "cId")})
private Set courseSet;
get & set ……
}
@Entity//实体类
@Table(name = "course")//映射的表名
public class Course {
@Id//主键
@GeneratedValue(strategy = GenerationType.IDENTITY)//主键自增
private Integer cid;
private String cname;
@ManyToMany//多对多映射
/**
* @JoinTable:配置中间表的表名
* JoinColumns:和本类中设置的表的关联的外键
* inverseJoinColumns:和另外一个类中的表关联外键(这里指的是Student类)
* @JoinColumn:对应的字段
*/
@JoinTable(name = "stu_course" ,
joinColumns = {@JoinColumn (name = "cId")},
inverseJoinColumns = {@JoinColumn(name = "sId")})
private Set stuSet;
get & set ……
}