本文來自【優銳課】——抽絲剝繭,細說架構那些事。java
ORM(對象關係映射)是用於數據庫編程的出色工具。只需一點經驗和Java註釋的強大功能,咱們就能夠相對輕鬆地構建複雜的數據庫系統並利用生產力。關係數據庫是大多數商業應用程序的主體。關係模型和麪向對象的模型之間的不匹配老是很難映射。ORM工具以一種能夠將對象映射到數據庫中的方式爲咱們提供了幫助,就好像咱們再也不使用關係模型的記錄而是使用面向對象模型中的對象同樣。這改變了JDBC編程的整個範例。mysql
在使用Java編寫普通的JDBC代碼時,你將贊成它確實笨拙而費力,幾乎每次咱們向數據庫發出CRUD請求時,一遍又一遍地編寫相同的代碼。如今,想象一下若是咱們能夠編寫以下內容,世界將會如何:程序員
1 MyPojo hmm=new MyPojo(); 2 MagicWand wave=MagicWand.getInstance(); 3 wave.save(hmm);
並保留沒有常規樣板代碼的POJO,而在咱們與JDBC中的數據庫交互時,咱們不可避免地須要用某種方式來編寫。你怎麼看?可能?好吧,是的。魔術棒是Java中的ORM(對象關係映射)工具。市場上有不少可用的ORM工具。Hibernate是其中之一,而且很是有效且可靠。在本文中,咱們將其做爲實例引用示例代碼。sql
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中提取對象實例的主要邏輯仍然是相同的。當對象包含對其餘對象或對象集合的引用時,狀況就更糟了。編程
Hibernate減輕了JDBC編程的許多麻煩,並以更合理的方式解決了這個問題,或者咱們應該說面向對象的方式。咱們能夠從選擇的表列中建立一個POJO,並將其保存在數據庫中。Hibernate直接支持類之間的繼承和其餘面向對象的關係。咱們可使用這些關係機制在關係數據庫級別創建一對一,一對多,多對多映射。在Java註釋@Entity的幫助下,建立實體很簡單。@Id表示empId是數據庫的主鍵。session
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版本以獲取僱員列表。app
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工具。框架
不,不,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架構思惟導圖,分享給你們對照知識點參考學習。