【JavaEE学习笔记】Hibernate_04_ORM,Hibernate,主键策略,uuid

Hibernate_04

A.模式,层

1.模式与框架

a.模式

是专家总结出来,在某种情况下,解决某类问题的最佳解决方案

是思想、知识

b.框架

是一种半成品软件,供开发者进行制定,达到简化开发

是工具

2.四层架构

表现层:Struts2    SpringMVC

业务层:Spring

持久层:Hibernate  mybatis

域对象层:用于层和层之间数据传递,经常被省略

3.持久化存放

JDBC->DAO模式->ORM

(Object Relation Mapping对象映射关系,允许用户以操作对象的方式操作关系型数据库)

ORM主要解决了对象模型和关系模型的阻抗不匹配

B.ORM

1.概述

是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术

2.本质

ORM是通过使用描述对象和数据库之间映射的元数据

将java程序中的对象自动持久化到关系数据库中

本质上就是数据从一种形式转到另外一种形式

3.结论

使用orm技术,可以在java程序以类和对象的方式去操控数据库表和记录

4.原理


5.优点

提高生产率

可维护性

更好性能

厂商独立性

C.Hibernate

1.概述

一种对象和关系之间映射ORM的框架

对JDBC进行了轻量级的对象封装

使Java程序员可以使用对象编程思想来操作关系数据库

开源免费,有丰富的文档和稳定的开发背景

2.优点

开源免费,方便需要时研究,改写源码,进行功能的定制

简单,避免引用过多复杂问题,进行轻量级封装,容易调试

具有可扩展性,API开放,根据需要扩展

稳定的性能,开源社区,团体,公司和个人的广泛支持

文档丰富,齐全,目前依然不断更新,维护中

3.缺点:有过度封装的嫌疑

4.五大核心编程接口

a.Configuration

负责管理Hibernate的配置信息

这个对象用于创建sessionFactory,属于即用即丢型对象

所以最佳的生命周期为方法内部,包括:

Hibernate运行的底层信息:数据库的URL,用户名,密码,JDBC驱动类,数据库Dialect,数据库连接池等(对应的hibernate.cfg.xml文件)

持久化类与数据表的映射关系(*.hbm.xml文件)

public class HibernateSessionFactory {
    private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
    private  static Configuration configuration = new Configuration();    
	public static Configuration getConfiguration() {
		return configuration;
	}

}
创建Configuration的两种方式

属性文件(src/hibernate.properties)

Configuration cfg = new Configuration();

xml文件(src/hibernate.cfg.xml)推荐

// 没有参数,则默认配置文件名称为hibernate.cfg.xml,位于src目录下
Configuration cfg = new Configuration().configure();

b.SessionFactory接口

Configuration对象根据当前的配置信息生成 SessionFactory 对象

SessionFactory 对象一旦构造完毕,即被赋予特定的配置信息

(SessionFactory 对象中保存了当前的数据库配置信息和所有映射关系以及预定义的SQL语句)

SessionFactory负责维护Hibernate的二级缓存

属于重量级对象,一般针对一个数据源只创建一个SessionFactory对象

最佳生命周期为应用范围,最佳的编程实践可以采用单例模式

    Session session = sf.openSession();
    Session session=sf.getCurrentSession();
这两种方法的区别?

getCurrentSession创建会先在上下文中查找,如果有,则直接获取,没有则创建,而Session则是直接创建

getCurrentSession会在事务回滚或事物提交后自动关闭,而openSession必须手动关闭

但getCurrentSession的使用必须配置

c.Session接口

Session充当了实体管理器的功能

是应用程序与数据库之间交互操作的一个单线程对象

是Hibernate运作的中心

所有持久化对象必须在session的管理下才可以进行持久化操作

此对象的生命周期很短,Session对象有一个一级缓存

显式执行flush之前,所有的持久层操作的数据都缓存在session对象处

相当于JDBC中的Connection

持久化类PO与Session关联起来后就具有了持久化的能力

是线程不安全的轻量级对象,使用ThreadLocal变量解决

最佳生命周期为request或者方法体内

是Connection对象的浅封装,必须使用try/finally结构保证及时关闭

