hibernate

1.什么是hibernate

  • Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库

2.使用hibernate

  1. 首先创建一个maven的web项目

  2. 在maven项目里面加入hibernate和你使用的数据库驱动(这里我用的是一个mysql)的依赖

    	<dependency>
    			<groupId>org.hibernate</groupId>
    			<artifactId>hibernate-core</artifactId>
    			<version>5.4.10.Final</version>
    		</dependency>
    
    		<dependency>
    			<groupId>mysql</groupId>
    			<artifactId>mysql-connector-java</artifactId>
    			<version>5.1.44</version>
    		</dependency>
    

3.hibernate的工作流程

如果只是单独的说一个Hibernate的流程主要分为以下八个步骤:

1.读取并解析配置文件(Hibernate_config.xml) 创建Configuration类的实例,它的构造方法将配置文件读入到内存中,一个Configuration实例代表Hibernate所有Java类到数据库映射的集合。

2.读取并解析映射信息,创建SessionFactory实例把Configuration对象中的所有配置信息拷贝到SessionFactory缓存中。SessionFactory的实例代表一个数据库存储源,创建后不再与Configuration对象关联。

3.调用SessionFactory创建Session的方DAA法,打开Sesssion

Session session = sessionFactory.openSession();

但在SSH框架中打开Session的过程交给了org.springframework.orm.hibernate3.support.OpenSessionInViewFilter

4.创建事务Transation

5.持久化操作, 通过Session接口提供的各种方法来操纵数据库访问

*6.*提交事务

7.关闭Session

8.关闭SesstionFactory

而在SSH框架中,Hibernate很多步骤都交给了Spring容器管理比如加载配置文件、打开和关闭Session、事务管理*….*等等

4.hibernate的配置

  1. 创建一个hibernate.cfg.xml
	<session-factory>
		<property name="connection.username">root</property>  	<!--配置与数据连接的用户名  -->
		<property name="connection.password">123456</property>	<!--密码  -->
		<property name="connection.url">jdbc:mysql://localhost:3306/bookshop?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false</property>	<!-- url -->
		<property name="connection.driver_class">com.mysql.jdbc.Driver</property>	<!--驱动所在的位置  -->
		<!-- 方言 每种类型的数据库的方言不同,我这里使用的是一个mysql -->
		<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
		
		<property name="show_sql">true</property><!-- 是否可以显示sql语句  (true 可以显示   false显示)-->
		<property name="format_sql">true</property><!--让显示的sql更加的工整 -->
		
		<!-- 映射文件 (hibernate.cfg.xml是hibernate的默认配置文件,一般会加载这个文件。在这个文件里里面的所有的映射放到Configuration,再通过这个Configuration创建SessionFactory。在执行对应的增删改查的方法。所以需要把表与数据的映射放到hibernate.cfg.xml中)-->
		<mapping resource="mapping/User.hbm.xml"/>  
		
	</session-factory>
  1. 创建数据库表和实体bean和数据的对应

    创建数据库表(t_user)

    create table t_user
    (
      id int not null primary key,                                      -- ID:主键,注:没有设置为自动增长
      user_name varchar(50) not null,                                   -- 用户名                                
      user_pwd varchar(10) not null,                                    -- 密码
      real_name varchar(50),                                            -- 真实姓名
      sex char(2),                                                      -- 性别                 
      birthday datetime,                                                -- 出生日期
      create_datetime timestamp NULL default CURRENT_TIMESTAMP,         -- 创建日期时间,默认为系统当前时间
      remark varchar(1024)                                              -- 备注
    );
    
    
    insert into t_user(id,user_name,user_pwd,real_name,sex,birthday,create_datetime,remark)
      values(1,'zs','123','张三','男',20001010,null,'abcd');
    	
    insert into t_user(id,user_name,user_pwd,real_name,sex,birthday,remark)
      values(2,'ls','123','李四','男',20001110,'xyz');
    

    创建一个实体bean

    public class User implements java.io.Serializable {
    	
    	private Integer id;
    	
    	private String userName;
    	
    	private String userPwd;
    	
    	private String realName;
    	
    	private String sex;
    	
    	private Date birthday;
    	
    	private Date createDatetime;
    	
    	private String remark;
    
    	//... 生成getter,setter
    
    }
    

    配置实体bean的和数据库表(t_user)的关系映射

    <?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>
    	<class name="com.zking.hbdemo.entity.User" table="t_user">
    		<id name="id" type="java.lang.Integer">
    			<column name="id"/>
    			<generator class="increment"/>
    		</id>
    		<property name="userName" type="java.lang.String" column="user_name"/>
    		<property name="userPwd" type="java.lang.String" column="user_pwd"/>
    		<property name="realName" type="java.lang.String" column="real_name"/>
    		<property name="sex" type="java.lang.String" column="sex"/>
    		<property name="birthday" type="java.util.Date" column="birthday"/>
    		<property name="createDatetime" type="java.util.Date" column="create_datetime"/>
    		<property name="remark" type="java.lang.String" column="remark"/>
    	</class>
    </hibernate-mapping>
    

    说明:
    native : 由Hibernate根据底层数据库自行判断采用identity、sequence其中一种作为主键生成方式。
    identity : 采用数据库提供的主键生成机制
    sequence : 采用数据库提供的sequence 机制生成主键。如Oralce 中的Sequence
    increment: 主键按数值顺序递增。此方式的实现机制为在当前应用实例中维持一个变量,以保存着当前的最大值,之后每次需要生成主键的时候将此值加1作为主键。 在多线程情况下可能出现主键重复的问题(一般不在生成环境中使用)

5.操作的具体实例

public class HbDemo {
	//增加
	@Test
	public void testSave() {
		//1. 读取配置
		Configuration conf = new Configuration();
		conf.configure("hibernate.cfg.xml");
		
		//2. 通过Configuration对象创建SessionFactory
		SessionFactory sFactory= conf.buildSessionFactory();
		
		//3. 通过SessionFactory获取Session
		Session session = sFactory.openSession();
		
		//4. 开启事务
		Transaction transcation = session.beginTransaction();
		
		//5. 操作数据库 ....
		User user = new User();
		user.setUserName("aq");
		user.setUserPwd("123456");
		user.setRealName("测试");
		user.setRemark("测试记录");
		user.setBirthday(new Date(System.currentTimeMillis()));
		user.setCreateDatetime(new Date(System.currentTimeMillis()));
		
		//通过session执行保存
		Serializable row = session.save(user);
		System.out.println("影响行数  = " + row);
		
		//6. 提交事务
		transcation.commit();
		
		//7. 关闭Session
		session.close();
		
	}

}

6.对象的三种状态

在hibernate中对象中又三种状态:临时状态,持久状态,游离状态。三三种状态的转换图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Has1pivv-1596690948013)(新建文本文档.assets/image-20200802134708043.png)]

session.flush() 清空一级缓存
游离状态的对象发生状态也不会被更新到数据中,(快照消失,没有判断的依据)
session.evict(u)移除某一个

