Hibernate的ORM原理和实现

简介: ORM的全称是Object Relational Mapping,即对象关系映射。它的实现思想就是将关系数据库中表的数据映射成为对象,以对象的形式展现,这样开发人员就可以把对数据库的操作转化为对这些对象的操作。

Hibernate和ORM

ORM的全称是Object Relational Mapping,即对象关系映射。它的实现思想就是将关系数据库中表的数据映射成为对象,以对象的形式展现,这样开发人员就可以把对数据库的操作转化为对这些对象的操作。因此它的目的是为了方便开发人员以面向对象的思想来实现对数据库的操作。

Hibernate是如何实现映射的

在使用Hibernate实现ORM功能的时候,主要的文件有:映射类(*.java)、映射文件(*.hbm.xml)以及数据库配置文件(*.properties或*.cfg.xml),它们各自的作用如下:

⑴映射类:它的作用是描述数据库表的结构,表中的字段在类中被描述成属性,将来就可以实现把表中的记录映射成为该类的对象。

⑵映射文件:它的作用是指定数据库表和映射类之间的关系,包括映射类和数据库表的对应关系、表字段和类属性类型的对应关系以及表字段和类属性名称的对应关系等。

⑶数据库配置文件:它的作用是指定与数据库连接时需要的连接信息,比如连接哪中数据库、登录用户名、登录密码以及连接字符串等。

在这三种主要的文件中,映射类为普通Java源文件、映射文件为XML格式、数据库配置文件为Properties格式或者是XML格式。想理解“映射”首先我们需要知道如何解析这三种文件,即解析XML格式文件、解析Properties格式文件和解析Java类文件。

⑴如何解析XML文件
解析XML的技术可以分为两类那就是SAX和DOM,这两种方式有各自的差别和优缺点。实现解析XML文件的功能很方便,我们可以通过下载第三方的一些工具包如xml-apis.jar和xercesImpl.jar等,也可以使用JDK自带的工具类DocumentBuilderFactory、
DocumentBuilder、Document、Element等等,大家可以通过API文挡查阅这些类的说明。通过这些类我们可以把XML文件的信息读入内存并通过类中的某些方法获取指定节点的名字、值、属性名、属性值这些信息。

⑵解析Properties文件
Properties文件一般采用“属性名=属性值”的形式描述信息。
如果配置文件采用Properties文件描述,我们就需要想办法解析这种类型的文件了。想解析Properties文件需要熟悉Properties这个类了,这个类有一些常用方法比如,load()加载指定文件并读取文件中的属性信息,PropertyNames()返回所有属性名,getProperty()返回指定属性名的属性值。通过解析Properties文件我们可以得到连接数据库必要的信息,然后通过底层JDBC技术与数据库建立连接。

⑶解析Java类文件
通过解析映射文件和数据库配置文件我们可以建立数据库的连接,可以得到映射类的名字、属性名、数据库表名、字段名以及类型等信息。要把数据库中表的数据映射成为对象,首先需要把表中的记录取出,然后将每个字段值给映射类对象的每个属性,这个赋值过程要调用对象中的set方法。
我们现在通过映射文件只知道类名和属性名,如何根据类名和属性名调用相应的set和get方法,是一个关键问题。在Java中有一种机制叫反射机制,使用这种机制我们可以得到类的信息,包括类只用的修饰符、方法、属性、继承的父类以及实现接口等信息。
反射机制相关的类有Class、Field、Method以及Constructor等。通过Class的getFields()、getMethods()和getConstructors()方法得到相应的属性、方法和构造方法。
通过Field类的getName()、getType()和getModifiers()方法得到相应的属性名、属性类型、属性修饰符信息。
通过Method类getReturnType()可以获取方法的返回类型,
invoke()方法可以根据给定的方法名和参数值执行对象中对应的方法。
我们可以首先通过以上方法获取类中的属性名,然后拼写成setXXX和getXXX方法名,最后根据方法名执行对应的方法,将数据库数据加载到对象中。

整理自 Hibernate框架ORM的实现原理


模拟Hibernate加载配置文件并映射到实体类的过程

 

(1)创建实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
  * 示例实体对象
  * 对应学生表
  */
public  class  Student {
 
