170 likes | 352 Views
Hibernate + Java. תכנות מתקדם 2 89-211 תרגול מספר 6 תש"ע 2009-2010. אליהו חלסצ'י. בתוכניות מורכבות המחזיקות מידע רב, נרצה להשתמש במסד נתונים ולא להתעסק ברמת מבנה הנתונים. נרצה אף להפריד בין שכבת מסד הנתונים לשכבת האפליקציה שעושה בו שימוש. (ויש לכך ארכיטקטורות שונות)
E N D
Hibernate + Java תכנות מתקדם 2 89-211תרגול מספר 6 תש"ע 2009-2010 אליהו חלסצ'י
בתוכניות מורכבות המחזיקות מידע רב, נרצה להשתמש במסד נתונים ולא להתעסק ברמת מבנה הנתונים. נרצה אף להפריד בין שכבת מסד הנתונים לשכבת האפליקציה שעושה בו שימוש. (ויש לכך ארכיטקטורות שונות) נרצה שהקוד שלנו לא ישתנה אם החלטנו להחליף למסד נתונים חדש בעל שפת שאילתות אחרת.למשל בין mysql ל oracle. הקדמה
בעיה יותר חמורה היא שאנו נרצה לעבוד עם אובייקטים כחלק מתוכנית מונחית עצמים – ולא לעבוד עם טבלאות רלציוניות. האם SQL מכיר את המושג ירושה? פולימורפיזם? דרך אחת להתמודדות עם הבעיה תהיה לפתור אותה בעצמנו ע"י שימוש ב java.sql נצטרך לפתוח תקשורת עם שרת ה mysql למשל, לשלוח לו פקודות בשפתו ולהמיר את המידע שהתקבל אל תוך אובייקטים... הקדמה
דוגמא האם שיטה זו עונהעל הצרכים שהגדרנו? הקדמה יצירת תקשורת עם שרת ה mysql Connection connection = null; try { // Load the JDBC driver String driverName = "org.gjt.mm.mysql.Driver"; // MySQL MM JDBC driver Class.forName(driverName); // Create a connection to the database String serverName = "localhost"; String mydatabase = "mydatabase"; String url = "jdbc:mysql://" + serverName + "/" + mydatabase; // a JDBC url String username = "username"; String password = "password"; connection = DriverManager.getConnection(url, username, password); } catch (ClassNotFoundException e) { // Could not find the database driver { catch (SQLException e) { // Could not connect to the database { שליחת פקודת sql וקבלת התוצאות כמחרוזות try { // Create a result set containing all data from my_table Statement stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM my_table"); // Fetch each row from the result set while (rs.next()) { // Get the data from the row using the column index String s = rs.getString(1); // Get the data from the row using the column name s = rs.getString("col_string"); } } catch (SQLException e) {}
למעשה אנו צריכים תשתית. תשתית בעלת ארכיטקטורת ORM. Object / Relational Mapping מתאם אוטומטי בין סכמה רלציונית למחלקה ובין תוכן הטבלה למופע של מחלקה זו. כאן נכנס Hibernate לתמונה. הקדמה
Hibernate: קוד פתוח ספריות ORM ל java צריך רק להגדיר את הקישור למסד הנתונים ואת מיפוי השדות - למשתני מחלקה בקובצי xml וכל העבודה מתבצעת באופן שקוף לנו. אנו עובדים עם אובייקטים שנטענים או נשמרים במסד נתונים. שאילות בשפת HQL שפת שאילתות מונחית עצמים אין צורך לשנות את הקוד שלנו אם השתנה מסד הנתונים הקדמה
נוריד את ה core package מהאתר http://www.hibernate.org/6.html ונפתח את ה zip במקום כלשהו. נפתח פרויקט java חדש בשם HibernateExample הוספת ה jars של Hibernate: נוסיף lib בשם Hibernate מאפייני הפרויקט build path לשונית librariesadd lib...user lib…new… נוסיף jars (באותו החלון add jars) נבחר את ה jars מהמקום בו פתחנו את ה zipוכן מתת-התיקייה lib/required כמו כן צריך לצרף את slf4j-jdk14-1.5.2.jar מתוך http://www.slf4j.org/dist/slf4j-1.5.2.zip עבור הלוג. הקמת סביבת העבודה
תחילה ניצור את מסד הנתונים הבא: כעת ניצור את קובץ הקונפיגורציה ל Hibernate תחת src בשם hibernate.cfg.xml תוכן הקובץ ייקשר את הפרויקט למסד הנתונים שיצרנו mysql תוכנית לדוגמא
כתובת מסד הנתוניםשלנו בשרת ה mysql המחלקה האחראית עלעל ביצוע הקישור – פרטים בצד שם המשתמש סיסמה Auto commit = trueשלא נצטרך לבצע ידנית לאחרכל פעולה, אלא אם נרצה בכך. הפנייה לקובץ המיפוי <?xmlversion='1.0'encoding='utf-8'?> <!DOCTYPEhibernate-configurationPUBLIC"-//Hibernate/Hibernate Configuration DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <propertyname="connection.url"> jdbc:mysql://localhost:3306/myDatabase </property> <propertyname="connection.driver_class"> com.mysql.jdbc.Driver </property> <propertyname="connection.username"> root </property> <propertyname="connection.password"> write here your password </property> <!-- Set AutoCommit to true --> <propertyname="connection.autocommit"> true </property> <!-- SQL Dialect to use. Dialects are database specific --> <propertyname="dialect"> org.hibernate.dialect.MySQLDialect </property> <!-- Mapping files --> <mappingresource="נמלא בשקפים הבאים"/> </session-factory> </hibernate-configuration> עלינו לצרף את ה jarהמכיל את המחלקהשמבצעת את הקישורעבור mysql. ניתן להורדה מ: http://dev.mysql.com/downloads/connector/j/5.1.html פתחו את ה zip במקוםכלשהו וצרפו את ה jar ל build path של הפרויקט.
כעת ניצור מחלקה ב java המתאימה לטבלה: נוסיף getters ו setters מתאימים. טיפ ל eclipse: קליק ימני על המחלקה SourceGenerate getters and setters… תוכנית לדוגמא publicclass User { privatelonguserId = 0 ; private String firstName = ""; private String lastName = ""; privateintage = 0; private String email = ""; }
כעת ניצור את קובץ ה xml האחראי למיפוי השדות, נקרא לו User.hbm.xml ב hibernate.cfg.xml נוסיף את ההפניה לקובץ המיפוי התאמת מחלקה לטבלה השדה id מהווה מפתח ראשי generator – השיטה ליצור מפתח מיפוי שאר השדות תוכנית לדוגמא <?xmlversion="1.0"?> <!DOCTYPEhibernate-mappingPUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <classname="User"table="USERS"> <idname="userId"type="java.lang.Long"column="user_id"> <generatorclass="increment"/> </id> <propertyname="firstName"type="java.lang.String"column="first_name"length="20"/> <propertyname="lastName"type="java.lang.String"column="last_name"length="20"/> <propertyname="age"type="java.lang.Integer"column="age"length="-1"/> <propertyname="email"type="java.lang.String"column="email"length="40"/> </class> </hibernate-mapping> <mappingresource="User.hbm.xml"/>
עד כה יצרנו: טבלה במסד הנתונים שלנו. קובץ xml לקונפיגורציה. מחלקה תואמת לטבלה ב java. קובץ xml למיפוי השדות. כעת נלמד כיצד "לדבר" עםמסד הנתונים שלנו. לשם כך נצטרך לפתוח sessionלקוח מול שרת ה mysql שלנו. המחלקה org.hibernate.Sessionעושה עבורנו את העבודה. המחלקה UserManager תנהל אובייקטים של User במסד הנתונים שלנו באמצעות Session. תוכנית לדוגמא import org.hibernate.Session; publicclass UserManager { private Session session = null; public UserManager(Session session) { if(session == null) thrownew RuntimeException("Invalid session object."); this.session = session; } publicvoid saveUser(User user){ session.save(user); } publicvoid updateUser(User user){ session.update(user); } publicvoid deleteUser(User user) { session.delete(user); } }
כעת נראה קוד ששומר אובייקט user במסד הנתונים שלנו. יצרנו מופע של User יצרנו מופע של SessionFactory שבעזרתו יצרנו מופע של Session יצרנו מופע של UserManager וקראנו ל saveUser הדפסנו את ה ID (=1) התוצאה: mysql תוכנית לדוגמא import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; publicclass Main { publicstaticvoid main(String[] args) { User user = new User(); user.setFirstName("Kermit"); user.setLastName("Frog"); user.setAge(54); user.setEmail("kermit@muppets.com"); SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); Session session = sessionFactory.openSession(); UserManager manager = new UserManager(session); manager.saveUser(user); System.out.println("User saved with ID = "+ user.getUserId()); session.flush(); } }
כעת נראה קוד שיוצר אובייקטים מתוך הרשומות במסד הנתונים. נשתמש במחלקה org.hibernate.Query כדי לכתוב שאילתות ל session נקבל את רשימת התוצאות ונעבור עליה באמצעות iterator תוכנית לדוגמא User user; SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); Session session = sessionFactory.openSession(); Query query = session.createQuery("from User"); List <User>list = query.list(); Iterator<User> it=list.iterator(); while (it.hasNext()){ user=it.next(); System.out.println("id: \t\t"+user.getUserId()); System.out.println("age: \t\t"+user.getAge()); System.out.println("first name: \t"+user.getFirstName()); System.out.println("last name: \t"+user.getLastName()); System.out.println("email: \t\t"+user.getEmail()); } id: 1 age: 54 first name: Kermit last name: Frog email: kermit@muppets.com
Hibernate Query Language שפת שאילתות שדומה בכוונה ל SQL אך אל תתנו לסינטקס להטעות אתכם, היא שפה בעלת תאימות מלאה ל object oriented יכולת הבנה של: ירושה פולימורפיזם קשר אסוציאטיבי HQL User user; SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); Session session = sessionFactory.openSession(); Query query = session.createQuery("from User"); List <User>list = query.list(); Iterator<User> it=list.iterator(); while (it.hasNext()){ user=it.next(); System.out.println("id: \t\t"+user.getUserId()); System.out.println("age: \t\t"+user.getAge()); System.out.println("first name: \t"+user.getFirstName()); System.out.println("last name: \t"+user.getLastName()); System.out.println("email: \t\t"+user.getEmail()); } ניתן להחליף את מסד הנתונים, הקוד שלנו יישאר אותו הדבר...
נראה מספר דוגמאות: "from Cat” : השאילתה הבסיסית למופעים של Cat “select u from User u ordered by u.firstName, u.lastName” : בחירת כל אובייקט מסוג User בצורה ממוינת תחילה לפי firstName ואח"כ לפי lastName. "select cat.weight + sum(kitten.weight) from Cat cat join cat.kittens kitten group by cat.id, cat.weight" : מה הקוד הזה נותן? ניתן לבקר במדריך הבא כדי להכיר את השפה:http://docs.jboss.org/hibernate/stable/core/reference/en/html/queryhql.html HQL
למה להשתמש ב hibernate? למה משמשת המחלקה Session? מהם היתרונות של השימוש ב HQL? היכנסו ל tutorial הבא: (ממנו נלקחו הדוגמאות)http://www.visualbuilder.com/java/hibernate/tutorial/והמשיכו את הדוגמא כדי לראות כיצד מבצעים קשר אסוציאטיבי בין טבלאות שונות. קשר one to many קשר many to many הטמעה