hibernate

hibernate:是关系对象映射框架,对jdbc进行了轻量级的封装。简单说就是将表数据映射到POJO上。流程如下(借图说话):

既然是映射,当然需要配置数据库表实体类的映射关系,配置文件中当指定表中字段与实体属性如何对应。

配置文件方式

映射关系配置文件如下:(路径可以随便放,只需在hibernate主配置文件中指明映射文件的路径即可)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
   
    <!-- package 指明以下配置映射关系的实体类的路径,在此包下的实体都可以一起配置映射 -->
<hibernate-mapping auto-import="true" package="com.muchen.entity">
	<!-- 
        必须配置id,hibernate要区分两条数据的不同
        name:即package下实体类的名称
        table:映射到数据库里面的那个表的名称
        catalog:数据库的名称 -->
	<class name="Xzqh" table="XZQH" catalog="MASZWFW">
		<id name="qhbm" column="QHBM">
                           <!-- increment: long、int、short的自增长,高并发时可能出现增长的id一样的情况
				  identity:SQLServer 、MySQL的自增长
				  sequence:Oracle、DB2的自增长
				  native:根据底层数据库对生成标识符的支持自动选择使用identity、sequence、hilo标识符生成器
				  uuid:由hibernate生成的字符型主键
				  assigned:由程序员生成指定
				  -->
			<generator class="native"></generator>
		</id>
		<property name="pqhbm" column="pqhbm"></property>
		<property name="qhmc" column="qhmc"></property>
		<property name="qhjb" column="qhjb"></property>
	</class>
		
	<!-- 实体属性可以多于、少于、等于表字段数,只需配置所需映射的属性和字段即可 -->
	<class name="Vote" table="T_VOTE" catalog="MASZWFW">
		<id name="uuid" column="uuid">
			<generator class="uuid"></generator>
		</id>
		<property name="businesseId" column="BUSINESSID"></property>
		<property name="date" column="VOTE_DATE"></property>
		<property name="order" column="VOTE_ORDER"></property>
		<property name="type" column="VOTE_TYPE"></property>
		<property name="userAccount" column="USER_ACCOUNT"></property>
	</class>
</hibernate-mapping>

主配置文件:

<?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 中的元素 -->
	<session-factory>
		<property name="connection.driver_class">oracle.jdbc.OracleDriver</property>
		<property name="connection.url">jdbc:oracle:thin:@100.235.111.35:1521:ceshi</property>
		<property name="connection.username">masa</property>
		<property name="connection.password">masa</property>
		<property name="connection.autocommit">false</property>
		<property name="connection.pool_size">10</property>
		<property name="format_sql">true</property>
		<property name="show_sql">true</property>
		<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>
            <!-- 使用getCurrentSession()必须要有以下配置 值为thread或jta-->	
                <property name="current_session_context_class">thread</property>
		<!-- 读取映射文件,在此不支持模糊匹配 -->
		<mapping resource="com/muchen/util/entity.hibernate-first.xml"/>
	</session-factory>
</hibernate-configuration>

获得主配置对象:

Configuration config = new Configuration().configure();// 默认配置名:hibernate.cfg.xml
Configuration config1 = new Configuration().configure("mu.hibernate.cfg.xml");// 指定配置名称

此方法底层:

// 没有指定主配置文件名时,默认为hibernate.cfg.xml
public Configuration configure()
    throws HibernateException
  {
    configure("/hibernate.cfg.xml");
    return this;
  }
  // 指定主配置文件名时
  public Configuration configure(String resource)
    throws HibernateException
  {
    log.info("configuring from resource: " + resource);
    InputStream stream = getConfigurationInputStream(resource);
    return doConfigure(stream, resource);
  }
