轻量级JavaEE应用的持久层解决方案。充当了面向对象程序设计语言和关系数据库之间的桥梁,Hibernate允许开发者采用面向对象的方式来操作关系型数据库。因为有了Hibernate的支持,使得JavaEE应用的OOA(面向对象分析)、OOD(面向对象设计)、OOP(面试相对象编程)三个过程一脉相承,成为一个整体。
ORM(对象关系数据库映射)是一种规范,概述了这类框架的基本特征。
ORM工具的唯一作用是:把持久对象的保存、删除、修改等操作。转换成对数据库的操作。从此程序员就可以以面向对象的方式操作持久化对象,而ORM框架负责转换成对应的SQL(结构化查询语言)操作。
Hibernate
1、 数据库连接池的理解
为什么 要有数据库连接池?
打开和 关闭数据库 链接的开销很大,数据库连接池技术允许我们维护数据库连接对象,提高数据库执行命令的性能。多个客户端请求可以重复使用连接池中的连接对象,每当客户端请求连接数据库时,就会搜索连接池,若没有闲置对象,则进入等待队列,或者在连接池中新建一个连接对象。一旦客户端使用完连接对象时,这个对象就会被放入连接池中,供其他请求使用。因为大部分请求都是用现成的连接对象不用自己去创建(耗时操作),所以连接池技术大大减少了等待创建数据库连接对象的时间,减少平均连接时间。
怎么使用数据库连接池?
应用服务器负责创建数据库连接对象,添加他们到连接池中,分别对客户端请求分配连接对象,回收使用完毕的数据库连接对象,重新放回连接池中。
2、 hibernate PO = POJO+持久化注解;
@Entity 声明该类是一个Hibernate 的持久化类
@Table(name=xxx) 志明该类映射到数据库那个表
@Id 用于 指定该类的标识属性
3、 理解JNDI?
JNDI java命名目录接口
看这样的代码
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver", true, Thread.currentThread().getContextClassLoader());
String user = "root";
String password = "123";
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/hibernate_db",user,password);
System.out.println(conn);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}finally {
if(conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
当你 url 、user、pass变动时必须改变java代码。最好的情况是程序员不需要关心数据库后台是什么、用户名密码、jdbc的URL格式是什么等等的问题。把这些问题交给j2EE容器来配置管理,程序员 只需对这些配置引用即可。那么JNDI出现了。
我们可以直接访问容器管理的数据源。
那么怎么在Tomcat上配置一个数据源呢?我们知道一个服务器 可以配置多个数据源,而这些数据源DataSource被绑定在JNDI树上(为每个数据源提供一个名字),客户端访问数据库是通过名字在JNDI树上找到对应的数据源,再找到对应的连接。
利用Eclipse配置Tomcat数据源
方案一 配置局部数据源 即 只有该应用可以使用的数据源
创建项目比如hibernate_cfg,在其META_INF下面创建Context.xml主要代码如下
"jdbc/mysql" auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/hibernate_db"
username="root" password="123" maxActive="5"
maxIdle="2" maxWait="10000"
/>
web.xml配置如下
<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<resource-ref>
<description>mysql DB connectiondescription>
<res-ref-name>jdbc/mysqlres-ref-name>
<res-type>javax.sql.DataSourceres-type>
<res-auth>Containerres-auth>
resource-ref>
web-app>
方案二
在tomcat目录下的/conf/context.xml配置如下代码(在context标签中)
"jdbc/mysql" auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/hibernate_db"
username="root" password="123" maxActive="5"
maxIdle="2" maxWait="10000"
/>
Web.xml 中配置如下
<resource-ref>
<description>mysql DB connectiondescription>
<res-ref-name>jdbc/mysqlres-ref-name>
<res-type>javax.sql.DataSourceres-type>
<res-auth>Containerres-auth>
resource-ref>
第三种 使用全局配置的数据源
找到tomcat的server.xml文件 在标签中添加如下代码
"jdbc/mysql" auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/hibernate_db"
username="root" password="123" maxActive="5"
maxIdle="2" maxWait="10000"
/>
Tomcat安装目录下的/conf/context.xml中context标签中
<resourceLink name=”jdbc/mysql” global=”jdbc/mysql” type=”javax.sql.DataSource”/>
类似
<Context docBase="WebApp" path="/WebApp" reloadable="true">
<ResourceLink global="jdbc/mysql" name="jdbc/mysql" type="javax.sql.DataSource" />
Context>
然后再web.xml中添加配置
<resource-ref>
<description>mysql DB connectiondescription>
<res-ref-name>jdbc/mysqlres-ref-name>
<res-type>javax.sql.DataSourceres-type>
<res-auth>Containerres-auth>
resource-ref>
最后便可以操作数据库了
Context initContext = new InitialContext();
Context ctx = (Context)initContext.lookup(“java:/comp/env/jdbc/mysql”);
DataSource ds = (DataSource)ctx.lookup(“jdbc/appDS”);
Connection conn = ds.getConnection(); //数据操作
4、Hibernate 核心接口
1、 Configuration
配置hibernate启动 hibernate 创建sessionFactory对象
2、 Sessionfactory
创建session. SessionFactory对象保存了当前数据库的配置信息和所有映射关系以及预定义的sql语句。同时 sessionFactory负责维护hibernate的二级缓存。SessionFactory的创建会有很大的开销,而且采取了线程安全的设计方式,因此SessionFactory可以尽量的共享。通常情况下,一个应用程序中针对 一个数据库可以共享一个SessionFactory对象。
Configration config = new Configration().configure();
SessionFactory factory = config.buildSessionFactory();
Session session =factory.getSession();
3、 Session
持久化管理器,提供和持久化相关的操作,增删改查,不是线程安全的,因此,一个session对象只能有一个线程来使用,避免多个线程共享,创建和销毁是轻量级的不许需要太多的资源。Session有个缓存称为一级缓存,存放当前单元加载的对象。
4、 Transaction hibernate 数据库事务接口
使用hibernate 进行增删改时必须显示调用事务Transaction.
Transaction tx = session.beiginTransaction();
5、 query和Criteria 接口
查询接口query实例包装了HQL查询语句,hql是面相对象的,它引用类名及属性名,而不是表名和字段名。Criteria完全封装了字符串查询语句,比query更加面向对象,擅长执行动态查询,session接口的find 方法也可以执行查询但也只是执行简单HQL语句查询的快捷方式,远没有query 功能强大。
5、hibernate运行过程
1、配置好Hibernate 的配置文件 和 与类对应的配置文件后,启动服务器
2、服务器通过实例化Configeration对象,读取hibernate.cfg.xml 文件的配置内容,并根据相关的需求建好表或者和表 建好映射关系
3、通过实例好的Configration对象就可以建立SessionFactory实例,进一步,通过SessionFactory 创建Session对象。
4、得到session 之后便可以对数据库进行操作了,除了比较复杂的全文搜索外,简单的操作都可以通过hibernate 封装好的session内置方法来实现。
Hibernate是如何连接数据库的?
主要是通过hibernate.cfg.xml 配置文件中的配置,这个文件定义了数据库连接所需要的信息包括数据库驱动、用户名、 密码 、数据库方言、等等Configeration 类借助dom4j的xml解析环器解析设置环境,然后使用这些环境属性来生成SessionFactory。这样这个SessionFactory就可以生成session获取数据库连接。、
Hibernate是如何进行数据库写操作?
对数据库的写操作包括保存、更新、和删除,当保存一个持久化对象时,触发Hibernate 保存事件监听器进行处理。Hibernate通过映射文件后的对象对应的数据库表名以及属性所对应的列名,然后通过反射机制持久化对象的各个属性,最终向数据库插入新对象的sql insert语句,调用了session.save()方法后这个对象会标识成持久化状态保存在session 中,对于hibernate来说这就是一个持久化了的对象,但这是hibernate 还不会真正的执行insert 语句,当进行session flush的时候 Hibernate 会把session缓存中的所有sql语句一起执行,对于跟新、删除操作都是这样的机制。然后提交事务并提交成功后这些写操作就会被永久的保存在数据库中,所以使用session对数据库操作还依赖于hibernate对事务的处理。如果设置了二级缓存,那么这些操作会被同步到二级缓存中。
Hibernate 如何从数据库中载入对象?
当时用session.load()载入对象是,可以设置是否采用延迟加载,如果延迟加载,那么load返回的对象世纪是CGLIB或者javassist返回的代理类,它的非主键属性都是空的,这对于对象集合属性很邮箱。Hibernate以此来节约内存,当真正需要读取对象时,hibernate会首先从缓冲中那数据,或者根据逐渐对象类型等信息组织select 语句导数据中读取,再把select结果封装成对象返回。
这里说一下 session.get() 和session.load()的区别
Session.load()加载一个对象时,此时并不会立即发出sql语句,当前的到的这个对象其实是代理对象,这个代理对象只是保存了实体对象的id值,到我们使用这个对象想要操作这个对象的其他属性的时候 ,才会发出sql语句返回结果。
而get并未实现延迟加载策略。
在实际 写一个简单案例的时候 还是遇到了不少麻烦! 我用的是hibernte5.2.10 MYSQL Eclipse oxygen Tomcat8.5用以下方式可以用tomcat 配置的全局数据源来进行数据库连接
项目总体布局
Person.java
package com.gjl.bean;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/*@Entity
@Table(name="Person")*/
public class Person {
/* @Id
@GeneratedValue(strategy=GenerationType.IDENTITY)*/
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
TestServlet.java
package com.gjl.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import com.gjl.bean.Person;
@WebServlet("/TestSevlet")
public class TestSevlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public TestSevlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int id= Integer.parseInt(request.getParameter("id"));
// SessionFactory sessionFactory = (SessionFactory) request.getServletContext().getAttribute("SessionFactory");
/*Configuration configuration = new Configuration();
configuration.configure("hibernate.cfg.xml");
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
SessionFactory sessionFactory = configuration
.buildSessionFactory(serviceRegistry);
Session session = sessionFactory.openSession();*/
StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder()
.configure( "hibernate.cfg.xml" )
.build();
Metadata metadata = new MetadataSources( standardRegistry )
.addAnnotatedClass(Person.class )
// You can add more entity classes here like above
.addResource( "mapping.hbm.xml" )
.getMetadataBuilder()
.applyImplicitNamingStrategy(ImplicitNamingStrategyJpaCompliantImpl.INSTANCE )
.build();
SessionFactory sessionFactory = metadata.getSessionFactoryBuilder().build();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Person emp = (Person) session.get(Person.class,id);
tx.commit();
PrintWriter out = response.getWriter();
response.setContentType("text/html");
if(emp != null){
out.print("Employee Details
");
out.print("");
out.print("PERSON ID ");
out.print("Person Name ");
out.print("Person Age ");
out.print("");
out.print("" + id + " ");
out.print("" +emp.getName() + " ");
out.print("" + emp.getAge() + " ");
out.print(" ");
out.print("
");
out.print("");
}else{
out.print("No Employee Found with ID="
+id+"");
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
/*@WebServlet("/GetEmployeeByID")
public class GetEmployeeByID extends HttpServlet {
private static final long serialVersionUID = 1L;
public final Logger logger = Logger.getLogger(GetEmployeeByID.class);
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int empId = Integer.parseInt(request.getParameter("empId"));
logger.info("Request Param empId="+empId);
SessionFactory sessionFactory = (SessionFactory) request.getServletContext().getAttribute("SessionFactory");
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
Employee emp = (Employee) session.get(Employee.class, empId);
tx.commit();
PrintWriter out = response.getWriter();
response.setContentType("text/html");
if(emp != null){
out.print("Employee Details
");
out.print("");
out.print("Employee ID ");
out.print("Employee Name ");
out.print("Employee Role ");
out.print("");
out.print("" + empId + " ");
out.print("" + emp.getName() + " ");
out.print("" + emp.getRole() + " ");
out.print(" ");
out.print("
");
out.print("");
}else{
out.print("No Employee Found with ID="+empId+"
");
}
}
}*/
hibernate.cfg.xml
<hibernate-configuration>
<session-factory>
<property name="connection.datasource">java:comp/env/jdbc/mysqlproperty>
<property name="dialect">org.hibernate.dialect.MySQLDialectproperty>
<property name="show_sql">trueproperty>
<property name="hibernate.format_sql">trueproperty>
<property name="hibernate.current_session_context_class">threadproperty>
session-factory>
hibernate-configuration>
mapping.hbm.xml
<hibernate-mapping>
<class name="com.gjl.bean.Person" table="Person">
<id name="id" type="int" column="id">
<generator class="assigned"/>
id>
<property name="name" column="name" type="string" length="20" />
<property name="age" column="age" type="int" length="20" />
class>
hibernate-mapping>
web.xml
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:web="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" id="WebApp_9" version="2.4">
<resource-ref>
<description>mysql DB connectiondescription>
<res-ref-name>jdbc/mysqlres-ref-name>
<res-type>javax.sql.DataSourceres-type>
<res-auth>Containerres-auth>
resource-ref>
web-app>
最后在浏览器 中输入 http://localhost:8080/Hibernate_datasource/TestSevlet?id=1
(要有自己数据库 别忘了)
如下结果
这样就可以用hibernate 进行与数据库的交互。