7. 加载策略

  1. 延迟加载, load()方法根据配置文件使用延时加载,默认为延时加载。

  2. 立即加载,session.get()忽略加载策略,使用立即加载。

  3. 区别

    • load方式检索不到的话会抛出org.hibernate.ObjectNotFoundException异常;get方法检索不到的话会返回null;

    • load方法的执行则比较复杂首先查找session的persistent Context(一级缓存)中是否有缓存,如果有则直接返回,如果没有则去查找二级缓存,如果有则返回,如果没有则判断是否是lazy,若不是lazy,直接访问数据库检索,查到记录返回(并且同时在二级缓存中存放查到的数据方便下次使用,若再下次使用时在二级缓存命中,就是查到数据,则有可能将数据放到

      一级缓存中。),查不到抛出异常。 若是lazy,则返回代理对象,而不到数据库中查找,除非使用此对象时,才到数据库中查找。

      get方法先到一级缓存,然后二级,最后db查找。

延迟加载实例(hibernate3默认lazy默认是true)

\\写一个测试的dao层
public class UserDao {
	
	public User load(int id) {
		Session session = SessionFactoryUtil.OpenSession();
		User user = session.load(User.class, id);
		SessionFactoryUtil.closeSession();
		return user;
	}

}
\\编写测试
public class UserDaoTest {
	
	private UserDao userDao = new UserDao();

	@Test
	public void testLoad() {
		
		User user = userDao.load(4);
		
		//id为主键,可正常输出
		System.out.println(user.getId());
		
		/*
		 * 此处将包异常,
		 * 原因:load为延时加载,此时只会预先加载主键值,userDao.load()方法返回,
		 * session将关闭,在需要使用非主键值时,根据延时加载策略,此时需要到数据库中
		 * 加载非主键值(延时加载,即使用时再加载),此时的session已经关闭。所以会报
		 * 出异常。
		 * load方法返回的实际上是一个代理对象,其中只用主键值(对象标识,oid)有值,其他的非
		 * 主键值是没有值的,在第一次使用非oid属性时在从数据库中去加载非oid属性的值。
		 * 作为测试,可以在load()方法返回前任意读取一个非oid属性,此处将不再抛出异常。
		 */
		System.out.println(user.getRealName());
	}

}

8.关联

关联分析又称关联挖掘,就是在交易数据、关系数据或其他信息载体中,查找存在于项目集合或对象集合之间的频繁模式、关联、相关性或因果结构。在hibernate存在着一对一和多对多,一对多的关联。

从对象的角度看,关联就是对象之间存在引用的关系

public class B {
    ...
}

public class A {
	private B b = new B();
	...
}

从数据库角度看,关联主要体现在外键上 ,比如一个表外键引用另一张的主键。