// 加载主配置文件里的内容
protected Configuration doConfigure(org.dom4j.Document doc)
    throws HibernateException
  {
    // 读取 session-factory 标签
    Element sfNode = doc.getRootElement().element("session-factory");
    // 获取标签下的属性
    String name = sfNode.attributeValue("name");
    if (name != null) {
      this.properties.setProperty("hibernate.session_factory_name", name);
    }
    addProperties(sfNode);
    // 产生SessionFactory 
    parseSessionFactory(sfNode, name);
    
    Element secNode = doc.getRootElement().element("security");
    if (secNode != null) {
      parseSecurity(secNode);
    }
    log.info("Configured SessionFactory: " + name);
    log.debug("properties: " + this.properties);
    
    return this;
  }

获取Session对象:

Configuration config1 = new Configuration().configure("mu.hibernate.cfg.xml");// 指定配置名称
		SessionFactory sessionFactory = config1.buildSessionFactory();
		
		//使用openSession方式
		Session session = sessionFactory.openSession();		
		session.beginTransaction();
		
		Query query = session.createQuery("from Xzqh where qhjb=?");
		List<Xzqh> list = query.setString(0, "3").list();
		
		session.getTransaction().commit();
		session.close();
		
		//使用getCurrrentSession方式
		Session currentSession = sessionFactory.getCurrentSession();
		// getCurrrentSession 必须要在事务中 
		currentSession.beginTransaction();
		//...
		// 
		currentSession.getTransaction().commit();

这里获取的Session不同于HttpSession,前者是对象持久化的管理器,后者用于记录前端用户的状态。

openSession得到的session每次都是新的session,需手动关闭,而getCurrentSession获得的session是绑定到当前线程上的,只要此session或者该线程未关闭,获得的都是同一个session,当食物commit或rollback会自动关闭此session,不需要手动显式关闭。

注解方式

用注解方式代替hibernate-mapping配置:

@Entity // 声明实体
@Table(name="T_VOTE",catalog="MASZWFW")// 实体对应的表名和数据库名
public class Vote {
	@Id
	// 通用主键生成器
	@GenericGenerator(name="myuuid",strategy="uuid")
	// 主键生成值
	@GeneratedValue(generator="myuuid")
	@Column(name="UUID")
	private String uuid;
	@Column(name="BUSINESSID")
	private String businesseId;
	@Column(name="USER_ACCOUNT")
	private String userAccount;
	@Column(name="VOTE_TYPE")
	private String type;
	@Column(name="VOTE_DATE")
	private String date;
	@Column(name="VOTE_ORDER")
	private Integer order;
	@Transient // 此属性不映射到表中
	private String something;

	public String getUuid() {
		return uuid;
	}
	public void setUuid(String uuid) {
		this.uuid = uuid;
	}	
	public String getBusinesseId() {
		return businesseId;
	}
	public void setBusinesseId(String businesseId) {
		this.businesseId = businesseId;
	}	
	public String getUserAccount() {
		return userAccount;
	}
	public void setUserAccount(String userAccount) {
		this.userAccount = userAccount;
	}	
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}	
	public String getDate() {
		return date;
	}
	public void setDate(String date) {
		this.date = date;
	}
	public Integer getOrder() {
		return order;
	}
	public void setOrder(Integer order) {
		this.order = order;
	}	
	public String getSomething() {
		return something;
	}
	public void setSomething(String something) {
		this.something = something;
	}
}

注意:属性映射注解要么全部放在属性上,要么全部放在get()方法上,否则会报错。基于面向对象的思想,最好还是放在方法上。

使用注解的方式取代配置映射文件,加上了映射注解的pojo也就相当于此pojo的映射配置文件,只需将此pojo加入hibernate主配置文件中即可:

<hibernate-configuration>
	<!-- 读取此配置文件时,会读取 session-factory 中的元素 -->
	<session-factory>
		<property name="connection.driver_class">oracle.jdbc.OracleDriver</property>
		<property name="connection.url">jdbc:oracle:thin:@10.235.11.35:1521:ceshiku</property>
		<property name="connection.username">maszwfw</property>
		<property name="connection.password">maszwfw</property>
		<property name="connection.autocommit">false</property>
		<property name="connection.pool_size">10</property>
		<property name="format_sql">true</property>
		<property name="show_sql">true</property>
		<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>	
		<!-- 使用getCurrentSession()必须要有以下配置 值为thread或jta-->	
		<property name="current_session_context_class">thread</property>
		<!-- 读取映射文件,在此不支持模糊匹配 -->
		<!-- <mapping resource="com/muchen/util/entity.hibernate-first.xml"/> -->
		<mapping class="com.muchen.entity.Vote"/>
	</session-factory>