     private  int  id;
     private  String name;
     private  String score;
     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  String getScore() {
         return  score;
     }
     public  void  setScore(String score) {
         this .score = score;
     }
}

  

(2)模拟解析hbm.xml和数据库配置文件,并且创建Session

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import  java.io.IOException;
import  java.lang.reflect.Method;
import  java.sql.Connection;
import  java.sql.DriverManager;
import  java.sql.PreparedStatement;
import  java.util.HashMap;
import  java.util.List;
import  java.util.Map;
import  org.jdom.Document;
import  org.jdom.Element;
import  org.jdom.JDOMException;
import  org.jdom.input.SAXBuilder;
import  org.jdom.xpath.XPath;
 
/**
  * 模拟Session类实现
  */
public  class  Session {
     
     /**
      * 模拟Stument.hbm.xml文件的内容
      * 这里没有解析hbm.xml
      */
     private  Map<String ,String > hbmInfo =  new  HashMap<String ,String >();
     
     //存放数据库连接配置
     private  Map<String, String> conConfig =  new  HashMap<String, String>();
 
     //实体的get方法集合
     String methodNames[];
     
     public  Session(){
         /**
          * 初始化实体,具体的实现应该是读取hbm.xml文件解析字段
          */
         hbmInfo.put( "id" "id" ); 
         hbmInfo.put( "name" "name" ); 
         hbmInfo.put( "password" "password" ); 
         methodNames =  new  String[hbmInfo.size()]; 
     }
 
     /**
      * 创建数据库连接
      * @return
      * @throws IOException
      * @throws JDOMException
      */
     public  Connection initConn()  throws  Exception{
         SAXBuilder sb =  new  SAXBuilder(); 
         Document doc = sb.build( this .getClass().getClassLoader().getResourceAsStream( "hibernate.cfg.xml" )); 
         Element root = doc.getRootElement(); 
         List list = XPath.selectNodes(root,  "/hibernate-configuration/property" ); 
 
         for  ( int  i =  0 ; i < list.size(); i++) {             
            Element property = (Element) list.get(i); 
            String name = property.getAttributeValue( "name" ); 
            String value = property.getText();          
            conConfig.put(name, value);          
           }
         
       //根据配置文件获得数据库连接
         Class.forName(conConfig.get( "driver" )); 
         Connection con = DriverManager.getConnection(conConfig.get( "url" ),conConfig.get( "username" ),conConfig.get( "password" ));
         return  con; 
     }
     