9.实例(一对多)

  1. 创建数据库的实例

    -- 订单表(主表)
    create table t_order
    (
      order_id int primary key auto_increment,
      order_no varchar(50) not null
    );
    
    
    -- 订单项表(从表)
    create table t_order_item
    (
      order_item_id int primary key auto_increment,
      product_id int not null,
      quantity int not null,
      oid int not null,
      foreign key(oid) references t_order(order_id)
    );
    
    
    -- 一对多双向自关联
    -- 菜单表
    -- t_sys_tree_node
    -- t:表
    -- sys:模块名缩写(system)
    -- tree_noe:表名
    create table t_sys_tree_node
    (
      tree_node_id int primary key auto_increment,                                                 -- ID
      tree_node_name varchar(50) not null,                                                         -- 名字
      tree_node_type int not null check(tree_node_type = 1 or tree_node_type = 2),                 -- 节点类型:1 枝节点 2 叶节点
    
      position bigint,                                                                             -- 位置
      parent_node_id int,                                                                         -- 父节点ID
      url varchar(1024),                                                                           -- URL
      foreign key(parent_node_id) references t_sys_tree_node(tree_node_id)
    );
    
    
    -- drop table t_sys_tree_node
    -- select * from t_sys_tree_node
    
    
    select * from t_sys_tree_node;
    truncate table t_sys_tree_node;
    
    
    insert into t_sys_tree_node(tree_node_id, tree_node_name, tree_node_type, position, parent_node_id, url)
      values(1,'系统管理',1, 1,null,null);
    insert into t_sys_tree_node(tree_node_id, tree_node_name, tree_node_type, position, parent_node_id, url)
      values(2,'市场管理',1, 2,null,null);
    
    insert into t_sys_tree_node(tree_node_id, tree_node_name, tree_node_type, position, parent_node_id, url)
      values(3,'字典管理',2, 3,1,null);
    insert into t_sys_tree_node(tree_node_id, tree_node_name, tree_node_type, position, parent_node_id, url)
      values(4,'用户管理',2, 4,1,null);
    insert into t_sys_tree_node(tree_node_id, tree_node_name, tree_node_type, position, parent_node_id, url)
      values(5,'角色管理',2, 5,1,null);
    insert into t_sys_tree_node(tree_node_id, tree_node_name, tree_node_type, position, parent_node_id, url)
      values(6,'权限管理',1, 6,1,null);
    
    insert into t_sys_tree_node(tree_node_id, tree_node_name, tree_node_type, position, parent_node_id, url)
      values(7,'进货管理',2, 7,2,null);
    insert into t_sys_tree_node(tree_node_id, tree_node_name, tree_node_type, position, parent_node_id, url)
      values(8,'销售管理',2, 8,2,null);
    insert into t_sys_tree_node(tree_node_id, tree_node_name, tree_node_type, position, parent_node_id, url)
      values(9,'库存管理',2, 9,2,null);
    
    insert into t_sys_tree_node(tree_node_id, tree_node_name, tree_node_type, position, parent_node_id, url)
      values(10,'用户分配角色',2, 10,6,null);
    insert into t_sys_tree_node(tree_node_id, tree_node_name, tree_node_type, position, parent_node_id, url)
      values(11,'角色授予用户',2, 11,6,null);
    
    1. 创建对象关系实例

      package com.zking.hibernatedemo2.entity;
      // Generated 2020-8-2 17:12:03 by Hibernate Tools 4.3.5.Final
      
      import java.util.HashSet;
      import java.util.Set;
      
      /**
       * TOrder generated by hbm2java
       */
      public class TOrder implements java.io.Serializable {
      
      	private Integer orderId;
      	private String orderNo;
      	
      	
      	private Set<TOrderItem> TOrderItems = new HashSet<TOrderItem>();
      
      	
      	private int  initOrderitem=0;
      	
      	
      	
      	public int getInitOrderitem() {
      		return initOrderitem;
      	}
      
      	public void setInitOrderitem(int initOrderitem) {
      		this.initOrderitem = initOrderitem;
      	}
      
      	public TOrder() {
      	}
      
      	public TOrder(String orderNo) {
      		this.orderNo = orderNo;
      	}
      
      	public TOrder(String orderNo, Set TOrderItems) {
      		this.orderNo = orderNo;
      		this.TOrderItems = TOrderItems;
      	}
      
      	public Integer getOrderId() {
      		return this.orderId;
      	}
      
      	public void setOrderId(Integer orderId) {
      		this.orderId = orderId;
      	}
      
      	public String getOrderNo() {
      		return this.orderNo;
      	}
      
      	public void setOrderNo(String orderNo) {
      		this.orderNo = orderNo;
      	}
      
      	public Set getTOrderItems() {
      		return this.TOrderItems;
      	}
      
      	public void setTOrderItems(Set TOrderItems) {
      		this.TOrderItems = TOrderItems;
      	}
      
      	@Override
      	public String toString() {
      		return "TOrder [orderId=" + orderId + ", orderNo=" + orderNo + ", TOrderItems=" + TOrderItems + "]";
      	}
      	
      	
      	
      
      }
      
      
      package com.zking.hibernatedemo2.entity;
      // Generated 2020-8-2 17:12:03 by Hibernate Tools 4.3.5.Final
      
      /**
       * TOrderItem generated by hbm2java
       */
      public class TOrderItem implements java.io.Serializable {
      
      
      
      	private Integer orderItemId;
      	private Integer productId;
      	private Integer quantity;
      	private Integer oid;
      	
      	//多对一
      	private TOrder TOrder;
      	public TOrderItem() {
      
      		
      	}
      	
      	public TOrderItem( Integer productId, Integer quantity, TOrder t) {
      		super();
      		
      		this.productId = productId;
      		this.quantity = quantity;
      		this.TOrder = t;
      		
      	}
      
      
      	public int getOid() {
      		return oid;
      	}
      
      	public void setOid(int oid) {
      		this.oid = oid;
      	}
      
      	public Integer getOrderItemId() {
      		return this.orderItemId;
      	}
      
      	public void setOrderItemId(Integer orderItemId) {
      		this.orderItemId = orderItemId;
      	}
      
      	public TOrder getTOrder() {
      		return this.TOrder;
      	}
      
      	public void setTOrder(TOrder TOrder) {
      		this.TOrder = TOrder;
      	}
      
      	public int getProductId() {
      		return this.productId;
      	}
      
      	public void setProductId(int productId) {
      		this.productId = productId;
      	}
      
      	public int getQuantity() {
      		return this.quantity;
      	}
      
      	public void setQuantity(int quantity) {
      		this.quantity = quantity;
      	}
      
      
      	@Override
      	public String toString() {
      		return "TOrderItem [orderItemId=" + orderItemId + ", productId=" + productId + ", quantity=" + quantity
      				+ ",oid="+oid+"]";
      	}
      	
      	
      
      }
      
      
    2. 配置文件实例

      <?xml version="1.0"?>
      <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
      "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
      <!-- Generated 2020-8-2 17:12:03 by Hibernate Tools 4.3.5.Final -->
      <hibernate-mapping>
          <class name="com.zking.hibernatedemo2.entity.TOrder" table="t_order" >
              <id name="orderId" type="java.lang.Integer">
                  <column name="order_id" />
                  <generator class="increment" />
              </id>
              <property name="orderNo" type="string">
                  <column name="order_no" />
              </property>
             
             
             <!--一对多  -->                                                            <!--inverse 表示主控方的意思默认是false。指定之后就是该类就是主控方  -->
              <set  name="TOrderItems" table="t_order_item" inverse="false" cascade="save-update" ><!-- cascade ="save-update" 表示保存和更新会级联处理-->
                  <key>
                      <column name="oid"/>
                  </key>
                  <one-to-many class="com.zking.hibernatedemo2.entity.TOrderItem" />
              </set>
          </class>
      </hibernate-mapping>
      
      
      <!-- cascade属性的配置项说明如下:
      
      none: 保存,更新或删除当前对象时,忽略其它关联的对象
      save-update:保存、更新时级联保存所有的临时对象,并且级联更新关联的游离对象
      delete:通过session的delete方法删除当前对象,级联删除关联的对象
      all:等于save-update操作+delete操作
      inverse:
      在一对多关系的配置中另外还配置了一个inverse属性,该属性的作用是设置主控方。默认值为false,true表示将对方设置为主控方(一对多双向关联中一般将多方设置为主控方,这样可以减少SQL语句的数量,减少多余的操作)。
      
      lazy:
      默认值为true,true延迟加载,false立即加载(一般设置为true,不使用立即加载,因为影响查询性能)-->
      
      <?xml version="1.0"?>
      <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
      "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
      <!-- Generated 2020-8-2 17:12:03 by Hibernate Tools 4.3.5.Final -->
      <hibernate-mapping>
          <class name="com.zking.hibernatedemo2.entity.TOrderItem" table="t_order_item">
              <id name="orderItemId" type="java.lang.Integer">
                  <column name="order_item_id" />
                  <generator class="increment" />
              </id>
            
              <property name="productId" type="java.lang.Integer">
                  <column name="product_id" />
              </property>
              <property name="quantity" type="java.lang.Integer">
                  <column name="quantity" />
              </property>
            
            <!--oid的属性值去order中的order_id,最简单的方式将该配置删掉,或者是配置 insert="false" -->
      		<!-- <property name="oid" type="java.lang.Integer" column="oid" insert="false" update="false"/> -->
              
                <many-to-one name="TOrder" class="com.zking.hibernatedemo2.entity.TOrder" >
                  <column name="oid"/>
             	 </many-to-one>
          </class>
      </hibernate-mapping>
      
      

    测试

    package com.zking.hibernatedemo2.dao;
    
    import javax.persistence.criteria.Order;
    
    import org.hibernate.Hibernate;
    import org.hibernate.Session;
    import org.hibernate.Transaction;
    
    import com.zking.hibernatedemo2.entity.TOrder;
    
    import com.zking.hibernatedemo2.utils.GetSession;
    
    public class OrderDao {
    	
    	
    	public int add(TOrder order) {
    		
    		Session session = GetSession.getSession();
    		Transaction transaction = session.beginTransaction();
    		int save =(int) session.save(order);
    		
    		transaction.commit();
    		return save;	
    	}
    	
    	public TOrder select(TOrder o) {
    		Session session = GetSession.getSession();
    		TOrder order = session.load(TOrder.class,o.getOrderId());
    		//强制初始化一个代理
    	   	if(o.getInitOrderitem()== 1) {
    	   		Hibernate.initialize(order.getTOrderItems());
    	   	}
    		GetSession.closeSession();
    		return order;			
    	}
    	
    	
    	
    	
    	
    	public void del() {
    		
    	}
    
    }
    
    
    package hibernatedemo2.test;
    
    import java.util.HashSet;
    import java.util.Set;
    
    import javax.persistence.criteria.Order;
    
    import org.apache.jasper.tagplugins.jstl.core.ForEach;
    import org.junit.Test;
    
    import com.zking.hibernatedemo2.dao.OrderDao;
    import com.zking.hibernatedemo2.entity.TOrder;
    import com.zking.hibernatedemo2.entity.TOrderItem;
    
    public class demo01 {
    	
    	//增加
    	@Test
    	public void test1() {
    		TOrder order=new TOrder();
    		
    		
    		OrderDao dao=new OrderDao();
    		
    		Set<TOrderItem> set=new HashSet<>();
    		for(int i=1;i<=10;i++) {
    			
    			TOrderItem item=new TOrderItem(i,i,order);
    			set.add(item);
    		}
    		order.setOrderNo("DD008");
    		order.setTOrderItems(set);
    		
    		
    		int add = dao.add(order);
    		System.out.println(add);
    	}
    	
    	//查看
    	
    	@Test
    	public void test2() {
    		TOrder order=new TOrder();
    		
    		
    		OrderDao dao=new OrderDao();
    		
    	
    		order.setOrderId(1);
    		order.setInitOrderitem(1);
    		
    		TOrder order2 = dao.select(order);
    		
    		
    		order2.getTOrderItems().forEach((a)->System.out.println(a));
    		System.out.println( order2.getOrderId());
    		System.out.println( order2.getOrderNo());
    	}
    	//删除(只能删除没有联系的值,如果删除又联系的值会报错)
    	@Test
    	public void test3() {
    		TOrder order=new TOrder();
    		OrderDao dao=new OrderDao();
    		order.setOrderId(4);
    		dao.del(order);
    	}
    	
    	
    	
    
    
    }
    
    