</hibernate-configuration>

映射是配置文件时:mapping 指定resource=配置文件路径;

映射是基于注解的pojo时:mapping指定class=该pojo完整类名。

读取配置文件:

Configuration config = new Configuration().configure("mu.hibernate.cfg.xml"); 
Configuration config = new AnnotationConfiguration().configure("mu.hibernate.cfg.xml");

使用注解时,hibernate3.0以前需使用AnnotationConfiguration()方式,才能解析hibernate注解,在3.0以后使用Configuration()就可以了,同样实现了解析注解的功能。

常见数据库操作

HqlQuery 针对实体操作

// 增删改
session.save(Object)/update(Object)/delete(Object)
// 查询
Query query = session.createQuery("from Vote where userAccount=?");
query.setString(0,"12364").list();

SqlSQLQuery

SQLQuery是Query的子接口     public interface SQLQuery   extends Query,所以Query有的方法SQLQuery都有,执行的是普通的sql语句

// 增删改
SQLQuery sql = session.createSQLQuery("delete from T_VOTE where USER_ACCOUNT=?");
sql.setString(0, "mn2527651").executeUpdate();

查询

SQLQuery sql = session.createSQLQuery
("select uuid qhbm,BUSINESSID pqhbm,VOTE_DATE hmc,VOTE_TYPE qhjb,VOTE_ORDER from T_VOTE where USER_ACCOUNT=?");

sql.setString(0, "songzhili1");
List<Object[]> sd = sql.list();// 返回的集合中的元素为Object[]数组

/* 指定查询的字段中取用哪些字段并指定这些字段的类型:addScalar */ 未指定字段将不返回在list中
sql.addScalar("qhbm", StandardBasicTypes.STRING).addScalar("pqhbm", StandardBasicTypes.STRING).
addScalar("qhmc", StandardBasicTypes.STRING).addScalar("qhjb", StandardBasicTypes.STRING);

/*  将查询的记录绑定到实体:addEntity  */ 返回的记录的字段要能与实体属性对应上,
返回的记录字段数不能比要对应的实体属性少,可以相等,也可以多于 */
List<Xzqh> aa = sql.addEntity(Xzqh.class).list(); // 必须使用addEntity 才能强转成功

除了Query和SQLQuery使用外,结合Spring框架在Service中 extends HibernateDaoSupport 可以获得 getHibernateTemplate(),类似Spring框架的 SimpleJdbcTemplate模板,不同的是前者通过extends获得,后者通过DataSource注入获得。

分页:

sqlQuery.setFirstResult(int);设置起始行数

sqlQuery.setMaxResults(int);设置要取的行数(pageSize)

Criteria:以面向对象的方式查询

            Criteria c = session.createCriteria(Vote.class);// 创建一个Criteria对象
            c.add(Restrictions.eq("userAccount", "songzhili1"));// 相当于 where userAccount='songzhili1'
            List<Vote> aa = c.list();

与Query相比,适合查询指定对象,限制条件多的,简单的,不需要怎么写sql的,Query功能更强大。

缓存

缓存介于应用程序与物理数据库之间,介质一般为内存或硬盘(数据量大时),能有效降低应用程序对数据库的访问频率,提高运行性能。

hibernate缓存分一级和二级缓存,一级缓存是session级别的缓存,是事务级别的缓存,二级缓存是sessionFactory级别的缓存,是进程级别的缓存。

一级缓存

在session级别,默认开启,无法卸载,在session关闭或事务关闭后缓存消失。

只有使用session的load() / get() 和query.iterator()等方法时才会将对象载入缓存,使用query其他方法并没有将结果对象加入缓存,由于session开闭比较频繁,所以在session级的缓存命中率很低。

