最近在做远程设计,因为涉及到权限部分,所以看了看决策平台的代码,发现数据库操作都是用 hibernate,很成熟的技术了,但是我们之前的开发中可能用的很少,恰好之后可能会用,因此就炒炒冷饭,分享下这个,顺便理一下决策平台是怎么使用 hibernate 的。
ORM 对于 ORM(Object-Relational Mapping) 对象关系映射,相信大家或多或少都用过 ORM 的框架。
面向对象是从软件工程基本原则(如耦合、聚合、封装)的基础上发展起来的,而关系数据库则是从数学理论发展而来的,两套理论存在显著的区别。为了解决这个不匹配的现象,对象关系映射技术应运而生。
是将面向关系概念转化成面向对象概念的一种思想。
面向对象概念
面向关系概念
类
表
对象
行(记录)
属性
列(字段)
将 关系数据库 中表中的 记录 映射成为 对象 ,以对象的形式展现,可以将对数据库的操作转化为对对象的操作。
可以方便开发人员以面向对象的思想来实现对数据库的操作。
从思想上来说,当然是很方便,同一种面向对象的思想,简单不过弯子。但是从代码上来说,这个方便不方便也是看场景的。简单的demo 当然还是直接写 sql 更快。
java的一些 ORM 框架 Hibernate,MyBatis 等。
稍后我们对这两个框架做一下对比。
Hibernate ORM wikipedia 地址
demo 我们先通过一个 demo 来了解一下 hibernate ORM。
搭环境,可以各种方式,无论是导入 jar包 或者 maven 创建,用 idea 在一个空项目上右键 添加框架 也可以。
创建一个user表,有三个字段,分别是 id,username,password.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 SET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS = 0 ;DROP TABLE IF EXISTS `user `;CREATE TABLE `user ` ( `id` int (11 ) NOT NULL AUTO_INCREMENT, `username` varchar (255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , `password` varchar (255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL , PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic ; SET FOREIGN_KEY_CHECKS = 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 29 30 31 32 33 34 35 36 package xyz.yaohwu.entity;public class User { private String username; private String password; private int id; public User () { } public String getUsername () { return username; } public void setUsername (String username) { this .username = username; } public String getPassword () { return password; } public void setPassword (String password) { this .password = password; } public int getId () { return id; } public void setId (int id) { this .id = id; } }
User 类有三个属性,id,username,password 分别对应 User 表中的三个字段。
创建映射文件User.hbm.xml。完成数据表到实体类的映射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" > <hibernate-mapping package ="xyz.yaohwu.entity" > <class name ="User" table ="user" > <id name ="id" column ="id" > <generator class ="native" > </generator > </id > <property name ="username" column ="username" > </property > <property name ="password" column ="password" > </property > </class > </hibernate-mapping >
指明映射关系。User 类对应 user 表,每种属性各自对应的字段。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd" > <hibernate-configuration > <session-factory > <property name ="connection.url" /> <property name ="connection.driver_class" /> <property name ="hibernate.connection.driver_class" > com.mysql.jdbc.Driver</property > <property name ="hibernate.connection.url" > jdbc:mysql://localhost:3306/hibernate_demo?useSSL=false</property > <property name ="hibernate.connection.username" > yaohwu</property > <property name ="hibernate.connection.password" > ******</property > <property name ="hibernate.dialect" > org.hibernate.dialect.MySQLDialect</property > <mapping resource ="xyz/yaohwu/entity/User.hbm.xml" /> </session-factory > </hibernate-configuration >
一些数据库的基本配置和指明有哪些映射文件。更详细的配置可以参考官方文档
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 package xyz.yaohwu.util;import org.hibernate.HibernateException;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;public final class HibernateUtil { private static final SessionFactory ourSessionFactory; static { try { Configuration configuration = new Configuration (); configuration.configure(); ourSessionFactory = configuration.buildSessionFactory(); } catch (Throwable ex) { throw new ExceptionInInitializerError (ex); } } public static Session getSession () throws HibernateException { return ourSessionFactory.openSession(); } }
1 2 3 4 5 6 7 8 9 10 package xyz.yaohwu.dao;import xyz.yaohwu.entity.User;public interface UserDAO { void save (User user) ; User findUserById (int id) ; }
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 package xyz.yaohwu.dao.impl;import org.hibernate.Session;import org.hibernate.Transaction;import xyz.yaohwu.dao.UserDAO;import xyz.yaohwu.entity.User;import xyz.yaohwu.util.HibernateUtil;public class UserDAOImpl implements UserDAO { @Override public void save (User user) { try (Session session = getSession()) { Transaction ts = session.beginTransaction(); session.save(user); ts.commit(); } } @Override public User findUserById (int id) { try (Session session = getSession()) { return session.get(User.class, id); } } private Session getSession () { return HibernateUtil.getSession(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class Main { public static void main (String[] args) { User user = new User (); user.setUsername("yaohwu" ); user.setPassword("password" ); UserDAO dao = new UserDAOImpl (); dao.save(user); user = dao.findUserById(1 ); if (user != null ) { System.out.println("所查询ID的姓名是: " + user.getUsername()); } System.exit(0 ); } }
这是网上找到的非常简单的 hibernate demo,回顾一下关键的步骤就两点,一个是配置对象关系映射,二是依据配置文件生成Session供调用。
对于配置对象关系映射来说,我们上文中用到的是写配置文件的方式,hibernate 还提供了别的方式,比如使用 Java Persistence API 提供的注解方式。
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 package xyz.yaohwu.entity;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.Table;import javax.persistence.UniqueConstraint;@Entity @Table(name = "book", uniqueConstraints = { @UniqueConstraint(columnNames = { "id", "author" }) }) public class Book { @Id @Column(name = "id", nullable = false) private int id; @Column(name = "author", nullable = false) private String author; public Book () { } public int getId () { return id; } public void setId (int id) { this .id = id; } public String getAuthor () { return author; } public void setAuthor (String author) { this .author = author; } } 补充,即使属性并非基本数据类型,也可以进行配置[@Convert ](https:
相应的配置文件 hibernate.cfg.xml 添加:
1 <mapping class ="xyz.yaohwu.entity.Book" />
同样的,也可以不在 hibernate.cfg.xml 中写对象关系映射,而是更灵活的在创建 session 之前添加:
1 2 3 4 5 6 7 8 9 10 11 12 static { try { Configuration configuration = new Configuration (); configuration.configure(); configuration.addResource("/xyz/yaohwu/entity/User.hbm.xml" ); configuration.addAnnotatedClass(Book.class); ourSessionFactory = configuration.buildSessionFactory(); } catch (Throwable ex) { throw new ExceptionInInitializerError (ex); } }
通过研究 org.hibernate.cfg.Configuration 类的源码,我们可以发现 hibernate 的配置是非常灵活的。hibernate.cfg.xml 中一些数据库的基本配置可以通过各种方式进行配置。
通过这个 demo,我们可以大致了解 hibernate 在这个应用中的架构:
上面就是完整的 demo 展示,我们新的决策平台就是通过这样的方式,完成对于内置数据的增删改查。
处理复杂SQL的逻辑 实际应用场景中肯定不止是一个 findSomeById 这样的查询逻辑,因此我们需要在复杂 SQL 的时候有解决方案。
org.hibernate.Criteria 提供了灵活的 API。
1 2 3 4 5 6 7 8 @Override @SuppressWarnings("unchecked") public List<Book> findBooksWrittenByAuthor (String author) { Criteria criteria = getSession().createCriteria(Book.class); criteria.add(Restrictions.eq("author" , author)); criteria.setMaxResults(10 ); return criteria.list(); }
虽然
This appendix covers the legacy Hibernate org.hibernate.Criteria API, which should be considered deprecated.New development should focus on the JPA javax.persistence.criteria.CriteriaQuery API. Eventually, Hibernate-specific criteria features will be ported as extensions to the JPA javax.persistence.criteria.CriteriaQuery.
但,决策平台还是使用这种方案,进行了封装之后供业务逻辑调用。提供了诸多的方案供调用,具体 API 可以参考文档 。可以实现几乎所有的 sql 查询逻辑,非常的灵活。
结构 鉴于 deprecated,我们这边再看一下 javax.persistence.criteria.CriteriaQuery 的查询方案,我发现一个 EntityManager,他是完全不同的两个架构设计。
EntityManager 是 hibernate 对于 JPA 中接口的实现。
javax.persistence.Persistence 给EntityManagerFactory的创建提供一种静态方法的启动类; javax.persistence.EntityManagerFactory 相当于hibernate的SessionFactory; javax.persistence.EntityManager 相当与hibernate的Session; javax.persistence.Query 相当与hibernate的Query,跟hibernate使用hql一样,同样可以使用对象化的查询语言; javax.persistence.EntityTransaction 相当于hibernate的Transaction;
hibernate ORM 可能未来会更注重对于 JPA 的实现。
通过 JPA API 和 Hibernate API 可以看一下 session 和 entitymanager 两者的关系。
看这里 解释一下 UML 图。 或者 。
和 mybatis 的对比 再研究下 mybatis 之后再出吧。 比较的话,也没有深入研究,都是入门级别的了解,挖个坑,深入理解之后比较一下两者内部实现的不同。
参考 Hibernate_User_Guide