10.实例(自关联)

  1. 创建对象关系实例

    package com.zking.hibernatedemo2.entity;
    // Generated 2020-8-2 17:12:03 by Hibernate Tools 4.3.5.Final
    
    import java.util.ArrayList;
    /*import java.util.HashSet;*/
    import java.util.List;
    /*import java.util.Set;*/
    import  java.io.Serializable;
    /**
     * TSysTreeNode generated by hbm2java
     */
    public class TSysTreeNode implements Serializable {
    
    	private Integer treeNodeId;
    	private String treeNodeName;
    	private int treeNodeType;
    	private Long position;
    	private String url;
    	/*private Set<TSysTreeNode> TSysTreeNodes = new HashSet();*/
    	private List<TSysTreeNode> childNodes = new ArrayList<TSysTreeNode>();
    	private TSysTreeNode TSysTreeNode;
    	
    
    
    	private int initChildNodes=0;
    	
    	public TSysTreeNode() {
    	}
    
    	/*public TSysTreeNode(String treeNodeName, int treeNodeType) {
    		this.treeNodeName = treeNodeName;
    		this.treeNodeType = treeNodeType;
    	}*/
    
    
    	public TSysTreeNode(String treeNodeName, Long position) {
    		this.treeNodeName=treeNodeName;
    		this.treeNodeType=2;
    		this.position=position;
    		
    
    	}
    	public int getInitChildNodes() {
    		return initChildNodes;
    	}
    
    	public void setInitChildNodes(int initChildNodes) {
    		this.initChildNodes = initChildNodes;
    	}
    
    	public Integer getTreeNodeId() {
    		return this.treeNodeId;
    	}
    
    	public void setTreeNodeId(Integer treeNodeId) {
    		this.treeNodeId = treeNodeId;
    	}
    
    	public TSysTreeNode getTSysTreeNode() {
    		return this.TSysTreeNode;
    	}
    
    	public void setTSysTreeNode(TSysTreeNode TSysTreeNode) {
    		this.TSysTreeNode = TSysTreeNode;
    	}
    
    	public String getTreeNodeName() {
    		return this.treeNodeName;
    	}
    
    	public void setTreeNodeName(String treeNodeName) {
    		this.treeNodeName = treeNodeName;
    	}
    
    	public int getTreeNodeType() {
    		return this.treeNodeType;
    	}
    
    	public void setTreeNodeType(int treeNodeType) {
    		this.treeNodeType = treeNodeType;
    	}
    
    	public Long getPosition() {
    		return this.position;
    	}
    
    	public void setPosition(Long position) {
    		this.position = position;
    	}
    
    	public String getUrl() {
    		return this.url;
    	}
    
    	public void setUrl(String url) {
    		this.url = url;
    	}
    
    	
    	
    	
    /*	public Set getTSysTreeNodes() {
    		return this.TSysTreeNodes;
    	}
    
    	public void setTSysTreeNodes(Set TSysTreeNodes) {
    		this.TSysTreeNodes = TSysTreeNodes;
    	}*/
    
    	public List<TSysTreeNode> getChildNodes() {
    		return childNodes;
    	}
    
    	public void setChildNodes(List<TSysTreeNode> childNodes) {
    		this.childNodes = childNodes;
    	}
    
    	@Override
    	public String toString() {
    		return "TSysTreeNode [treeNodeId=" + treeNodeId + ", treeNodeName=" + treeNodeName + ", treeNodeType="
    				+ treeNodeType + ", position=" + position + ", url=" + url + "]";
    	}
    
    
    	
    	
    
    }
    
    
  2. 创建数据库关系映射配置文件

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <!-- Generated 2020-8-2 17:12:03 by Hibernate Tools 4.3.5.Final -->
    <hibernate-mapping>
        <class name="com.zking.hibernatedemo2.entity.TSysTreeNode" table="t_sys_tree_node" catalog="westos" optimistic-lock="version">
            <id name="treeNodeId" type="java.lang.Integer">
                <column name="tree_node_id" />
                <generator class="increment" />
            </id>
           
            <property name="treeNodeName" type="string">
                <column name="tree_node_name" length="50" not-null="true" />
            </property>
            <property name="treeNodeType" type="int">
                <column name="tree_node_type" not-null="true" />
            </property>
            <property name="position" type="java.lang.Long">
                <column name="position" />
            </property>
            <property name="url" type="string">
                <column name="url" length="1024" />
            </property>
            
            
             <many-to-one name="TSysTreeNode" class="com.zking.hibernatedemo2.entity.TSysTreeNode">
                <column name="parent_node_id" />
            </many-to-one>
            
           <!--set方式  --> 
            <!-- <set name="TSysTreeNodes" table="t_sys_tree_node" inverse="false"  cascade="save-update">
                <key>
                    <column name="parent_node_id" />
                </key>
                <one-to-many class="com.zking.hibernatedemo2.entity.TSysTreeNode" />
            </set> -->
            
            
            <!-- list 按指定的order-by条件进行排序,注意:条件中是列名而不是属性名-->
         <bag name="childNodes" cascade="save-update" inverse="false" order-by="position asc">
    			<key column="parent_node_id"/>
    			<one-to-many class="com.zking.hibernatedemo2.entity.TSysTreeNode"/>
    	</bag>
        </class>
    </hibernate-mapping>
    
    
  3. 创建测试用到dao

    package com.zking.hibernatedemo2.dao;
    
    import java.io.Serializable;
    
    import org.hibernate.Hibernate;
    import org.hibernate.Session;
    import org.hibernate.Transaction;
    
    import com.zking.hibernatedemo2.entity.TSysTreeNode;
    import com.zking.hibernatedemo2.utils.GetSession;
    
    public class TreeNodeDao {
    	
    	
    	
    	/*	public TSysTreeNode get(TSysTreeNode t) {
    			
    			
    			Session session = GetSession.getSession();
    			
    			
    			
    			return null;
    		}
    		*/
    	
    	public int add(TSysTreeNode t) {
    		
    		
    		Session session = GetSession.getSession();
    		
    		Transaction transaction = session.beginTransaction();
    		
    		int save =(int) session.save(t);
    		
    		transaction.commit();
    		
    		session.close();
    		return save;
    	}
    	
    	
    	
    	public TSysTreeNode select(TSysTreeNode t) {
    		
    		
    		Session session = GetSession.getSession();
    		
    		
    		TSysTreeNode treeNode=session.load(TSysTreeNode.class,t.getTreeNodeId());
    		//强制初始化一个代理
    		if(1==t.getInitChildNodes()) {
    			Hibernate.initialize(treeNode.getChildNodes());
    		}
    
    		GetSession.closeSession();
    		return treeNode;
    	}
    	
    }
    
    
  4. 测试

    package hibernatedemo2.test;
    
    import java.util.ArrayList;
    
    import java.util.List;
    
    
    import org.apache.jasper.tagplugins.jstl.core.ForEach;
    import org.junit.Test;
    
    import com.zking.hibernatedemo2.dao.TreeNodeDao;
    import com.zking.hibernatedemo2.entity.TSysTreeNode;
    
    public class demo02 {
    	private TreeNodeDao dao=new TreeNodeDao();
    	
    	//增加
    	@Test
    	public void add() {
    		TSysTreeNode father=new TSysTreeNode();
    
    		List<TSysTreeNode> list=new ArrayList<>();
    		
    		for(int i=13;i<=16;i++) {
    			TSysTreeNode t=new TSysTreeNode("书籍删除"+i,(long)i);
    			t.setTSysTreeNode(father);
    			list.add(t);
    		}
    		father.setTreeNodeType(1);
    		father.setPosition((long)12);
    		father.setTreeNodeName("书记管理");
    		father.setChildNodes(list);
    		dao.add(father);
    		
    	}
    	
    	//查看
    	@Test
    	public void select() {
    		TSysTreeNode tree=new TSysTreeNode();
    		tree.setTreeNodeId(1);
    		tree.setInitChildNodes(1);
    		TSysTreeNode node = dao.select(tree);
    		
    		node.getChildNodes().forEach((a)->System.out.println(a));
    	}
    
    }
    
    