VoteInfo v1= (VoteInfo) session.get(VoteInfo.class, 21);

VoteInfo v2= (VoteInfo) session.load(VoteInfo.class, 21);

上述代码执行过程只会发送一次sql,第二次从缓存中取:第一次查询在缓存中保存了此对象及该对象的持久化OID,第二次查询先从一级缓存中查询。


Iterator<VoteInfo> list2 =  session.createQuery("from VoteInfo WHERE id=?").setInteger(0, 21).iterate();
while(list2.hasNext()){
    System.out.println(list2.next());
}

N+1问题:使用query.itrator()会先查询返回符合查询条件的OID,当需要使用对象时如果缓存中有此持久化对象则直接从缓存取,没有才会去数据库查询对象。


二级缓存

由于一级缓存频繁开闭,导致一级缓存使用生命周期很短,真正使用命中率很低,所以出现了二级缓存,也称sessionFactory缓存,属于进程级共享缓存,而hibernate本身并没有自己去实现二级缓存,而是通过第三方的方式实现的二级缓存。(二级缓存默认关闭)

开启二级缓存:既然是sessionFactory缓存,那在配置文件生成SessionFactory时就已经配置好SessionFactory的缓存机制,在hibernate.cfg.xml中添加缓存配置

1. 开启二级缓存

2. 指明二级缓存供应方

<hibernate-configuration>
	<!-- 读取此配置文件时,会读取 session-factory 中的元素 -->
	<session-factory>
		<property name="connection.driver_class">oracle.jdbc.OracleDriver</property>
		<property name="connection.url">jdbc:oracle:thin:@localhost:1521:xzsp</property>
		<property name="connection.username">xzsp</property>
		<property name="connection.password">xzsp</property>
		<property name="connection.autocommit">false</property>
		<property name="connection.pool_size">10</property>
		<property name="format_sql">true</property>
		<property name="show_sql">true</property>
        <!-- SessionFactory开启二级缓存-->
		<property name="cache.use_second_level_cache">true</property>
        <!-- SessionFactory二级缓存实现方-->
		<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

		<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>	
		<!-- 使用getCurrentSession()必须要有以下配置 值为thread或jta-->	
		<property name="current_session_context_class">thread</property>
		<mapping class="com.muchen.entity.Xzqh"/>
		<mapping class="com.muchen.entity.VoteInfo"/>
	</session-factory>
</hibernate-configuration>

3. 指定缓存对象

3.1 配置映射文件的方式 

添加:<cache usage="read-only"/>

<class name="Vote" table="T_VOTE" catalog="MASZWFW">
		<cache usage="read-only"/>
		<id name="uuid" column="uuid">
			<generator class="uuid"></generator>
		</id>
		<property name="businesseId" column="BUSINESSID"></property>
		<property name="date" column="VOTE_DATE"></property>
		<property name="order" column="VOTE_ORDER"></property>
		<property name="type" column="VOTE_TYPE"></property>
		<property name="userAccount" column="USER_ACCOUNT"></property>
	</class>

3.2 注解方式

实体上添加缓存注解:@Cache(usage=CacheConcurrencyStrategy.READ_ONLY)

@Entity
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY)
@Table(name="T_JC_VOTEINFO",catalog="XZSP")
public class VoteInfo {
		
	private Integer id;
	private String voteName;
	private Integer voteKindId;
	private String voteObject;
	private String type;
	private String year;
	
	@Id
	@Column(name="ID")
	@GeneratedValue(strategy=GenerationType.SEQUENCE)
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	@Column(name="VOTENAME")
	public String getVoteName() {
		return voteName;
	}
	public void setVoteName(String voteName) {
		this.voteName = voteName;
	}
}

注:read-only方式用的多,因为缓存中适合放置的对象基本为以下几种

a. 不怎么需要变动(写操作很少)

b. 不考虑并发的不是很重要的数据

c. 数据量不是很大的情况(多了反而占用资源,性能下降)

4. 配置缓存文件ehcache.xml

