1 缓存
1.1 什么是缓存?
- 数据存到数据库里面,数据库本身是文件系统,使用流操作文件效率不是很高。将数据存在内存里面不需要使用流的方式,可以直接读取内存中的数据。把数据收到内存中可以提高读取效率。
- 提供缓存的目的是为了让数据访问的速度适应CPU的处理速度。
1.2 Hibernate的一级缓存
- hibernate的一级缓存是默认打开的。
- hibernate的一级缓存的使用范围是session的范围,即从session被实例化到被关闭的过程。
- hibernate的一级缓存中,存储的数据必须是持久态(由session获得的)的数据。
- hibernate的二级缓存默认不是打开的,并且现在都用redis去代替它,其使用范围为sessionFactory范围
1.3 验证一级缓存的存在
- 验证方式:两次查询uid = 1的对象,第一次会查数据库,第二次就会从缓存中取
Students students = session.get(Students.class,3);
Students students2 = session.get(Students.class,3);
只有第一句会向数据库发送sql语句。
1.4 一级缓存的执行过程
- 调用Students students = session.get(Students.class,3);后
- 首先查询一级缓存区,查看是否存在id = 3的这个对象,如果存在则直接返回。
- 如果不存在,则向数据库发送请求,返回的对象再存入一级缓存中。
1.5 一级缓存特性-持久态自动更新数据库
- 持久态数据会自动更新数据库而不需要去调用类似session.update()方法。
Students students = session.get(Students.class,3);
students.setName("jacob");
//session.update(students);//不需要调用update也会更新数据库
-
原理如下图:
2 事务标准写法
@Test
public void testTX(){
StandardServiceRegistry standardServiceRegistry = null;
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try {
standardServiceRegistry = new StandardServiceRegistryBuilder().configure().build();
sessionFactory = new MetadataSources(standardServiceRegistry).buildMetadata().buildSessionFactory();
session = sessionFactory.openSession();
//开启事务
tx = session.beginTransaction();
Students students = session.get(Students.class,3);
students.setGender("女");
//抛出异常,回滚,性别仍是男
int a = 1/0;
System.out.println(a);
students.setGender("男");
tx.commit();
}catch (Exception e){
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
3 三种查询api
- Query对象
Query query = session.createQuery("from Students");
List list = query.list();
for(Students student:list){
System.out.println(student);
}
- Criteria对象
Criteria criteria = session.createCriteria(Students.class);
List list = criteria.list();
for(Students student:list){
System.out.println(student);
}
- SQLQuery对象
//返回数组类型
SQLQuery sqlQuery = session.createSQLQuery("select * from students");
List
//返回对象类型
SQLQuery sqlQuery = session.createSQLQuery("select * from students");
sqlQuery.addEntity(Students.class);
List list = sqlQuery.list();
for(Students students:list){
System.out.println(students);
}
4 一对多操作
4.1 一对多配置
- 以联系人与客户为例,客户是一,联系人是多。
- 创建两个实体类,客户和联系人。
- 让两个实体类互相表示。
- 创建映射文件,配置一对多关系。(映射文件中,表示所有联系人)
- 配置多对一关系。(映射文件中,表示所属客户)。
- 将映射文件引入核心配置文件。
- 接来下是各个步骤对应的代码:
1/2. 实体类创建并互相表示
import java.util.List;
public class Customer {
private Integer cid;
private String custName;
private String custLevel;
private String custSource;
private String custPhone;
private String custMobile;
private List list;
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public Customer() {
}
public Customer(Integer cid, String custName, String custLevel, String custSource, String custPhone, String custMobile, List list) {
this.cid = cid;
this.custName = custName;
this.custLevel = custLevel;
this.custSource = custSource;
this.custPhone = custPhone;
this.custMobile = custMobile;
this.list = list;
}
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getCustName() {
return custName;
}
public void setCustName(String custName) {
this.custName = custName;
}
public String getCustLevel() {
return custLevel;
}
public void setCustLevel(String custLevel) {
this.custLevel = custLevel;
}
public String getCustSource() {
return custSource;
}
public void setCustSource(String custSource) {
this.custSource = custSource;
}
public String getCustPhone() {
return custPhone;
}
public void setCustPhone(String custPhone) {
this.custPhone = custPhone;
}
public String getCustMobile() {
return custMobile;
}
public void setCustMobile(String custMobile) {
this.custMobile = custMobile;
}
}
public class Contacter {
private Integer conId;
private String conName;
private String conGender;
private String conPhone;
private Customer customer;
public Contacter() {
}
public Contacter(Integer conId, String conName, String conGender, String conPhone, Customer customer) {
this.conId = conId;
this.conName = conName;
this.conGender = conGender;
this.conPhone = conPhone;
this.customer = customer;
}
public Integer getConId() {
return conId;
}
public void setConId(Integer conId) {
this.conId = conId;
}
public String getConName() {
return conName;
}
public void setConName(String conName) {
this.conName = conName;
}
public String getConGender() {
return conGender;
}
public void setConGender(String conGender) {
this.conGender = conGender;
}
public String getConPhone() {
return conPhone;
}
public void setConPhone(String conPhone) {
this.conPhone = conPhone;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
- 创建映射文件配置一对多关系
- 创建多对一关系
- 导入配置文件
- 编写工具类 + 测试
public class HibernateUtils {
static StandardServiceRegistry ssregistry = null;
static SessionFactory sessionFactory = null;
static {
ssregistry = new StandardServiceRegistryBuilder().configure().build();
sessionFactory = new MetadataSources(ssregistry).buildMetadata().buildSessionFactory();
}
public static Session getSessionObject(){
return sessionFactory.getCurrentSession();
}
public static SessionFactory getSessionFactory(){
return sessionFactory;
}
public static void main(String []args){
}
}
运行该类即可发现数据库创建了两张表。
4.2 级联保存
- 方式一:
public class HibernateOneToManyTest {
@Test
public void oneToManyTest(){
Session session = null;
SessionFactory sessionFactory = null;
Transaction tx = null;
try{
sessionFactory = HibernateUtils.getSessionFactory();
session = HibernateUtils.getSessionObject();
tx = session.beginTransaction();
Customer customer = new Customer();
customer.setCustLevel("vip");
customer.setCustMobile("111");
customer.setCustName("阿里巴巴");
customer.setCustSource("网络");
customer.setCustPhone("222");
Contacter contacter = new Contacter();
contacter.setConGender("男");
contacter.setConName("jacob");
contacter.setConPhone("333");
customer.getList().add(contacter);
contacter.setCustomer(customer);
session.save(customer);
session.save(contacter);
tx.commit();
}catch (Exception e){
e.printStackTrace();
tx.rollback();
}finally {
session.close();
sessionFactory.close();
}
}
}
- 方式二:
- 首先在映射文件中添加配置cascade="save-update"
- 代码:
Customer customer = new Customer();
customer.setCustLevel("vip");
customer.setCustMobile("111");
customer.setCustName("因特尔");
customer.setCustSource("网络");
customer.setCustPhone("222");
Contacter contacter = new Contacter();
contacter.setConGender("男");
contacter.setConName("rose");
contacter.setConPhone("333");
customer.getList().add(contacter);
session.save(customer);
4.3 级联删除
-
有外键关联时的删除做法。
直接删除一个customer是会报错的,因为有外键对其关联。
- 做法步骤应如下:
- 删除从表的对应数据
- 删除主表对应数据
- 级联删除的步骤如下:
- 在客户映射文件进行配置
Customer customer = session.get(Customer.class,2);
session.delete(customer);
4.4 更改联系人
Customer customer = session.get(Customer.class,1);
Contacter contacter = session.get(Contacter.class,11);
customer.getList().add(contacter);
contacter.setCustomer(customer);
- 问题在于会进行两次外键设置,使得运行负担较大。
- 解决方法 inverse="true"