11.实例(多对多)

  1. 创建数据库的数据
-- 书本类别表
create table t_category
(
   category_id int primary key auto_increment,
   category_name varchar(50) not null
);

-- 书本表
create table t_book
(
   book_id int primary key auto_increment,
   book_name varchar(50) not null,
   price float not null
);


-- 桥接表
-- 定义三个列,其实只要两个列
-- 一个类别对应多本书,一本书对应多个类别
create table t_book_category
(
  bcid int primary key auto_increment,  
  bid int not null,
  cid int not null,
  foreign key(bid) references t_book(book_id),
  foreign key(cid) references t_category(category_id)
);



  1. 创建实体多对多关系

    • Category.java

      public class Category implements Serializable {
      	
      	private Integer categoryId;
      	
      	private String categoryName;
      	
      	//一种类型可以对应多本书
      	private Set<Book> books = new HashSet<>();
      	
      	public Set<Book> getBooks() {
      		return books;
      	}
      
      	public void setBooks(Set<Book> books) {
      		this.books = books;
      	}
      
      	public Integer getCategoryId() {
      		return categoryId;
      	}
      
      	public void setCategoryId(Integer categoryId) {
      		this.categoryId = categoryId;
      	}
      
      	public String getCategoryName() {
      		return categoryName;
      	}
      
      	public void setCategoryName(String categoryName) {
      		this.categoryName = categoryName;
      	}
      
      	@Override
      	public String toString() {
      		return "Category [categoryhljs-string" style="color: #d69d85; line-height: 160%; box-sizing: content-box;">", categoryName=" + categoryName + "]";
      	}
      
      }
      

      Book.java

      public class Book implements Serializable {
      	
      	private Integer bookId;
      	
      	private String bookName;
      	
      	private Float price;
      	
      	//一本书可以对应多种类型
      	private Set<Category> categorys = new HashSet<>();
      
      	public Set<Category> getCategorys() {
      		return categorys;
      	}
      
      	public void setCategorys(Set<Category> categorys) {
      		this.categorys = categorys;
      	}
      
      	public Integer getBookId() {
      		return bookId;
      	}
      
      	public void setBookId(Integer bookId) {
      		this.bookId = bookId;
      	}
      
      	public String getBookName() {
      		return bookName;
      	}
      
      	public void setBookName(String bookName) {
      		this.bookName = bookName;
      	}
      
      	public Float getPrice() {
      		return price;
      	}
      
      	public void setPrice(Float price) {
      		this.price = price;
      	}
      
      	@Override
      	public String toString() {
      		return "Book [bookhljs-string" style="color: #d69d85; line-height: 160%; box-sizing: content-box;">", bookName=" + bookName + ", price=" + price + "]";
      	}
      
      }
      
  2. 配置文件

    <?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>
    
    	<class name="com.zking.hbdemo.entity.Book" table="t_book">
    	
    		<!-- OID对象标识列 主键列 -->
    		<id name="bookId" type="java.lang.Integer" column="book_id">
    			<generator class="native"></generator>
    		</id> 
    		
    		<property name="bookName" type="string" column="book_name" />
    		
    		<property name="price" type="java.lang.Float" column="price" />
    		
    		<!--
    		select * from t_book t1 
    				inner join t_book_category_hb4 t2 on t1.book_id = t2.bid
    		     	inner join t_category_hb4 t3 on t2.cid = t3.category_id
    		 -->
    		<set name="categorys" cascade="save-update" inverse="false" table="t_book_category">
    			<key column="bid"/>
    			<many-to-many class="com.zking.hbdemo.entity.Category" column="cid"/>
    		</set>
    		
    	</class>
    	
    </hibernate-mapping>
    
    
    
    
    <?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>
    
    	<class name="com.zking.hbdemo.entity.Category" table="t_category">
    	
    		<!-- OID对象标识列 主键列 -->
    		<id name="categoryId" type="java.lang.Integer" column="category_id">
    			<generator class="native"/>
    		</id> 
    		
    		<property name="categoryName" type="string" column="category_name"/>
    		
    		<!-- 
    		select * from t_category_hb4 t1 
    		          inner join t_book_category_hb4 t2 on t1.category_id = t2.cid
    		          inner join t_book_hb4 t3 on t2.bid = t3.book_id
    		 -->
    		<set name="books" cascade="save-update" inverse="true" table="t_book_category">
    			<key column="cid"/>
    			<many-to-many  class="com.zking.hbdemo.entity.Book" column="bid"/>
    		</set>
    		
    	</class>
    	
    </hibernate-mapping>
    
    
    再把这两个配置到hibernate核心配置文件中去
    
  3. 编写dao

    package com.zking.hibernatedemo2.dao;
    
    import java.io.Serializable;
    
    import org.hibernate.Hibernate;
    import org.hibernate.Session;
    import org.hibernate.Transaction;
    
    import com.zking.hibernatedemo2.entity.Book;
    import com.zking.hibernatedemo2.entity.Category;
    import com.zking.hibernatedemo2.utils.GetSession;
    
    public class BookDao {
    	
    	public Book  get(Book b) {
    		Session session = GetSession.getSession();
    		
    		Book get = session.load(Book.class,b.getBookId());
    		
    		if(b.getInin()==1) {
    			
    			Hibernate.initialize(get.getCategorys());
    			Hibernate.initialize(get.getBookId());
    		}
    		GetSession.closeSession();
    		return get;
    	}
    	
    	
    	public Category get(Category c) {
    		Session session = GetSession.getSession();
    		Transaction transaction = session.beginTransaction();
    		Category get = session.get(Category.class,c.getCategoryId());
    		
    		if(c.getInin()==1) {	
    			Hibernate.initialize(get.getBooks());
    			Hibernate.initialize(get.getCategoryId());
    		}
    		transaction.commit();
    		GetSession.closeSession();
    		return get;
    	}
    	
    	public int  add(Book book) {
    		
    		Session session = GetSession.getSession();
    		
    		
    		Transaction transaction = session.beginTransaction();
    		int save =(int) session.save(book);
    		
    		transaction.commit();
    		
    		GetSession.closeSession();
    		
    		return save;
    	}
    	
    	
    	public int  add(Category category) {
    		
    		Session session = GetSession.getSession();
    		
    		
    		Transaction transaction = session.beginTransaction();
    		int save =(int) session.save(category);
    		
    		transaction.commit();
    		
    		GetSession.closeSession();
    		
    		return save;
    	}
    	
    	
    /*	public void delBook(Book book) {
    		
    		
    		Session session =GetSession.getSession();
    		Transaction t = session.beginTransaction();
    		
    		Book b = session.get(Book.class, book.getBookId());
    		if(null!=b) {
    			
    			
    			session.delete(b);
    			
    		}
    		
    		t.commit();
    		GetSession.closeSession();	
    		
    		
    	}
    	
    	
    
    	*/
    	public void delCategory(Category category) {
    		
    		
    		Session session =GetSession.getSession();
    		Transaction t = session.beginTransaction();
    		
    		Category c = session.get(Category.class, category.getCategoryId());
    		if(null!=c) {
    			for(Book book: c.getBooks()) {
    				//错误,需要解除的是关联关系,书为主控方
    				//通过book获取书本对应的categorys,再删除对应的category
    				//c.getBooks().remove(book);
    				book.getCategorys().remove(c);
    			}
    			session.delete(c);
    		}
    		t.commit();
    		GetSession.closeSession();	
    		
    		
    	}
    	
    	
    	/*//必須是主控方category才能级联操作。
    		public void delCategory(Category category) {
    		
    		Session session =GetSession.getSession();
    		Transaction t = session.beginTransaction();
    		
    		Category c = session.get(Category.class, category.getCategoryId());
    		if(c != null) {
    			//删除被控方需要先解除关联关系
    			for(Book book: c.getBooks()) {
    				//错误,需要解除的是关联关系,书为主控方
    				//通过book获取书本对应的categorys,再删除对应的category
    				//c.getBooks().remove(book);
    				book.getCategorys().remove(c);
    			}
    			session.delete(c);
    		}
    		
    		t.commit();
    		GetSession.closeSession();
    	}*/
    
    	
    	
    
    }
    
    
  4. 测试

    package hibernatedemo2.test;
    
    import java.util.Objects;
    
    import org.junit.Test;
    
    import com.zking.hibernatedemo2.dao.BookDao;
    import com.zking.hibernatedemo2.entity.Book;
    import com.zking.hibernatedemo2.entity.Category;
    
    public class demo3 {
    	
    	
    	//add
    /*	@Test
    	public void add() {
    		
    	BookDao bookDao=new BookDao();	
    		
    	Book book=new Book();
    	book.setBookName("圣墟");
    	book.setPrice(100f);
    	
    	Category category=new Category();
    	category.setCategoryName("武侠");
    	category.getBooks().add(book);
    	
    	Category category1=new Category();
    	category1.setCategoryName("古典");
    	category1.getBooks().add(book);
    	
    	
    	
    	book.getCategorys().add(category);
    	book.getCategorys().add(category1);
    	int add = bookDao.add(book);
    	
    	
    	
    	
    		System.out.println(add);
    		
    		
    	}*/
    	
    	/*	
    @Test
    	public void add() {
    		
    	BookDao bookDao=new BookDao();	
    		
    	Book book=new Book();
    	book.setBookName("西游记");
    	book.setPrice(100f);
    	
    	
    	Book book1=new Book();
    	book1.setBookName("红楼梦");
    	book1.setPrice(100f);
    	
    	
    	
    	Book book2=new Book();
    	book2.setBookName("三国演义");
    	book2.setPrice(100f);
    	
    	
    	Book book3=new Book();
    	book3.setBookName("水浒传");
    	book3.setPrice(100f);
    
    	Category category=new Category();
    	category.setCategoryName("四大名著");
    	category.getBooks().add(book);
    	category.getBooks().add(book1);
    	category.getBooks().add(book2);
    	category.getBooks().add(book3);
    	
    	
    	book.getCategorys().add(category);
    	book1.getCategorys().add(category);
    	book2.getCategorys().add(category);
    	book3.getCategorys().add(category);
    	int add = bookDao.add(category);
    	System.out.println(add);
    		
    		
    	}*/
    	
    	//删除
    /*	@Test
    	public void del() {
    		
    		
    		Book book=new Book();
    		book.setBookId(18);
    		
    		BookDao dao=new BookDao();
    		dao.delBook(book);
    	}
    */
    	//删除
    	/*	@Test
    		public void del() {
    			
    			
    			Category c=new Category();
    			c.setCategoryId(5);
    			
    			BookDao dao=new BookDao();
    			dao.delCategory(c);
    		}*/
    	
    	//查看
    	
    	
    	
    	@Test
    	public void select() {
    		
    		
    		Category c=new Category();
    		c.setCategoryId(17);
    		c.setInin(1);
    		
    		BookDao dao=new BookDao();
    		Category category = dao.get(c);
    		System.out.println(category);
    		if(Objects.isNull(category.getBooks())) {
    			System.out.println(123123);
    		}
    		category.getBooks().forEach((a)->System.out.println(a));
    	}
    	
    	
    	
    /*	@Test
    	public void select() {
    		
    		
    		Book  c=new Book();
    		c.setBookId(23);
    		c.setInin(1);
    		
    		BookDao dao=new BookDao();
    		Book category = dao.get(c);
    		System.out.println(category);
    	
    		category.getCategorys().forEach((a)->System.out.println(a));
    	}*/
    	
    }
    
    