package com.wpf.hibernate;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public class HibernateSessionFactory {
	private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
	private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
	private static final ThreadLocal<Transaction> ts = new ThreadLocal<Transaction>();
	private static Configuration configuration = new Configuration();
	private static org.hibernate.SessionFactory sessionFactory;
	private static String configFile = CONFIG_FILE_LOCATION;

	static {
		try {
			configuration.configure(configFile);
			sessionFactory = configuration.buildSessionFactory();
		} catch (Exception e) {
			System.err.println("%%%% Error Creating SessionFactory %%%%");
			e.printStackTrace();
		}
	}

	private HibernateSessionFactory() {
	}

	public static Transaction beginTransaction() throws HibernateException {
		Transaction tx = ts.get();
		if (tx == null) {
			Session session = getSession();
			tx = session != null ? session.beginTransaction() : null;
			ts.set(tx);
		}
		return tx;
	}

	public static void commitTransaction() throws HibernateException {
		Transaction tx = ts.get();
		ts.set(null);
		if (tx != null)
			tx.commit();
	}

	public static void rollbackTransaction() throws HibernateException {
		Transaction tx = ts.get();
		ts.set(null);
		if (tx != null)
			tx.rollback();
	}

	public static Session getSession() throws HibernateException {
		Session session = (Session) threadLocal.get();

		if (session == null || !session.isOpen()) {
			if (sessionFactory == null) {
				rebuildSessionFactory();
			}
			session = (sessionFactory != null) ? sessionFactory.openSession() : null;
			threadLocal.set(session);
		}

		return session;
	}

	public static void rebuildSessionFactory() {
		try {
			configuration.configure(configFile);
			sessionFactory = configuration.buildSessionFactory();
		} catch (Exception e) {
			System.err.println("%%%% Error Creating SessionFactory %%%%");
			e.printStackTrace();
		}
	}

	/**
	 * Close the single hibernate session instance.
	 * 
	 * @throws HibernateException
	 */
	public static void closeSession() throws HibernateException {
		Session session = (Session) threadLocal.get();
		threadLocal.set(null);

		if (session != null) {
			session.close();
		}
	}

	public static org.hibernate.SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	public static void setConfigFile(String configFile) {
		HibernateSessionFactory.configFile = configFile;
		sessionFactory = null;
	}

	public static Configuration getConfiguration() {
		return configuration;
	}
}
在web应用,一般使用filter实现一个用户请求处理过程中对应一个session

对应一个transaction,优势在于不用考虑延迟加载的问题

但是会影响并发性,使用getCurrentSession()解决

package com.wpf.hibernate;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class OpenSessionInViewFilter implements Filter {

	@Override
	public void destroy() {

	}

	@Override
	public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
			throws IOException, ServletException {
		try {
			HibernateSessionFactory.beginTransaction();
			arg2.doFilter(arg0, arg1);
			HibernateSessionFactory.commitTransaction();
		} catch (Exception e) {
			HibernateSessionFactory.rollbackTransaction();
			// 必须抛出异常
			throw new ServletException(e);
		} finally {
			HibernateSessionFactory.closeSession();
		}
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {

	}

}
web.xml配置

注意和struts2前端控制的顺序

OpenSessionInViewFilter在StrutsPrepareAndExecuteFilter之前

<filter>
	<filter-name>openSession</filter-name>
	<filter-class>com.yan.filter.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>openSession</filter-name>
	<url-pattern>*.action</url-pattern>
</filter-mapping>

session类的方法

get和load的区别

1)load默认采用的延迟加载机制当调用load方法时,先在缓存中查找,如果找到了则立即返回;如果没有则立即返回一个代理对象,如果访问代理对象中的非键属性时才执行查找操作(要求session不能关闭,否则org.hibernate.LazyInitializationException:),get方法默认采用的是立即加载机制当调用get方法时,首先在缓存中查找则立即返回;如果没有找到对应的数据则立即执行数据库查询获取数据

2)load方法在查询不到对应id的对象时,会抛出一个异常org.hibernate.ObjectNotFoundException,当使用get时返回为null,没有异常

Save(obj):Serializable返回一个主键值

saveOrUpdate(obj):void

update(obj):void,执行按照obj的id值修改所有的非id属

delete(obj):void 按照obj的id属性值执行按照id删除操作

mysql的中文

<propertyname = connection.url ">
	jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
</property>

d.Transaction接口

用于封装底层的事务实现

代表一次原子操作,它具有数据库事务的概念