放置在classpath路径下,Configuration.config加载hibernate配置文件解析session-factory元素时加载ehcache.xml文件。

<?xml version="1.0" encoding="UTF-8"?>
        
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd" >

    <!-- 指定磁盘缓存路径 
    * user.home - 用户的主目录
    * user.dir - 用户当前工作目录
    * java.io.tmpdir - 默认临时文件路径   -->
    <diskStore path="e:\\tempCache"/>
    
    <!-- 设置缓存的默认数据过期策略 -->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            maxElementsOnDisk="10000000"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
            />
    <!--  
        设定具体的命名缓存的数据过期策略。每个命名缓存代表一个缓存区域
        缓存区域(region):一个具有名称的缓存块,可以给每一个缓存块设置不同的缓存策略。
        如果没有设置任何的缓存区域,则所有被缓存的对象,都将使用默认的缓存策略。即:<defaultCache.../>
        Hibernate 在不同的缓存区域保存不同的类/集合。
            对于类而言,区域的名称是类名。如:com.atguigu.domain.Customer
            对于集合而言,区域的名称是类名加属性名。如com.atguigu.domain.Customer.orders
    -->
    <!--  
        name: 设置缓存的名字,它的取值为类的全限定名或类的集合的名字
        maxElementsInMemory: 设置基于内存的缓存中可存放的对象最大数目
        eternal: 设置对象是否为永久的, true表示永不过期,
            此时将忽略timeToIdleSeconds 和 timeToLiveSeconds属性; 默认值是false
        timeToIdleSeconds:设置对象空闲最长时间,以秒为单位, 超过这个时间,对象过期。
            当对象过期时,EHCache会把它从缓存中清除。如果此值为0,表示对象可以无限期地处于空闲状态。
        timeToLiveSeconds:设置对象生存最长时间,超过这个时间,对象过期。
            如果此值为0,表示对象可以无限期地存在于缓存中. 该属性值必须大于或等于 timeToIdleSeconds 属性值
        overflowToDisk:设置基于内存的缓存中的对象数目达到上限后,是否把溢出的对象写到基于硬盘的缓存中
        diskPersistent:  在重新启动虚拟机之间,磁盘存储是否持久化,默认值为false。

        diskExpiryThreadIntervalSeconds:运行磁盘过期线程之间的秒数。默认值是120秒

        diskSpoolBufferSizeMB: 这是为spool缓冲区分配磁盘存储的大小。写的是然后异步写入磁盘。默认大小为30MB。

        memoryStoreEvictionPolicy:缓存对象清除策略。有三种: 

        1 FIFO ,first in first out ,先进先出

        2 LFU , Less Frequently Used ,一直以来最少被使用的。缓存的元素有一个hit 属性,hit 值最小的将会被清出缓存。 

        3 LRU ,Least Recently Used ,(默认)最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
    -->
    <cache name="com.muchen.entity.VoteInfo"
        maxElementsInMemory="1"
        eternal="false"
        timeToIdleSeconds="60"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        />
 
</ehcache>

注意:ehcache.xml放在项目中时,里面不能有中文,是中文注释也不行,会报错。

查看二级缓存:

Map cacheMap = sessionFactory.getStatistics().getSecondLevelCacheStatistics("com.muchen.entity.VoteInfo").getEntries();

只要是对com.muchen.entity.VoteInfo的查询操作都会进入二级缓存,不管是get(),load(),iterator()还是Query的方法,只要SessionFactory不关闭,缓存的对象在配置的有效时间内会一直存在,除非被手动清除。

清除指定缓存对象:

清除指定对象:   sessionFactory.evict(VoteInfo.class,指定id);

清除所有某对象: sessionFactory.evict(VoteInfo.class);

hibernate缓存对象的3种状态

transient:瞬时态,一般是通过new 获得的对象,尚未与session取得关联,随时被jvm回收;

persistent:持久态,在数据库有对应的记录,通过查询或保存瞬时态获得的对象,此时存在session中;

detached:游离态,有OID,由于session关闭失去与session的关联,变成游离态。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值