12.hql

什么是hql

​ HQL是Hibernate Query Language(Hibernate 查询语言)的缩写,提供更加丰富灵活、更为强大的查询能力;HQL更接近SQL语句查询语法。Hibernate 查询语言(HQL)是一种面向对象的查询语言,类似于 SQL,但不是去对表和列进行操作,而是面向对象和它们的属性。 HQL 查询被 Hibernate 翻译为传统的 SQL 查询从而对数据库进行操作。

HQLSQL
类名/属性表名/列名
区分大小写,关键字不区分大小写不区分大小写
?,从下标0开始计算位置 ,(高版本的不再支持?)?,从顺序1开始计算位置
:命名参数不支持:命名参数
面向对象的查询语言面向结构查询语言

注:
注1:QuerySyntaxException:XXX is not mapped
原因:
1)在hql中类名写错,注意区分大小写
2)对应的类没有编写hibernate映射文件
3)编写的映射文件但没有将映射文件加入到核心配置文件

实例

package my;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.hibernate.Session;
import org.hibernate.query.Query;
import org.junit.Test;

import com.zking.hibernate.entity.User;
import com.zking.hibernate.utils.GetSession;

public class HqlDemp {
	
	//查询全部

	@Test
	public void selectAll() {
		// 可以简写为from  User u
		String hql="from  User u";
		//String hql="select u from User u";
		Session session = GetSession.getSession();
		Query query = session.createQuery(hql);
		
		List<User> list = query.list();
		
		GetSession.closeSession();
		list.forEach((a)->System.out.println(a));

	}
	
