Java - 框架之 Hibernate
一:hibernate.cfg.xml 配置
<!-- 1、配置数据库连接的4个参数 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 连接数据库,本地数据库可以不用设置主机和端口 -->
<property name="hibernate.connection.url">jdbc:mysql:///hibernate_01</property>
<!-- jdbc:mysql://localhost:3306/数据库名 -->
<!-- 用户名/密码 -->
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">chaoqi</property> <!-- 是否显示sql语句 -->
<property name="show_sql">true</property> <!-- 是否格式化sql语句 -->
<property name="format_sql">true</property> <!-- 是否自动提交事务:针对insert有效,针对delete无效 -->
<property name="hibernate.connection.autocommit">true</property> <!-- 配置值 JavaBean 与表的映射文件 -->
<mapping resource="com/q/hibernate/user.hbm.xml" />
二:类 xml 配置
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- name: 映射的类,table: 操作的数据库 -->
<class name="com.q.hibernate.User" table="t_user">
<!-- <id>: 与数据库对应id值, name: 类中id属性, column: 表中id属性 (类和表中的字段如果一样可以不用写 column) -->
<id name="uid" column="id">
<!-- 设置自增ID -->
<generator class="native"></generator>
</id> <!-- 添加字段(name, password) 由于数据库中字段名一样所以不用写 column 属性 -->
<property name="username"></property>
<property name="password"></property>
</class>
</hibernate-mapping>
三:插入数据
// 1. 获取核心配置对象,默认是加载src的hibernate.cfg.xml文件
Configuration cfg = new Configuration().configure(); // 2. 创建会话工厂
SessionFactory factory = cfg.buildSessionFactory(); // 3. 创建会话【相当于连接 Connect】
Session session = factory.openSession(); // 开启事务
Transaction trans = session.getTransaction();
trans.begin(); // 实例化要插入数据的对象
User user = new User();
user.setUsername("q3");
user.setPassword("123"); // 保存在 session 中
session.save(user); // 提交事务
trans.commit(); // 4. 关闭会话
session.close(); // 5. 关闭工厂,释放资源
factory.close();
四. sessionFactory 提供类两个方式获取 session
1. factory.openSession() # 获取一个权限的 session (重新开启一个新的线程, 需要手动 close )
2. factory.getCurrentSession() # 获取一个与当前线程绑定的 session (同一个线程里面调用返回同一个对象)
- 配置:
<property name="hibernate.current_session_context_class">thread</property>
// 开启一个线程:
new Thread(){
public void run(){
System.out.println("new thread");
}
}.start();
五. Transaction 事务
1. 默认需要手动提交事务:
// 开启事务
Transaction trans = session.getTransaction();
trans.begin();
// 提交事务
trans.commit();
2. 可在 hibernate.cfg.xml 文件中自动配置提交
<!-- 是否自动提交事务:针对insert有效,针对delete无效 -->
<property name="hibernate.connection.autocommit">true</property>
5.5. session 的 get / load 方法
1. 通过 id 获取数据
2. get : 未找到数据返回 null (直接查询数据库)
User user1 = (User) session.get(User.class, 1);
3. load: 未找到数据报错 (懒加载,用到时才去查询数据库,返回的是对象的一个代理)
User user2 = (User) session.load(User.class, 1);
六. session 的 delete / update 方法
1. update:
// 如果是从数据库中获取的对象,会自动 update
// 如:
// User user = (User) session.get(User.class, 1);
// user.setPassword("123"); // 创建的对象需要手动更新
User user = new User();
user.setUid(1);
user.setUsername("a");
user.setPassword("b"); session.update(user); // 更新时, 一定要有id, 否则会出现异常
session.saveOrUpdate(user); // 有就更新,没有就创建
2. delete : 需要手动提交事务
// 开启事务
session.getTransaction().begin(); 方式一:(创建一个 User,设置 id, 调用delete)
User user = new User();
user.setUid(1);
session.delete(user); 方式二:(获取删除对象,调用delete)
User user = (User) session.get(User.class, 1);
session.delete(user); // 提交事务
session.getTransaction().commit();
七. Query 查询 (HQL)
1. // 创建查询对象 User username password
Query query = session.createQeury("from 类名 where 字段=? and 字段?")
query.setParameter(0, "a");
query.setParameter(1, "b"); // 执行 (返回一条数据)
User user = (User) query.uniqueResult();
2. 分页查询 limit
// 创建查询对象
Query query = session.createQuery("from User"); // 分页查询 [limit 3,3]
query.setFirstResult(3); // 起始位置
query.setMaxResults(3); // 返回数据条数 // 返回多条数据
List<User> list = query.list();
for(User obj : list){
System.out.println(obj);
}
八. Criteria 查询 (条件查询)
// 创建 Criteria 查询
Criteria criteria = session.createCriteria(User.class); // 1. eq : =
criteria.add(Restrictions.eq("username","q"));
criteria.add(Restrictions.eq("username","123"));
System.out.println(criteria.uniqueResult()); // 2. gt 等于, ge 大于等于
criteria.add(Restrictions.gt("id", 3));
System.out.println(criteria.list()); // 3. lt 小于, le 小于等于 // 4. like 模糊查询
criteria.add(Restrictions.like("username", "%q%"));
System.out.println(criteria.list()); // 看文档...
九. SQLQuery 查询 原生(SQL)
// 查询
SQLQuery query = session.createSQLQuery("select * from user"); // 返回的数组封装到了集合,集合中是数组
List<Object[]> list = query.list();
for(Object[] objs : list){
for(Object obj : objs){
System.out.println(obj);
}
}
十. hibernate 配置文件
1. update : 更新,如果数据库没有表,会自动创建。
2. create : 每次启动 hibernate 都会创建表。
3. create-drop : 每次启动 hibernate 都会创建表,执行结束后会删除表。
4. 数据库方言配置:
mysql:
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</proterty>
十一. 实体类 entity (model) 的编写规则 和 OID
entity:
1. 必须提供无参数的构造方法。
2. 提供一个标识属性,映射数据库主键字段,提供id。
3. 所有属性提供 public 访问控制符的 get/set 方法 (JavaBean)。
4. 标识属性尽量使用包装类型。
5. 不能使用 final 修饰实体 (将无法生成代理对象进行优化)。
OID: 持久化对象的唯一标识
1. 对象的 OID 和 数据库中标的主键对应。
十二. 主键生成
< id name="id" column="id"> 1. native : mysql 数据库自增, oracle数据库自增。
2. uuid : 需要将类中的 id 字段改为 字符类型,自动设置 uud。
3. increment : 自增,hibernate 执行 select max(id) 查询,有并发问题。
4. sequence : oracle 数据库使用。
5. assigned : 需手动设置 id <generator class="native"></generator>
</id>
十三. hibernate 实体的状态
三种状态:瞬时状态,持久状态,脱管状态
1. 瞬时状态:transient, session 没有缓存,数据库没有记录,oid 没有值。
load, get 返回持久对象,关闭session或清除后会变成脱管状态。
2. 持久状态:persistent, session 有缓存,数据库有记录,oid 有值。
使用 save, saveOrUpdate 。
3. 脱管状态:detached, session 没有缓存,数据库有记录,oid 有值。
十四. 一级缓存
当获取一次 session ,hibernate 在 session 中创建多个集合,用于存放操作数据,优先从session缓存中获取,
当 session 关闭时,一级缓存销毁。
HQL / Criteria 有一级缓存
SQL 没有一级缓存
1. 使用 get 方法时会触发一级缓存,查询同一条语句时,只会执行一条 查询sql
2. 清除缓存: session.clear(); / session.evict(s);
3. 一级缓存快照:与一级缓存一样的存放位置,对一级缓存数据备份。保证数据库的数据与一级缓存中的数据一致,
如果一级缓存修改了,在执行 commit 提交时,将自动刷新一级缓存,执行 update 语句,并更新到数据。
4. 一级缓存刷新:手动刷新,让一级缓存的数据和数据库保持一致。
sesson.flush();
十五. save / persist
1. save:
// 执行save方法,触发 insert 语句,从数据库获取主键。
// 执行save前,设置oid会被忽略。
// 如果执行查询,session缓存被清除了,再次执行save方法,将执行 insert
2. persist
// 保存对象前,不能设置 Id ,否则报错。
// 在事务外部调用不会执行 insert ,在事务内部中结束后执行 insert。
十六. 一对多
1. Customer
private Integer id;
private String name; // 一对多属性描述
private Set<Order> orders = new HashSet<Order>();
2. Order
private Integer id;
private String name; private Customer customer;
3. customer.hbm.xml
<hibernate-mapping package="domain">
<class name="Customer" table="t_customer">
<id name="id">
<generator class="native" />
</id> <property name="name" /> <!--
cascade : 级联
save-update : 级联保存,级联修改,保存A的同时保存B。
delete : 级联删除,删除A的同时删除B。(先删B,再删A)
delete-orphan : 删除A关联的B ,但不删除A all = [ save-update, delete ] (级联保存, 级联删除)
all-delete-orphan = [ save-update, delete, delete-opphan ] -->
<set name="orders" cascade="all-delete-orphan">
<key column="customer_id"></key>
<one-to-many class="Order"></one-to-many>
</set>
</class>
</hibernate-mapping>
4. order.hbm.xml
<hibernate-mapping package="domain">
<class name="Order" table="t_order">
<id name="id">
<generator class="native" />
</id> <property name="name" /> <many-to-one name="customer" class="Customer" column="customer_id" /> </class>
</hibernate-mapping>
# 一对多操作
5. 创建数据
// 0. 开启事务
session.getTransaction().begin(); // 1. 创建客户对象
Customer customer = new Customer();
customer.setName("q"); // 2. 创建订单对象
Order order1 = new Order();
order1.setName("商品1");
Order order2 = new Order();
order2.setName("商品2"); // 3. 给订单建立客户关系
order1.setCustomer(customer);
order2.setCustomer(customer); // 4. 给客户添加订单
customer.getOrders().add(order1);
customer.getOrders().add(order2); // 5. 保存数据
session.save(customer);
session.save(order1);
session.save(order2); // 6. 结束事务
session.getTransaction().commit();
6. 查询数据
Customer customer = (Customer) session.get(Customer.class, 1); // 获取用户
String customer1 = customer.getName();
System.out.println(customer1); // 获取用户当前所有订单
Set<Order> orders = customer.getOrders();
for(Order order : orders){
System.out.println(order.getName());
}
7. 删除数据
Customer customer = (Customer) session.get(Customer.class, 1); session.getTransaction().begin(); // 更新订单
for(Order order : customer.getOrders()){
order.setCustomer(null);
} // 删除用户
session.delete(customer);
8. 级联更新
Customer customer = new Customer();
customer.setName("q"); Order order1 = new Order();
Order order2 = new Order();
order1.setName("d1");
order2.setName("d2"); order1.setCustomer(customer);
order2.setCustomer(customer); customer.getOrders().add(order1);
customer.getOrders().add(order2); session.save(customer);
9. 级联删除 先删 B 再删 A
session.getTransaction().begin(); Customer customer = (Customer) session.get(Customer.class, 2);
session.delete(customer); session.getTransaction().commit();
10. 级联删除 删除与A关联的B 但是不删除 A
session.getTransaction().begin(); Customer customer = (Customer) session.get(Customer.class, 1); Set<Order> orders = customer.getOrders();
Iterator<Order> iterator = orders.iterator(); while(iterator.hasNext()){
iterator.next(); // 取出下一个元素
iterator.remove(); // 移除当前元素
} session.getTransaction().commit();
十七. 多对多
1. Order
private Integer id;
private String name; private Customer customer;
2. Course
private Integer cid;
private String name;
private Set<Student> students = new HashSet<Student>();
3. Student.hbm.xml
<hibernate-mapping package="domain">
<class name="Order" table="t_order">
<id name="id">
<generator class="native" />
</id> <property name="name" /> <many-to-one name="customer" class="Customer" column="customer_id" /> </class>
</hibernate-mapping>
4. Course.hbm.xml
<hibernate-mapping package="domain">
<class name="Course" table="t_course">
<id name="cid" column="id">
<generator class="native"></generator>
</id> <property name="name" /> <set name="students" table="t_student_course" cascade="save-update">
<key column="cid"></key>
<many-to-many class="Student" column="sid" />
</set> </class>
</hibernate-mapping>
# 多对多操作
注意事项:
1. 在xml配置文件中 set 属性要加上: cascade="save-update" 才会自动创建表
2. 如果在 Student配置 inverse="true", 由Course来维护外键关系,中间表没数据。
3. 默认Student配置 inverse="false", 由 Student来维护外键关系,中间表有数据。
4. 多对多,inverse 不能两边都为 true, 如果两边都为 true, 不管保存哪个对象,中间表都没数据。
5. 创建数据
session.getTransaction().begin(); // 创建学生对象
Student stu1 = new Student("ming");
Student stu2 = new Student("pang"); // 创建课程对象
Course c1 = new Course("Java");
Course c2 = new Course("Python"); // 将课程绑定学生
stu1.getCourses().add(c1);
stu1.getCourses().add(c2); stu2.getCourses().add(c1);
stu2.getCourses().add(c2); // 创建保存
session.save(stu1);
session.save(stu2); session.getTransaction().commit();
6. 查询
Student stu1 = (Student) session.get(Student.class,3); System.out.println(stu1);
System.out.println(stu1.getCourses()); // Set<Course> courses = stu1.getCourses();
// System.out.println(courses);
十八. 锁
1. 写锁
当线程A拿到 数据行 d 的锁时,其它线程无法对 数据行 d 进行操作,会阻塞住,直到线程A释放(commit)。
session.getTransaction().begin(); //Hibernate的写锁/排他锁实现
/**
* 演示客户名,查找id为1
* A线程【命令行】,开启事务->读取一行数据加锁
* B线程【应用程序】,开启事务->读取一行数据加锁
*/ //执行sql语句,使用写锁
/*Customer customer = (Customer) session.get(Customer.class,1, LockOptions.UPGRADE);
System.out.println(customer);*/ /**
* HQL的from后面不能写for update
* 调用query.setLockOptions(LockOptions.UPGRADE);
*/
Query query = session.createQuery("from Customer where id=?");
query.setLockOptions(LockOptions.UPGRADE);
query.setParameter(0,1); Customer customer = (Customer) query.uniqueResult();
System.out.println(customer); session.getTransaction().commit();
2. 乐观锁
在数据库增加一个字段(verson),每次更新不同的数据会对字段值+1(verson+1) ,
如果本次更新值后verson+1 小于数据中verson值,那么会报错。
# 需要配置 XML 中的 verson
<!--version 放在id和property的中间,这个由dtd约束决定-->
<version name="version"></version>
# 操作
session.getTransaction().begin(); //乐观锁:每次更新,版本会加1
/**
* 如果当前的版本【2】比数据库【3】低,就不更新,出错
* 乐观锁是hibernate自己实现
* for update 是mysql实现
*/
Customer customer = (Customer) session.get(Customer.class,1);
customer.setName("abc232"); session.getTransaction().commit();
十九. 一对一
1. Company
private Integer id;
private String name;
private Address address;
2. Address
private Integer id;
private String name;
private Company company;
3. Company.hbm.xml
<class name="Company" table="t_company">
<id name="id" column="id">
<generator class="native"></generator>
</id> <property name="name" /> <one-to-one name="address" class="Address"></one-to-one> </class>
4. Address.hbm.xml
<class name="Address" table="t_address">
<id name="id" column="id">
<!-- 主键又是外键 -->
<generator class="foreign">
<param name="property">company</param>
</generator>
</id> <property name="name" /> <many-to-one name="company" class="Company" column="company_id" unique="true"></many-to-one> <!-- 设置主键就是外键 -->
<!--<one-to-one name="company" class="Company" constrained="true"></one-to-one>--> </class>
# 一对一操作
5. 创建数据
session.getTransaction().begin(); Company company1 = new Company();
company1.setName("Ali"); Address address1 = new Address();
address1.setName("China");
address1.setCompany(company1); session.save(company1);
session.save(address1); session.getTransaction().commit();
6. 查询数据
Company company = (Company) session.get(Company.class, 1); System.out.println(company.getName());
System.out.println(company.getAddress().getName());
二十. c3p0 连接池(配置在 hibernate.cfg.xml)
<!-- 配置 c3p0 -->
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.max_size">2</property>
<property name="hibernate.c3p0.min_size">2</property>
<property name="hibernate.c3p0.timeout">5000</property>
<property name="hibernate.c3p0.max_statements">100</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<property name="hibernate.c3p0.acquire_increment">2</property>
<property name="hibernate.c3p0.validate">false</property>
二十一. 二级缓存
1. 类缓存:
查询后会在类缓存中存储这个类对象,再次查询的时候会匹配查询类和缓存中的类对象是否一致,然后返回结果,没有则去数据库。
2. 集合缓存
在集合缓存中存储的是类id,然后通过id去类缓存中找匹配的类对象,然后返回结果,没有则去数据库。
3. 查询缓存
需要手动开启缓存,可以在不同的 session 中获取类对象,其还是去类缓存中查找。
4. 时间戳缓存
会将本次查询和上次查询进行匹配,如果一致则不去数据库查,直接返回上次结果。
5. ehache 缓存
如果缓存大小溢出,那么就会存储到ehache中的缓存空间中。
Java - 框架之 Hibernate的更多相关文章
- java框架篇---hibernate入门
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库. Hibernate可以应用在任何使用JDB ...
- Java框架之Hibernate(三)
本文主要讲解: 1 级联 cascade 关键字 2 级联删除 3 inverse 关键字 4 懒加载 5 缓存的模拟 6 Hibernate 的一级缓存 7 Hibernate 的二级缓存 一.级联 ...
- Java框架之Hibernate(一)
一.Hibernate - 核心接口 它是 JBoss Community team (社区团队) 开发的.Hibernate 是一个开源的,对象关系模型框架 (ORM),它对JDBC进行了轻量的封 ...
- JAVA框架之Hibernate框架的学习步骤
首先介绍一下Java三大框架的关系 以CRM项目即客户关系管理项目示例 hibernate框架的学习路线: 1.学习框架入门,自己搭建框架,完成增删改查的操作 2.学习一级缓存,事物管理和基本查询 3 ...
- java框架之Hibernate(1)-简介及初使用
简介 hibernate 是一个开源 ORM ( Object / Relationship Mipping ) 框架,它是对象关联关系映射的持久层框架,它对 JDBC 做了轻量级的封装,而我们 ja ...
- java框架之Hibernate(2)-持久化类&主键生成策略&缓存&事务&查询
持久化类 概述 持久化:将内存中的对象持久化到数据库中的过程就是持久化.Hibernate 就是用来进行持久化的框架. 持久化类:一个 Java 对象与数据库的表建立了映射关系,那么这个类在 Hibe ...
- java框架篇---hibernate之缓存机制
一.why(为什么要用Hibernate缓存?) Hibernate是一个持久层框架,经常访问物理数据库. 为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能. 缓存内的数据是对物理数 ...
- JAVA框架之Hibernate【配置文件详解】
Hibernate配置文件主要功能是配置数据库连接和Hibernate运行时所需的各种属性,配置文件应该位于JAVA应用或者JAVA Web应用的类文件中,刚开始接触Hibernate的时候,感觉Hi ...
- 【JAVA框架】Hibernate 与Mybatis 区别
Hibernate Mybatis 简介 区别 与联系 欢迎提出见解及转载. 1 简单简介 1.1 Hibernate 框架 Hibernate是一个开放源代码的对象关 ...
- Java框架之Hibernate(四)
本文主要介绍: 1 悲观锁和乐观锁 2 使用版本号控制并发访问 3 flush方法和批量更新的问题 4 DetachedCriteria 5 N + 1 次查询 6 使用sql进行查询 7 注解方式 ...
随机推荐
- Apache Kafka安全| Kafka的需求和组成部分
1.目标 - 卡夫卡安全 今天,在这个Kafka教程中,我们将看到Apache Kafka Security 的概念 .Kafka Security教程包括我们需要安全性的原因,详细介绍加密.有了这 ...
- python大道——博客目录
python基础 第一章 计算机基础 计算机基础 第二章 python基础语法 python入门 第三章 基础数据类型和文件操作 整型.布尔.字符串 列表.字典.集合 公共功能.小数据池 hash ...
- 38 多线程(十)——volatile 数据同步
在多线程并发的情况下,同一个变量被多个线程调用,那修改的数据就不会每分每秒保持一致.例如,对于某个变量a,线程1对它进行一套操作,线程2又对它进行另一套操作,但如果cpu太忙了,太忙了,假设cpu都用 ...
- while 语句的逻辑
# i =3# username = '大天天'# password = 123# while i > 0:# name = input('请输入你的名字:')# i -= 1# if name ...
- LOJ3123 CTS2019 重复 KMP自动机、DP、多项式求逆
传送门 CTS的计数题更完辣(撒花 Orz zx2003,下面的内容在上面的博客基础上进行一定的补充. 考虑计算无限循环之后不存在子串比\(s\)字典序小的串的个数.先对串\(s\)建立KMP自动机, ...
- JDK提供的原子类和AbstractQueuedSynchronizer(AQS)
大致分成: 1.原子更新基本类型 2.原子更新数组 3.原子更新抽象类型 4.原子更新字段 import java.util.concurrent.atomic.AtomicInteger; impo ...
- 动画处理<并行和串行>
并行动画 当多个动画定义同时指向某个组件,并使用动画控制器启动时,就产生了并行动画(Parallel Animation).例如我们可以让一个组件: 移动的同时改变大小 旋转的同时边界颜色闪烁 圆形图 ...
- FreeRTOS任务运行时间信息统计
相关宏的设置 configGENERATE_RUN_TIME_STATS //使能 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() //配置一个高精度定时器/计数器提 ...
- java中将对象引用设置为null对于GC有没有帮助
相信,网上很多java性能优化的帖子里都会有这么一条: 尽量把不使用的对象显式得置为null.这样有助于内存回收 可以明确的说,这个观点是基本错误的.sun jdk远比我们想象中的机智.完全能判断出对 ...
- 微信小程序跑马灯效果--基于CSS3 animation 及 基于JS
如果本文对你有用,请爱心点个赞,提高排名,帮助更多的人.谢谢大家!❤ 如果解决不了,可以在文末进群交流. 基于CSS3主要代码实现 效果图: 视图模板wxml中: <view class=&qu ...