所有持久层都应该在事务管理下进行

即使是只读操作(可以使hibernate针对底层操作进行优化处理)

线程不安全的轻量级对象,最佳生命周期为方法体内

可以使用ThreadLocal进行管理

(这里是为了编码方便,实际上session和Transaction是绑定的)

session.beginTransaction();

session.getTransaction().commit();

扩展工具类新增的方法(参考上条代码)

e.Query和Criteria

用于实现复杂查询操作

Hibenrate中默认提供了5种查询方法:

OID按照id进行查询

HQL:hibrnate query language(有人读为/黑扣/)是Hibernate提供的一种面向对象的查询方法,使用Query接口

QBC:Query by criteria(使用Criteria的查询,重点在于QBE)、

NativeSQL本地化SQL(一般不推荐使用,如果需要使用SQL进行优化,一般建议使用MyBatis)

OGN对象导航,用于关联另外的对象执行的查询

D.映射元文件中的id设置

1.主键生成策略

PK---实现实体完整性---定义主键有两种形式

代理主键和自然主键,hibernate 一般推荐使用代理主键

自然主键是用assigned人为赋值的方式作为主键生成机制

这是唯一选择,由用户自行保证唯一性,自然主键可以是任意类型

	<id name="id" type="java.lang.Long">
		<column name="id" />
		<generator class="assigned"></generator>
	</id>

2.代理主键类型

a.整型

	<id name="id" type="java.lang.Long">
		<column name="id" />
		<generator class="native"></generator>
	</id>

由hibernate负责管理维护主键值

即时编程中对id进行赋值也是无效的

这是由hibernate根据底层数据库判断使用哪种主键生成器

自行在hilo、identity、sequence三种生成器中进行选择

identity主要用于mysql(auto_increment)或者sqlserver(identity(1,1))

实现由底层数据库生成一组连续增长值作为主键(Oracle不支持)

	<id name="id" type="java.lang.Long">
		<column name="id" />
		<generator class="identity"></generator>
	</id>

sequence主要用于oracle或者db2

实现由底层的序列对象负责生成一组连续值

create sequence seq1 start with 1 maxvalue 99999999999999999

	<id name="id" type="java.lang.Long">
		<column name="id" />
		<generator class="sequence">
			<param name="sequence">seq1</param>
		</generator>
	</id>

Hilo高低位算法,主键值是由两部分构成的(hibernate5已经不支持)

高位值

在数据库中创建一个独立的表用于存放高位值,每次使用后会自动加1

低位值

hibernate所维护的一个连续增长值

	<id name="id" type="java.lang.Long">
		<column name="id" />
		<generator class="hilo" />
	</id>

increment主键按数值顺序递增

此方式的实现机制为在当前应用实例中维持一个变量

以保存着当前的最大值

之后每次需要生成主键的时候将此值加1作为主键

这种方式可能产生的问题是:

如果当前有多个实例访问同一个数据库,

那么由于各个实例各自维护主键状态

不同实例可能生成同样的主键

从而造成主键重复异常

因此,如果同一数据库有多个实例访问,此方式必须避免使用

b.字符串--浪费空间、无序、可用于分布式应用中

uuid.hex由Hibernate基于128 位唯一值产生算法生成16 进制数值(编码后以长度32 的字符串表示)作为主键

uuid.string与uuid.hex 类似,只是生成的主键未进行编码(长度16)。在某些数据库中可能出现问题(如PostgreSQL)

一般而言,利用uuid.hex方式生成主键将提供最好的性能和数据库平台适应性

对于并发Insert要求较高的系统,推荐采用uuid.hex 作为主键生成机制

uuid标识符生成器使用一个128位的全局唯一标识符Universally Unique Identifier,UUID算法生成字符串类型的标识符

UUID包含本机的IP地址、本机JVM的信息,相对于同一时空中的所有机器都是唯一的

uuid标识符生成器由Hibernate维护并生成uuid值,不依赖于底层数据库的实现细节,因而可以适用于所有数据库

	<id name="id" type="java.lang.Long">
		<column name="id" />
		<generator class="uuid" />
	</id>

3.复合自然主键

针对复合主键类型,需要生成两个方法

hashCode和equals

	<id name="id" type="java.lang.Long">
		<column name="id" />
		<generator class="uuid" />
	</id>


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值