	//带where语句的查询
	@Test
	public void selectAllWhere() {
		
		String hql="from  User u where u.userName like :name";
	
		Session session = GetSession.getSession();
		Query query = session.createQuery(hql);
		
		
		query.setParameter("name", "z%");
		
		List<User> list = query.list();
		
		GetSession.closeSession();
		list.forEach((a)->System.out.println(a));

	}
	
	
	//查询单条(如果数据库有多条的话会报错)
	@Test
	public void selectone() {
		String hql="from User u where u.id=:id";
		Session session = GetSession.getSession();
		
		
		Query query = session.createQuery(hql);
		
		query.setParameter("id", 1);
		
		User user = (User)query.uniqueResult();
		System.out.println(user);
		GetSession.closeSession();
	}


	
	
	
	//返回Object[]
	@Test
	public void selectObjects() {
		
		String hql="select u.userName,u.userPwd  from  User u where u.userName = :name";
	
		Session session = GetSession.getSession();
		Query query = session.createQuery(hql);
		
		
		query.setParameter("name", "zs");
		
		 List<Object[]> list = query.list();
		
		GetSession.closeSession();

		list.forEach((a)->System.out.println(Arrays.toString(a)));

	}

	
	
	
	//返回Map
	@Test
	public void selectMap() {
		
		String hql="select new Map(u.userName as 名字,u.userPwd as 密码)  from  User u where u.userName = :name";
	
		Session session = GetSession.getSession();
		Query query = session.createQuery(hql);
		
		
		query.setParameter("name", "zs");
		
		 List<Map<String, Object>> list = query.list();
		
		GetSession.closeSession();

		list.forEach((a)->System.out.println(a.get("名字")+"\t"+a.get("密码")));

	}
	

}



@Test
	public void  ls() {
		
		String hql="SELECT new Map( t1.orderNo as 订单编号,t2.quantity as 订单排序)  FROM TOrder t1 INNER JOIN  TOrderItem t2  on t1.orderId  =t2.TOrder.orderId WHERE  t1.orderId=1";
				
		Session session = GetSession.getSession();
		
		Query query = session.createQuery(hql);
		List<Map<String, Object>> list = query.list();
		
		list.forEach((a)->System.out.println(a));
		
		
		GetSession.closeSession();
	}
	
	

//*一般的话这个是使用配置文件配置的属性。如果没有配置oid的话会一直报文件不能解析
	@Test
	public void  ls() {
		
		String hql="SELECT new Map( t1.orderNo as 订单编号,t2.quantity as 订单排序)  FROM TOrder t1 INNER JOIN  TOrderItem t2  on t1.orderId  =t2.oid WHERE  t1.orderId=1";
				
		Session session = GetSession.getSession();
		
		Query query = session.createQuery(hql);
		List<Map<String, Object>> list = query.list();
		
		list.forEach((a)->System.out.println(a));
		
		
		GetSession.closeSession();
	}

	@Test
	public void  ls() {
		
		String hql="SELECT new Map( t1.orderNo as 订单编号,t2.quantity as 订单排序)  FROM TOrder t1 INNER JOIN  TOrderItem t2  on t1  =t2.TOrder WHERE  t1.orderId=1";
				
		Session session = GetSession.getSession();
		
		Query query = session.createQuery(hql);
		List<Map<String, Object>> list = query.list();
		
		list.forEach((a)->System.out.println(a));
		
		
		GetSession.closeSession();
	}
	

//使用聚合函数(使用多是一样的,这边就拿sum举例子)
@Test	
public void  ls() {
		
		String hql="SELECT new Map( t1.orderNo as 订单编号,sum(t2.quantity) as 订单排序总数)  FROM TOrder t1 INNER JOIN  TOrderItem t2  on t1  =t2.TOrder WHERE  t1.orderId=1";
				
		Session session = GetSession.getSession();
		
		Query query = session.createQuery(hql);
		List<Map<String, Object>> list = query.list();
		
		list.forEach((a)->System.out.println(a));
		
		
		GetSession.closeSession();
	}

13.缓存

  1. 为什么要缓存

    • 用缓存,主要有两个用途:高性能、高并发。

      ​ 高性能:非实时变化的数据-查询mysql耗时需要300ms,存到缓存中,每次查询仅仅1ms,性能瞬间提升百倍。

      ​ 高并发:mysql 单机支撑到2K QPS就容易报警了,如果系统中高峰时期1s请求1万,仅单机mysql是支撑不了的,但是使用缓 存的话,单机支撑的并发量轻松1s几万~十几万。原因是缓存位于内存,内存对高并发的良好支持。

    • 什么数据需要使用缓存

      • 很少被修改或根本不改的数据
      • 使用频率高的数据

      业务场景比如:耗时较高的统计分析sql、电话账单查询sql等

    • 最经典的缓存+数据库读写的模式,就是 Cache Aside Pattern。

      • 读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存,同时返回响应。
      • 更新的时候,先更新数据库,然后再删除缓存。

      如何保证数据库与缓存一致

      1. 非高并发

        先修改数据库,再删除缓存。如果缓存删除失败,导致缓存中是旧数据。而数据库上面的是新数据

        解决办法:

        先删除缓存,在修改数据库。如果删除缓存失败,那么整个都失败。如果是修改时报错。那么下一次读取数据的时候,虽然都是旧数据,但是保持了数据的一致性

      2. 高并发

        先删除了缓存,然后要去修改数据库,此时还没修改。(定义为步骤A)

        一个请求过来,去读缓存,发现缓存空了,去查询数据库(定义为步骤B1)。查到了修改前的旧数据,放到了缓存中。(定义为步骤B2)

        随后数据变更的程序完成了数据库的修改。此时数据库和缓存数据不一致了。

        解决方法:

        定义一个FIFO的阻塞队列,例如:LinkedBlockingQueue,将步骤A和步骤B放入同一个队列中。步骤A必然在步骤B的前面。

        当场景发生了上述步骤B1时,只有2个情况:缓存已删除,数据库已修改或者数据库还未修改。不考虑已修改的正常情况,则步骤A必然已发生。
        则可以在,步骤A和步骤B1发生时均按照数据唯一标识(ID)入同一个队列。步骤A先于步骤B1入队,按照FIFO的方式,步骤A会先完成,则问题
        理论上得以解决。

        注意事项:

        • 高并发场景下肯定会有同一个数据多个步骤B的出现,可以过滤去重。即:队列中已存在则不用再入队了。

        • 由于步骤B已变成异步读请求,基于我们的高并发场景,需要考虑读超时的问题。如果请求还在等待时间范围内,不断轮询发现可以取到值了,那么就直接返回;如果请求等待的时间超过一定时长,那么这一次直接从数据库中读取当前的旧值。

        • 如果大量的数据更新频繁,导致队列中堆积大量的更新操作,然后大量的读请求超时,最后导致大量的请求直接走数据库。则需要根据具体业务模拟测试峰值,部署多个应用分摊更新操

