本文来自【优锐课】——抽丝剥茧,细说架构那些事。
ORM(对象关系映射)是用于数据库编程的出色工具。只需一点经验和Java注释的强大功能,我们就可以相对轻松地构建复杂的数据库系统并利用生产力。关系数据库是大多数商业应用程序的主体。关系模型和面向对象的模型之间的不匹配总是很难映射。ORM工具以一种可以将对象映射到数据库中的方式为我们提供了帮助,就好像我们不再使用关系模型的记录而是使用面向对象模型中的对象一样。这改变了JDBC编程的整个范例。
它在哪里适合JDBC
在使用Java编写普通的JDBC代码时,你将同意它确实笨拙而费力,几乎每次我们向数据库发出CRUD请求时,一遍又一遍地编写相同的代码。现在,想象一下如果我们可以编写如下内容,世界将会如何:
1 MyPojo hmm=new MyPojo(); 2 MagicWand wave=MagicWand.getInstance(); 3 wave.save(hmm);
并保留没有常规样板代码的POJO,而在我们与JDBC中的数据库交互时,我们不可避免地需要用某种方式来编写。你怎么看?可能?好吧,是的。魔术棒是Java中的ORM(对象关系映射)工具。市场上有很多可用的ORM工具。Hibernate是其中之一,并且非常有效且可靠。在本文中,我们将其作为实例引用示例代码。
JDBC方式
JDBC需要大量的代码来管理连接并维护各种规则,以确保我们的应用程序不会泄漏任何资源。 查看以下相对较大的JDBC代码,以获取员工记录的列表。
1 public List<Employee> getEmployees() { 2 List<Employee> list = new ArrayList<>(); 3 Connection con = null; 4 PreparedStatement pstmt = null; 5 try { 6 Class.forName("com.mysql.jdbc.Driver"); 7 con = DriverManager.getConnection("jdbc:mysql://localhost/minilibrary", "user1", "secret"); 8 pstmt = con.prepareStatement("SELECT * FROM emp ORDER BY empId"); 9 ResultSet rs = pstmt.executeQuery(); 10 while (rs.next()) { 11 Employee emp = new Employee(); 12 emp.setEmpId(rs.getInt(1)); 13 emp.setName(rs.getString(2)); 14 emp.setPhone(rs.getString(3)); 15 emp.setEmail(rs.getString(4)); 16 emp.setSalary(rs.getFloat(5)); 17 emp.setDesignation(rs.getString(6)); 18 list.add(emp); 19 } 20 } catch (SQLException | ClassNotFoundException ex) { 21 Logger.getLogger(EmployeeBean.class.getName()).log(Level.SEVERE, "Could not acquire record", ex); 22 throw new EmployeeException("Failed to retrieve employee from the database"); 23 } finally { 24 try { 25 if (pstmt != null) { 26 pstmt.close(); 27 } 28 if (con != null) { 29 con.close(); 30 } 31 } catch (SQLException ex) { 32 Logger.getLogger(EmployeeBean.class.getName()).log(Level.SEVERE, null, ex); 33 } 34 } 35 return list; 36 }
尽管有各种各样的技术可以将其缩小到相当合适的大小,尤其是用于打开连接和记录问题的样板部分,但是从ResultSet中提取对象实例的主要逻辑仍然是相同的。当对象包含对其他对象或对象集合的引用时,情况就更糟了。
输入ORM
Hibernate减轻了JDBC编程的许多麻烦,并以更合理的方式解决了这个问题,或者我们应该说面向对象的方式。我们可以从选择的表列中创建一个POJO,并将其保存在数据库中。Hibernate直接支持类之间的继承和其他面向对象的关系。我们可以使用这些关系机制在关系数据库级别建立一对一,一对多,多对多映射。在Java注释@Entity的帮助下,创建实体很简单。@Id表示empId是数据库的主键。
1 @Entity 2 public class Employee { 3 @Id 4 private int empId; 5 private String empName; 6 ... 7 }
hibenate的关键在于配置设置,可以在通常称为hibernate.cfg.xml的XML文件中完成配置。也可以通过Java代码设置此配置设置,如下所示。
1 public class HibernateUtil { 2 3 private static final SessionFactory sessionFactory; 4 private static final ServiceRegistry serviceRegistry; 5 static { 6 try { 7 Configuration config = getConfiguration(); 8 serviceRegistry = new ServiceRegistryBuilder().applySettings( 9 config.getProperties()).buildServiceRegistry(); 10 config.setSessionFactoryObserver(new SessionFactoryObserver() { 11 private static final long serialVersionUID = 1L; 12 13 14 15 @Override 16 public void sessionFactoryCreated(SessionFactory factory) { 17 } 18 19 20 21 @Override 22 public void sessionFactoryClosed(SessionFactory factory) { 23 ServiceRegistryBuilder.destroy(serviceRegistry); 24 } 25 }); 26 sessionFactory = config.buildSessionFactory(serviceRegistry); 27 } catch (Throwable ex) { 28 System.err.println("Initial SessionFactory creation failed." + ex); 29 throw new ExceptionInInitializerError(ex); 30 } 31 } 32 public static Session openSession() { 33 return sessionFactory.openSession(); 34 } 35 36 37 38 private static Configuration getConfiguration() { 39 Configuration cfg = new Configuration(); 40 cfg.addAnnotatedClass(Employee.class ); 41 cfg.setProperty("hibernate.connection.driver_class","com.mysql.jdbc.Driver"); 42 cfg.setProperty("hibernate.connection.url","jdbc:mysql://localhost/hr"); 43 cfg.setProperty("hibernate.connection.username", "user1"); 44 cfg.setProperty("hibernate.connection.password", "secret"); 45 cfg.setProperty("hibernate.show_sql", "true"); 46 cfg.setProperty("hibernate.dialect","org.hibernate.dialect.MySQLSQLDialect"); 47 cfg.setProperty("hibernate.hbm2ddl.auto", "update"); 48 cfg.setProperty("hibernate.cache.provider_class","org.hibernate.cache.NoCacheProvider"); 49 cfg.setProperty("hibernate.current_session_context_class", "thread"); 50 return cfg; 51 } 52 }
设置好配置属性后,我们就可以开始了。现在让我们重写getEmployees函数的JDBC版本以获取雇员列表。
1 public List<Employee> getEmployees(){ 2 Session s=HibernateUtil.openSession(); 3 s.beginTransaction(); 4 List<Employee> list=s.createQuery("FROM Employee").list(); 5 s.getTransaction().commit(); 6 s.close(); 7 return list; 8 }
并不是那么简单,清晰,并说明了为什么任何JDBC程序员都在数据库编程中使用Hibernate或任何其他ORM工具。
如果ORM是解决方案,那么JDBC是一个问题吗?
不,不,JDBC完全可以。实际上,在某些情况下(例如常见的CRUD操作),某种类型的对象关系映射是适当的,而通过JDBC连接API进行直接访问的传统方法占据了上风。ORM为程序员提供了一层便利。这种便利是否会带来性能代价。嗯,有很多传闻证明了这种缺点(尽管我尚未测试),但是我相信使用ORM工具的缺点远大于缺点。他们之间没有战争。一个可以弥补另一个缺点。从较高的角度来看,我们可以说– JDBC API在数据库编程中可以独立运行,而ORM工具则不能。即使我们在代码中显然不使用JDBC API,ORM也会始终使用下面的JDBC API。因此,以某种方式问我们应该选择哪个是一个荒谬的问题?ORM位于你的应用程序和JDBC之间,从而提供了编程的面向对象模型和关系数据库模型之间缺少的链接。实际上,这个所谓的ORM与JDBC交互以最终与数据库对话。下图可能会进一步阐明该概念。
图1:休眠在Java应用程序中的作用
结论
可以从Java应用程序直接调用Hibernate,也可以通过另一个框架访问它。无论是Swing应用程序,Servlet,JSP页面还是有权访问数据库的任何其他Java应用程序,我们通常都使用它来为应用程序创建数据访问层或替换现有的数据访问层。其他的ORM工具(例如MyBatis)通过不同的API和访问机制执行类似的功能。总体而言,ORM尤其是Hibernate比此高级概述更强大,更深入。也许本文提供了第一手的见解,并引起了你的兴趣,以探索兔子洞的深度。
感谢阅读!最后奉上近期整理出来的一套完整的java架构思维导图,分享给大家对照知识点参考学习。