     /**
      * 持久化对象
      * @param student
      */
     public  void  save(Student student) {
         
          String sql = getSaveStatement(); 
          System.out.println(sql); 
       
          try  {
             //获得连接
             Connection con = initConn();
             //创建jdbc执行语句
             PreparedStatement state =  (PreparedStatement) con.prepareStatement(sql); 
             
             for ( int  i= 0 ;i<methodNames.length;i++) { 
 
                 //得到每一个方法的对象 
                 Method method = student.getClass().getMethod(methodNames[i]); 
 
                 //得到他的返回类型 
                 Class cla = method.getReturnType(); 
 
                 //根据返回类型来设置插入数据库中的每个属性值。 
                 if (cla.getName().equals( "java.lang.String" )) { 
                     String returnValue = (String)method.invoke(student); 
                     state.setString(i+ 1 , returnValue); 
                
                 else  if (cla.getName().equals( "int" )) { 
                     Integer returnValue = (Integer) method.invoke(student); 
                     state.setInt(i+ 1 , returnValue); 
                 }                       
            
 
             state.executeUpdate(); 
             state.close(); 
             con.close(); 
         catch  (Exception e) {
             e.printStackTrace();
        
     }
     
     
     private  String getSaveStatement(){
         //strColumn代表数据库中表中的属性列。并将其连接起来。 
         String strColumn =  ""
         int  index= 0
         for (String key :hbmInfo.keySet()) 
        
             strColumn +=key+ ","
             String v = hbmInfo.get(key); 
 
             //获得属性的get方法,需要将属性第一个字母大写如:getId()
             v =  "get"  + Character.toUpperCase(v.charAt( 0 )) + v.substring( 1 ); 
             methodNames[index] = v;
             index++; 
        
         strColumn  = strColumn.substring( 0 , strColumn.length()- 1 ); 
 
         //拼接参数占位符,即:(?, ?, ?)
         String strValue =  ""
         for ( int  i= 0 ;i<hbmInfo.size();i++) 
             strValue += "?," ;       
         strValue = strValue.substring( 0 ,strValue.length()- 1 ); 
 
         String sql =  "insert into "  + hbmInfo.get( "tableName" ) + "("  + strColumn +  ")"  " values ("  + strValue +  ")" ;  
         return  sql; 
    
     
}


(3)测试持久化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public  class  Test {
 
     /**
      * 测试持久化
      * 数据库语句:
      * DROP TABLE IF EXISTS `tb_student`; 
      * CREATE TABLE tb_student (
      * `id` int(10) NOT NULL DEFAULT 0 ,
      * `name` varchar(50) DEFAULT NULL ,
      * `score` int(11) DEFAULT 0 ,
      * PRIMARY KEY (`id`)
      * )ENGINE=MyISAM  DEFAULT CHARSET=utf8;
      */
     public  void  main(){
         Student student= new  Student();
         student.setId( 100 );
         student.setName( "Tom" );
         student.setScore( "99" );
         //获得Session对象
         Session session= new  Session();
         //执行持久化操作
         session.save(student);
     }
     
}

  


目录
相关文章
|
5月前
|
缓存 Java 数据库连接
Hibernate或MyBatis:ORM映射、缓存机制等知识讲解梳理
Hibernate或MyBatis:ORM映射、缓存机制等知识讲解梳理
48 0
|
SQL XML 缓存
认识 ORM 框架 Hibernate,为什么 2022 年了还在谈论它?
前言 Hibernate 作为一种全自动 ORM 框架,在几年前常与 Spring、Struts2 一起使用,并称 SSH,作为主流的企业级应用框架。伴随着 MyBatis 的诞生,以及 Hibernate 本身的一些缺陷,如今 Hibernate 已经慢慢淡出了大家的视野。
434 0
认识 ORM 框架 Hibernate,为什么 2022 年了还在谈论它?
|
SQL 关系型数据库 程序员
什么是ORM?为什么要使用ORM?底层原理是什么?
什么是ORM?为什么要使用ORM?底层原理是什么?
735 0
|
SQL 安全 数据库
ORM映射框架总结--代码生成器
年前发布了一些文章,是关于.NET数据操作(点击查看)的。刚开始学习编程的时候,总感觉Java中的Hibernate 功能好强大,现在也不可否认它的确强大,特别是它在数据关系处理上,却是那样的让人称叹。
1238 0
|
XML SQL Java
Hibernate-ORM:14.Hibernate中的命名查询
      ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------         本篇博客讲述命名查询,所谓命名查询是什么呢? Hibernate中允许我们在xml,实体类,甚至注解的方式来编写查询语句,本篇博客将讲述xml中的方式 一,准备好准备工作,我由于上篇博客把大量的准备都做好,所以,本篇从简 二,预览hbm.
1030 0
|
Java 关系型数据库 MySQL
Hibernate-ORM:10.Hibernate中的分页
  ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------       本篇博客讲述Hibernate中的分页 hibernate中的分页其实很好写,它通过操作对象的方式,来进行分页查询操作 分页无非就是查俩个:1.
942 0
|
缓存 Java 数据库连接
Hibernate-ORM:06.Hibernate中三种状态
  ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------       本篇博客主要叙述Hibernate中的三种状态:临时状态(瞬时状态),持久状态,游离状态 commit和flush三种状态间的使用,commit和flush的区别: save...
1097 0
|
Java 关系型数据库 程序员
Hibernate-ORM:13.Hibernate中的连接查询
    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------     本篇博客将会解释Hibernate中的连接查询(各种join) 一,目录   1.
908 0
|
Java 关系型数据库 数据库连接
Hibernate-ORM:11.Hibernate中的关联查询
      ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------         本篇博客将讲述Hibernate中的关联查询,及其级联(cascade)操作,以及指定哪一方维护关联关系的(inverse)   一,讲述目录如下:   1.
1198 0
|
SQL Java 数据库连接
Hibernate-ORM:07.Hibernate中的参数绑定
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------     本篇博客会讲解Hibernate中的参数绑定,就是相当于sql语句中的where后面的条件   一,讲解概述:   1.
1041 0