14.eacache

  1. eacache是什么:

    EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider。

    注1:本章介绍的是2.X版本,3.x的版本和2.x的版本API差异比较大

  2. 导入依赖

          <dependency>
          	<groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>2.10.0</version>
          </dependency>
    
  3. 实例

    package com.zking.hibernatedemo2.utils;
    
    import java.io.InputStream;
    
    import net.sf.ehcache.Cache;
    import net.sf.ehcache.CacheManager;
    import net.sf.ehcache.Element;
    
    public final class EhcacheUtil {
    
        private static CacheManager cacheManager;
    
        static {
            try {
                InputStream is = EhcacheUtil.class.getResourceAsStream("/ehcache.xml");
                cacheManager = CacheManager.create(is);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    
        private EhcacheUtil() {
        }
    
        public static void put(String cacheName, Object key, Object value) {
            Cache cache = cacheManager.getCache(cacheName);
            if (null == cache) {
                //以默认配置添加一个名叫cacheName的Cache
                cacheManager.addCache(cacheName);
                cache = cacheManager.getCache(cacheName);
            }
            cache.put(new Element(key, value));
        }
    
    
        public static Object get(String cacheName, Object key) {
            Cache cache = cacheManager.getCache(cacheName);
            if (null == cache) {
            	return null;
            }
            Element element = cache.get(key);
            return null == element ? null : element.getValue();
        }
    
        public static void remove(String cacheName, Object key) {
            Cache cache = cacheManager.getCache(cacheName);
            if (null == cache) {
            	System.out.println("移除了");
            	return;
            }
            cache.remove(key);
        }
    

    使用

    public class EhcacheUtilTest {
    
    	@Test
    	public void test() {
    		User user =  new User();
    		user.setId(1);
    		user.setUserName("admin");
    		user.setRealName("管理员");
    		
    		System.out.println("放入缓存");
    		EhcacheUtil.put("stuCache", "user001", user);
    		
    		User u = (User)EhcacheUtil.get("stuCache", "user001");
    		System.out.println("从缓存中获取"+u);
    	}
    
    }
    

14.hibernate集成ehcache

​ 1. 在原有的的环境上导入jar包

<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-ehcache</artifactId>
			<version>5.4.10.Final</version>
		</dependency>
  1. 配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
             updateCheck="false">
        <!--磁盘存储:将缓存中暂时不使用的对象,转移到硬盘,类似于Windows系统的虚拟内存-->
        <!--path:指定在硬盘上存储对象的路径-->
        <!--java.io.tmpdir 是默认的临时文件路径。 可以通过如下方式打印出具体的文件路径 System.out.println(System.getProperty("java.io.tmpdir"));-->
        <diskStore path="java.io.tmpdir"/>
    
    
        <!--defaultCache:默认的管理策略-->
        <!--eternal:设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断-->
        <!--maxElementsInMemory:在内存中缓存的element的最大数目-->
        <!--overflowToDisk:如果内存中数据超过内存限制,是否要缓存到磁盘上-->
        <!--diskPersistent:是否在磁盘上持久化。指重启jvm后,数据是否有效。默认为false-->
        <!--timeToIdleSeconds:对象空闲时间(单位:秒),指对象在多长时间没有被访问就会失效。只对eternal为false的有效。默认值0,表示一直可以访问-->
        <!--timeToLiveSeconds:对象存活时间(单位:秒),指对象从创建到失效所需要的时间。只对eternal为false的有效。默认值0,表示一直可以访问-->
        <!--memoryStoreEvictionPolicy:缓存的3 种清空策略-->
        <!--FIFO:first in first out (先进先出)-->
        <!--LFU:Less Frequently Used (最少使用).意思是一直以来最少被使用的。缓存的元素有一个hit 属性,hit 值最小的将会被清出缓存-->
        <!--LRU:Least Recently Used(最近最少使用). (ehcache 默认值).缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存-->
        <defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="false" diskPersistent="false"
                      timeToIdleSeconds="0" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU"/>
    
    
               
               
        <!--name: Cache的名称,必须是唯一的(ehcache会把这个cache放到HashMap里)-->
        <cache name="com.zking.hibernatedemo2.entity.TSysTreeNode" eternal="false" maxElementsInMemory="100"
               overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="0"
               timeToLiveSeconds="300" memoryStoreEvictionPolicy="LRU"/>
    
    
    
    
    </ehcache>
    
  2. hibernate的配置核心配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-configuration PUBLIC
    	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    	"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
    <hibernate-configuration>
    	<session-factory>
    		<property name="connection.username">root</property><!-- 连接的name -->
    		<property name="connection.password">123456</property><!-- 连接的密码 -->
    		<property name="connection.url">jdbc:mysql://localhost:3306/westos?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false</property><!--url -->
    		<property name="connection.driver_class">com.mysql.jdbc.Driver</property><!--驱动程序  -->
    		<!-- mysql方言 -->
    		<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
    		
    		<property name="show_sql">true</property> <!--显示sql语句  -->
    		<property name="format_sql">true</property><!--  使显示的sql语句格式化,更方便查看-->
    		
    
    	
    	
    	  <!-- 开启二级缓存 -->
          <property name="hibernate.cache.use_second_level_cache">true</property>
          <!-- 开启查询缓存 -->
          <property name="hibernate.cache.use_query_cache">true</property>
          <!-- EhCache驱动 -->
        	<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property> 
          
          
          
    		
    		<!-- 映射文件 -->
    	
    		
    		<mapping resource="mapping/Torder.hbm.xml"/>
    		<mapping resource="mapping/Torderitem.hbm.xml"/>
    		<mapping resource="mapping/TSysTreeNode.hbm.xml"/>
    		
    		<!-- 多对多 -->
    		<mapping resource="mapping/Category.hbm.xml"/>
    		<mapping resource="mapping/Book.hbm.xml"/>
    	</session-factory>
    </hibernate-configuration>
    
  3. 实体配置文件的配置(配置关联的需要在关联的里面设置)

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    <!-- Generated 2020-8-2 17:12:03 by Hibernate Tools 4.3.5.Final -->
    <hibernate-mapping>
        <class name="com.zking.hibernatedemo2.entity.TSysTreeNode" table="t_sys_tree_node" catalog="westos" optimistic-lock="version">
            
            <cache usage="read-only" />
            
            <!--
     
    
    
    -->
            
            <id name="treeNodeId" type="java.lang.Integer">
                <column name="tree_node_id" />
                <generator class="increment" />
            </id>
           
            <property name="treeNodeName" type="string">
                <column name="tree_node_name" length="50" not-null="true" />
            </property>
            <property name="treeNodeType" type="int">
                <column name="tree_node_type" not-null="true" />
            </property>
            <property name="position" type="java.lang.Long">
                <column name="position" />
            </property>
            <property name="url" type="string">
                <column name="url" length="1024" />
            </property>
            
            
             <many-to-one name="TSysTreeNode"  class="com.zking.hibernatedemo2.entity.TSysTreeNode"  >
                <column name="parent_node_id" />
            </many-to-one>
            
           <!--set方式  --> 
            <!-- <set name="TSysTreeNodes" table="t_sys_tree_node" inverse="false"  cascade="save-update">
                <key>
                    <column name="parent_node_id" />
                </key>
                <one-to-many class="com.zking.hibernatedemo2.entity.TSysTreeNode" />
            </set> -->
            
            
            <!-- list 按指定的order-by条件进行排序,注意:条件中是列名而不是属性名-->
         <bag name="childNodes" inverse="false" cascade="save-update"  order-by="position asc">
           <cache usage="nonstrict-read-write" region="com.zking.hibernatedemo2.entity.TSysTreeNode.childNodes"/>
    			<key column="parent_node_id"/>
    			<one-to-many class="com.zking.hibernatedemo2.entity.TSysTreeNode"/>
    	</bag>
        </class>
    </hibernate-mapping>
    
    

5.测试

	@Test
	public void s() {
		Session session = GetSession.getSession();
		String hql="SELECT t  FROM TSysTreeNode t";
		
		
		Query query = session.createQuery(hql);
		
		query.setCacheable(true);
		List list = query.list();
		
		list.forEach((a)->System.out.println(a));
		GetSession.closeSession();
		
		
		System.out.println("------------------------------------------------------");
		
		Session session1 = GetSession.getSession();
		String hql1="SELECT t  FROM TSysTreeNode t";
		
		
		Query query1 = session1.createQuery(hql1);
		query1.setCacheable(true);
		
		List list1 = query1.list();
		
		list1.forEach((a)->System.out.println(a));
		GetSession.closeSession();
		
	}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值