接下來咱們開始介紹Hibernate的數據類型,由於咱們如今暫時只關注Hibernate這塊,所以咱們此次只創建一個Java Project,命名爲hibernate2。java
加入hibernate JAR包:mysql
選擇hibernate2項目,點擊MyEclipse->Add Hibernate Capabilities, Hibernate Specification與風中頁老師的相同,爲Hibernate3.2,點擊next,繼續next,去掉Specify database connection details前面的√接着next,去掉Create SessionFactory class?前面的√點擊Finish。sql
把上一個hibernate項目的hibernate.cfg.xml文件拷貝過來,覆蓋掉當前src下面的hibernate.cfg.xml文件,修改mapping信息:數據庫
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <!-- Generated by MyEclipse Hibernate Tools. --> <hibernate-configuration> <session-factory> <property name="show_sql">true</property> <!-- 屬性之間沒有上下關係,放在哪裏都行 --> <property name="connection.url">jdbc:mysql://localhost:3306/myhibernate2</property> <property name="connection.username">root</property> <property name="connection.password">root</property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <mapping resource="Customers.hbm.xml"/> <!-- 將主配置文件包含對象-關係映射文件,之因此映射是由於hibernate啓動時只會加載主配置文件 --> </session-factory> </hibernate-configuration>
添加MySql驅動,從hibernate項目拷貝mysql-connector-java-5.1.34-bin.jar到hibernate根目錄下。session
建立表:(bigint即long類型;bit即boolean類型;timestamp也是一個日期類型的,比date精度更高,能夠精確到毫秒;blob即二進制大型物件)app
mysql> create table CUSTOMERS( -> ID bigint not null primary key, -> NAME varchar(15) not null, -> EMAIL varchar(128) not null, -> PASSWORD varchar(8) not null, -> PHONE int, -> ADDRESS varchar(255), -> SEX char(1), -> IS_MARRIED bit, -> DESCRIPTION text, -> IMAGE blob, -> BIRTHDAY date, -> REGISTERED_TIME timestamp -> );
新建com.test.bean包,在該包下面新建一個類Customer.java:函數
package com.test.bean; import java.sql.Date; import java.sql.Timestamp; public class Customer { private Long id; private String name; private String email; private String password; private int phone; // or Integer private String address; private char sex; private boolean married; private String description; private byte[] image; private Date birthday; private Timestamp registeredTime; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getPhone() { return phone; } public void setPhone(int phone) { this.phone = phone; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public char getSex() { return sex; } public void setSex(char sex) { this.sex = sex; } public boolean isMarried() { return married; } public void setMarried(boolean married) { this.married = married; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public byte[] getImage() { return image; } public void setImage(byte[] image) { this.image = image; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public Timestamp getRegisteredTime() { return registeredTime; } public void setRegisteredTime(Timestamp registeredTime) { this.registeredTime = registeredTime; } }
在src下面新建一個Customers.hbm.xml:測試
<?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> <class name="com.test.bean.Customer" table="customers"> <!-- 將類與表相關聯,使得類中的屬性和表中的字段關聯起來 --> <id name="id" column="id" type="long"> <!-- 類中id屬性和映射到表中的id字段,類型爲int/integer皆可 --> <generator class="increment"> <!-- 主鍵id的生成方式爲自增 --> </generator> </id> <property name="name" column="name" type="string" not-null="true"></property> <!-- 若是不寫字段名,則默認與類中的屬性名相同 ;hibernate層和數據庫層均可以對非空進行檢查--> <property name="email" column="email" type="string" not-null="true"></property> <property name="password" column="password" type="string" not-null="true"></property> <property name="phone" column="phone" type="int"></property> <property name="address" column="address" type="string" ></property> <property name="sex" column="sex" type="character" ></property> <property name="married" column="is_married" type="boolean" ></property> <property name="description" column="description" type="text"></property> <property name="image" column="image" type="binary" ></property> <property name="birthday" column="birthday" type="date" ></property> <property name="registeredTime" column="registered_time" type="timestamp"></property> </class> </hibernate-mapping>
在com.test.bean包下面,建立測試類HibernateTest.java同時放置一個photo.gif文件:fetch
package com.test.bean; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.sql.Date; import java.util.Iterator; import java.util.List; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; public class HibernateTest { public static SessionFactory sessionFactory; static { try { Configuration config = new Configuration().configure(); sessionFactory = config.buildSessionFactory(); } catch (Exception e) { e.printStackTrace(); } } public void findAllCustomers(PrintStream out) throws Exception { // Ask for a session using the JDBC information we've configured Session session = sessionFactory.openSession(); Transaction tx = null; try { tx = session.beginTransaction(); List customers = session.createQuery("from Customer as c order by c.name asc").list(); for (Iterator it = customers.iterator(); it.hasNext();) { printCustomer(out, (Customer) it.next()); } // We're done; make our changes permanent tx.commit(); } catch (Exception e) { if (tx != null) { // Something went wrong; discard all partial changes tx.rollback(); } throw e; } finally { // No matter what, close the session session.close(); } } public static void saveCustomer(Customer customer) throws Exception { // Ask for a session using the JDBC information we've configured Session session = sessionFactory.openSession(); Transaction tx = null; try { tx = session.beginTransaction(); session.save(customer); // We're done; make our changes permanent tx.commit(); } catch (Exception e) { if (tx != null) { // Something went wrong; discard all partial changes tx.rollback(); } throw e; } finally { // No matter what, close the session session.close(); } } public void loadAndUpdateCustomer(Long customer_id, String address) throws Exception { // Ask for a session using the JDBC information we've configured Session session = sessionFactory.openSession(); Transaction tx = null; try { tx = session.beginTransaction(); Customer c = (Customer) session.load(Customer.class, customer_id); c.setAddress(address); // We're done; make our changes permanent tx.commit(); } catch (Exception e) { if (tx != null) { // Something went wrong; discard all partial changes tx.rollback(); } throw e; } finally { // No matter what, close the session session.close(); } } public void deleteAllCustomers() throws Exception { // Ask for a session using the JDBC information we've configured Session session = sessionFactory.openSession(); Transaction tx = null; try { tx = session.beginTransaction(); Query query = session.createQuery("from Customer"); List list = query.list(); for (Iterator i = list.iterator(); i.hasNext();) { session.delete((Customer) i.next()); } tx.commit(); } catch (Exception e) { if (tx != null) { // Something went wrong; discard all partial changes tx.rollback(); } throw e; } finally { // No matter what, close the session session.close(); } } private void printCustomer(PrintStream out, Customer customer) throws Exception { byte[] buffer = customer.getImage(); OutputStream fout = new FileOutputStream("photo_copy.gif"); fout.write(buffer); fout.close(); out.println("------如下是" + customer.getName() + "的我的信息------"); out.println("ID: " + customer.getId()); out.println("口令: " + customer.getPassword()); out.println("E-Mail: " + customer.getEmail()); out.println("電話: " + customer.getPhone()); out.println("地址: " + customer.getAddress()); String sex = customer.getSex() == 'M' ? "男" : "女"; out.println("性別: " + sex); String marriedStatus = customer.isMarried() ? "已婚" : "未婚"; out.println("婚姻情況: " + marriedStatus); out.println("生日: " + customer.getBirthday()); out.println("註冊時間: " + customer.getRegisteredTime()); out.println("自我介紹: " + customer.getDescription()); } public void test(PrintStream out) throws Exception { Customer customer = new Customer(); customer.setName("zhangsan"); customer.setEmail("zhangsan@yahoo.com"); customer.setPassword("1234"); customer.setPhone(1381234); customer.setAddress("Shanghai"); customer.setSex('M'); customer.setDescription("I am very honest."); InputStream in = this.getClass().getResourceAsStream("photo.gif"); byte[] buffer = new byte[in.available()]; in.read(buffer); customer.setImage(buffer); customer.setBirthday(Date.valueOf("1980-05-06")); saveCustomer(customer); findAllCustomers(out); loadAndUpdateCustomer(customer.getId(), "Tianjin"); findAllCustomers(out); deleteAllCustomers(); } public static void main(String args[]) throws Exception { new HibernateTest().test(System.out); sessionFactory.close(); } }
經過給一下幾行代碼添加註釋的方式進行測試:ui
saveCustomer(customer); findAllCustomers(out); loadAndUpdateCustomer(customer.getId(), "Tianjin"); findAllCustomers(out); deleteAllCustomers();
運行後在hibernate2根目錄下面會生成一個photo_copy.gif圖形文件。
上面的例子比較簡單,下面咱們看一個複雜的:表與表之間存在關聯關係,類與類之間存在關聯關係:
新建一個名爲hibernate3的Java Project,導入相應的hibernate包(操做過程如以前所述)。
配置hibernate.cfg.xml:
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <!-- Generated by MyEclipse Hibernate Tools. --> <hibernate-configuration> <session-factory> <property name="show_sql">true</property> <!-- 屬性之間沒有上下關係,放在哪裏都行 --> <property name="connection.url">jdbc:mysql://localhost:3306/myhibernate3</property> <property name="connection.username">root</property> <property name="connection.password">root</property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <mapping resource="Customer.hbm.xml"/> <!-- 將主配置文件包含對象-關係映射文件,之因此映射是由於hibernate啓動時只會加載主配置文件 --> <mapping resource="Order.hbm.xml"/> </session-factory> </hibernate-configuration>
接下來建立兩個域模型,一個是Customer,一個是Order:
src下面新建包com.test,在該包下面新建類:Customer.java:
package com.test; import java.util.Set; public class Customer { private Long id; private String name; private Set orders; // 一對多,經過該變量能夠引用到對應的Order集合對象 public Customer(String name, Set orders) { this.name = name; this.orders = orders; } // hibernate通常要求咱們提供一個不帶參數的構造方法,爲了符合hibernate要求,所以: public Customer() { } public Customer(Set orders) { this.orders = orders; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set getOrders() { return orders; } public void setOrders(Set orders) { this.orders = orders; } }
接着新建與Customer成多對一關係的Order.java類:
package com.test; public class Order { private Long id; private String orderNumber; private Customer customer; // 多對一,經過該變量能夠引用到對應的Customer public Order(String orderNumber, Customer customer) { this.orderNumber = orderNumber; this.customer = customer; } public Order() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getOrderNumber() { return orderNumber; } public void setOrderNumber(String orderNumber) { this.orderNumber = orderNumber; } public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } }
下面,在數據模型,寫配置文件,在這以前須要創建兩張表:
數據庫Schema:
create table customers( ID bigint not null, NAME varchar(15), primary key(ID) ); create table orders( ID bigint not null, ORDER_NUMBER varchar(15), CUSTOMER_ID bigint not null, primary key(ID) ); alter table orders add index IDX_CUSTOMER_ID(CUSTOMER_ID), add constraint FK_CUSTOMER_ID foreign key (CUSTOMER_ID) references customers(ID);
接下來在src下建立Customer.hbm.xml:
<?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> <class name="com.test.Customer" table="customers"> <!-- 將類與表相關聯,使得類中的屬性和表中的字段關聯起來 --> <id name="id" column="id" type="long"> <!-- 類中id屬性和映射到表中的id字段,類型爲int/integer皆可 --> <generator class="increment"> <!-- 主鍵id的生成方式爲自增 --> </generator> </id> <property name="name" type="string"> <column name="name" length="15"></column> <!-- 第二種定義column的方式,能夠進行精細化配置 --> </property> <set name="orders" cascade="save-update" inverse="true"> <!-- 反轉屬性爲true,表示關聯關係由多的一方維持,這是hibernate的一個最佳實踐。 --> <key column="customer_id"></key> <!-- key元素設定與所關聯的持久化類對應的表的外鍵 --> <one-to-many class="com.test.Order"/> </set> </class> </hibernate-mapping>
繼續在src下建立Order.hbm.xml:
<?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> <class name="com.test.Order" table="orders"> <id name="id" column="id" type="long"> <generator class="increment"> </generator> </id> <property name="orderNumber" type="string"> <column name="order_number" length="15"></column> </property> <many-to-one name="customer" column="customer_id" class="com.test.Customer"> </many-to-one> </class> </hibernate-mapping>
最後,不要忘記引入mysql的驅動:mysql-connector-java-5.1.34-bin.jar
而後,爲了驗證咱們的配置是否正確且如願生效,咱們編寫一個測試類,在com.test包下面新建一個類Test.java:
package com.test; import java.util.HashSet; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; public class Test { public static SessionFactory sessionFactory; static { try { sessionFactory = new Configuration().configure(). buildSessionFactory(); } catch(Exception ex) { System.out.println("exeception occured"); ex.printStackTrace(); } } public static void saveCustomerAndOrderWithCascade() throws Exception { Session session = sessionFactory.openSession(); Transaction tx = null; try { tx = session.beginTransaction(); Customer customer = new Customer("zhangsan", new HashSet()); Order order = new Order(); order.setOrderNumber("zhangsan_order1"); Order order2 = new Order(); order2.setOrderNumber("zhangsan_order2"); Order order3 = new Order(); order3.setOrderNumber("zhangsan_order3"); order.setCustomer(customer); // 將一的一方關聯到多的一方 order2.setCustomer(customer); order3.setCustomer(customer); customer.getOrders().add(order); // 將多的一方增長到一的一方 customer.getOrders().add(order2); customer.getOrders().add(order3); session.save(customer); tx.commit(); } catch(Exception ex) { if(null != tx) tx.rollback(); ex.printStackTrace(); } finally { if(null != session) session.close(); } } public static void main(String[] args) throws Exception { saveCustomerAndOrderWithCascade(); } }
執行結果:Console輸出:
Hibernate: select max(id) from customers Hibernate: select max(id) from orders Hibernate: insert into customers (name, id) values (?, ?) Hibernate: insert into orders (order_number, customer_id, id) values (?, ?, ?) Hibernate: insert into orders (order_number, customer_id, id) values (?, ?, ?) Hibernate: insert into orders (order_number, customer_id, id) values (?, ?, ?)
進入數據庫中查看,咱們發現orders表中的外鍵已經關聯到customers表中的主鍵上了。
補充圖例:
下面,繼續進行探索,對於樹模型的關係——找到一個節點,能找到它的多個子節點(或者沒有)和惟一(或者沒有)的父節點,如:
首先創建域模型:在hibernate3項目下的com.test包下創建類:Category.java:
package com.test; import java.util.Set; public class Category { private Long id; private String name; private Category parentCategory; private Set childCategories; public Category(String name, Category parentCategory, Set childCategories) { this.name = name; this.parentCategory = parentCategory; this.childCategories = childCategories; } public Category() { } public Category(Set childCategories) { this.childCategories = childCategories; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Category getParentCategory() { return parentCategory; } public void setParentCategory(Category parentCategory) { this.parentCategory = parentCategory; } public Set getChildCategories() { return childCategories; } public void setChildCategories(Set childCategories) { this.childCategories = childCategories; } }
創建表,數據庫Schema:
create table categories( ID bigint not null, NAME varchar(15), CATEGORY_ID bigint, primary key(ID) ); alter table categories add index IDX_CATEGORY_ID(CATEGORY_ID), add constraint FK_CATEGORY_ID foreign key(CATEGORY_ID) references categories(ID);
創建Category.hbm.xml文件:
<?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> <class name="com.test.Category" table="categories"> <!-- 將類與表相關聯,使得類中的屬性和表中的字段關聯起來 --> <id name="id" column="id" type="long"> <!-- 類中id屬性和映射到表中的id字段,類型爲int/integer皆可 --> <generator class="increment"> <!-- 主鍵id的生成方式爲自增 --> </generator> </id> <property name="name" type="string"> <column name="name" length="15"></column> <!-- 第二種定義column的方式,能夠進行精細化配置 --> </property> <!-- 反轉屬性爲true,表示關聯關係由多的一方維持,這是hibernate的一個最佳實踐。 --> <set name="childCategories" cascade="all" inverse="true"> <!-- cascade="all"表示保存、更新或刪除當前對象時級聯其餘關聯的對象 --> <key column="category_id"></key> <!-- key元素設定與所關聯的持久化類對應的表的外鍵 --> <one-to-many class="com.test.Category"/> </set> <many-to-one name="parentCategory" column="category_id" class="com.test.Category"> </many-to-one> </class> </hibernate-mapping>
接下來,在Test.java中增長方法——saveCategoryWithCascade和deleteCategoryWithCascade:
package com.test; import java.util.HashSet; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; public class Test { public static SessionFactory sessionFactory; static { try { sessionFactory = new Configuration().configure(). buildSessionFactory(); } catch(Exception ex) { System.out.println("exeception occured"); ex.printStackTrace(); } } public static void saveCustomerAndOrderWithCascade() throws Exception { Session session = sessionFactory.openSession(); Transaction tx = null; try { tx = session.beginTransaction(); Customer customer = new Customer("zhangsan", new HashSet()); Order order = new Order(); order.setOrderNumber("zhangsan_order1"); Order order2 = new Order(); order2.setOrderNumber("zhangsan_order2"); Order order3 = new Order(); order3.setOrderNumber("zhangsan_order3"); order.setCustomer(customer); // 將一的一方關聯到多的一方 order2.setCustomer(customer); order3.setCustomer(customer); customer.getOrders().add(order); // 將多的一方增長到一的一方 customer.getOrders().add(order2); customer.getOrders().add(order3); session.save(customer); tx.commit(); } catch(Exception ex) { if(null != tx) tx.rollback(); ex.printStackTrace(); } finally { if(null != session) session.close(); } } @SuppressWarnings("unchecked") public static void saveCategoryWithCascade() throws Exception { Session session = sessionFactory.openSession(); Transaction tx = null; try { tx = session.beginTransaction(); // 根據圖例,建立食品類別、蔬菜類別、水果類別、西紅柿類別、蘋果類別、桔子類別。 Category foodCategory = new Category("food", null, new HashSet()); Category fruitCategory = new Category("fruit", null, new HashSet()); Category vegetableCategory = new Category("vegetable", null, new HashSet()); Category appleCategory = new Category("apple", null, new HashSet()); Category orangeCategory = new Category("orange", null, new HashSet()); Category tomatoCategory = new Category("tomato", null, new HashSet()); foodCategory.getChildCategories().add(fruitCategory); fruitCategory.setParentCategory(foodCategory); foodCategory.getChildCategories().add(vegetableCategory); vegetableCategory.setParentCategory(foodCategory); fruitCategory.getChildCategories().add(appleCategory); appleCategory.setParentCategory(fruitCategory); fruitCategory.getChildCategories().add(orangeCategory); orangeCategory.setParentCategory(fruitCategory); vegetableCategory.getChildCategories().add(tomatoCategory); tomatoCategory.setParentCategory(vegetableCategory); session.save(foodCategory); // 級聯保存全部的關聯對象 tx.commit(); } catch(Exception ex) { if(null != tx) tx.rollback(); ex.printStackTrace(); } finally { if(null != session) session.close(); } } public static void deleteCategoryWithCascade() throws Exception { Session session = sessionFactory.openSession(); Transaction tx = null; try { tx = session.beginTransaction(); // session.get和session.load方法完成的功能是同樣的,接受參數類型也是同樣的,它們之間的惟一差異在於根據主鍵尋找某一個對象 // 若是找不到,get方法返回一個null,而load方法直接拋異常。 Category category = (Category)session.load(Category.class, new Long(1)); session.delete(category); // 級聯保存全部的關聯對象 tx.commit(); } catch(Exception ex) { if(null != tx) tx.rollback(); ex.printStackTrace(); } finally { if(null != session) session.close(); } } public static void main(String[] args) throws Exception { // saveCustomerAndOrderWithCascade(); // saveCategoryWithCascade(); deleteCategoryWithCascade(); } }
最後在主配置文件hibernate.cfg.xml中增長對Category.hbm.xml文件的映射:
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <!-- Generated by MyEclipse Hibernate Tools. --> <hibernate-configuration> <session-factory> <property name="show_sql">true</property> <!-- 屬性之間沒有上下關係,放在哪裏都行 --> <property name="connection.url">jdbc:mysql://localhost:3306/myhibernate3</property> <property name="connection.username">root</property> <property name="connection.password">root</property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <mapping resource="Customer.hbm.xml"/> <!-- 將主配置文件包含對象-關係映射文件,之因此映射是由於hibernate啓動時只會加載主配置文件 --> <mapping resource="Order.hbm.xml"/> <mapping resource="Category.hbm.xml" /> </session-factory> </hibernate-configuration>
運行Test.java程序,能夠看到保存和刪除都已經實現了級聯操做。
下面咱們來看如何用hibernate表示一對一和多對多關係:
一對一在實際開發中用的也比較多,好比一我的對應一個身份證。這種一對一的關係可使用共用主鍵來表達。首先導入工程hibernate1(風中葉銀行企陪day6)
Student 和 Certificate 類及其相關的映射文件
package model; public class Student { private String id; // 標識id private String cardId; // 學號 private String name; // 學生姓名 private int age; // 歲數 private Certificate cer;// 身分證 private Team team;// 班級 public int getAge() { return age; } public String getName() { return name; } public String getCardId() { return cardId; } private void setId(String id) { this.id = id; } public void setAge(int age) { this.age = age; } public void setName(String stuName) { this.name = stuName; } public void setCardId(String cardId) { this.cardId = cardId; } public String getId() { return id; } public Student() { // 無參的構造函數 } public Certificate getCer() { return cer; } public void setCer(Certificate pass) { this.cer = pass; } /** * @return 返回 team。 */ public Team getTeam() { return team; } /** * @param team * 要設置的 team。 */ public void setTeam(Team team) { this.team = team; } } ---------------------------------------------------------------------------- package model; public class Certificate { private String id; private String describe; private Student stu; /** * @return 返回 stu。 */ public Student getStu() { return stu; } /** * @param stu * 要設置的 stu。 */ public void setStu(Student stu) { this.stu = stu; } /** * @return 返回 describe。 */ public String getDescribe() { return describe; } /** * @param describe * 要設置的 describe。 */ public void setDescribe(String describe) { this.describe = describe; } /** * @return 返回 id。 */ public String getId() { return id; } /** * @param id * 要設置的 id。 */ private void setId(String id) { this.id = id; } } ----------------------------------------------------------------- Student.hbm.xml: <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="model.Student" table="student" lazy="true"><!--把類和數表關聯起來--> <id name="id" unsaved-value="null"><!--id的產生方式是uuid.hex--> <generator class="uuid.hex" /> <!-- 或者寫uuid也能夠 --> </id> <property name="cardId" type="string" /><!--映射號--> <property name="name" type="string" /><!--映射學生名--> <property name="age" type="int" /><!--映射學生歲數--> <one-to-one name="cer" class="model.Certificate" fetch="join" cascade="all" /><!--映射對應的身分證對象--> </class> </hibernate-mapping> ---------------------------------------------------------------------------------------------------------- Certificate.hbm.xml: <?xml version="1.0" encoding="GB2312"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="model.Certificate" table="certificate" lazy="true"> <id name="id"> <generator class="foreign"> <param name="property" >stu</param> <!-- stu是Certificate類的一個成員變量 --> </generator> </id> <!-- describe是數據庫中的一個保留字,不能做爲字段名,所以須要加上``(鍵盤1左邊的) --> <property name="describe" column="`describe`" type="string" /> <one-to-one name="stu" class="model.Student" fetch="select" constrained="true" cascade="none"/> <!-- cascade設置爲none說明身份證丟(刪除操做)了不能說明人沒了:~ --> </class> </hibernate-mapping>
schema:
drop database if exists schoolproject; create database schoolproject; use schoolproject; drop table if exists certificate; CREATE TABLE certificate ( id varchar(100) NOT NULL default '', `describe` varchar(100) default '', PRIMARY KEY (id) ) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci; -- -- Dumping data for table 'certificate' -- INSERT INTO certificate VALUES ('ff80808105416d3b0105416d3eca0001','tomclus'); INSERT INTO certificate VALUES ('ff808081054175b501054175b9190001','tom'); -- -- Table structure for table 'student' -- drop table if exists student; CREATE TABLE student ( id varchar(100) NOT NULL default '', name varchar(20) default '', `cardId` varchar(20) NOT NULL default '', age int(11) default '0', PRIMARY KEY (id) ) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci; -- -- Dumping data for table 'student' -- INSERT INTO student VALUES ('ff80808105416d3b0105416d3eca0001','tomclus','200512345',33); INSERT INTO student VALUES ('ff808081054175b501054175b9190001','tom','11111111',33);
BM.java(business manager)
package BusinessManager; import model.Certificate; import model.Student; import org.hibernate.HibernateException; import persistence.StudentDAO; public class BM { public static void main(String[] args) throws HibernateException { Student stu = new Student(); stu.setName("spark"); stu.setCardId("200211332"); stu.setAge(33); Certificate cer = new Certificate(); cer.setDescribe("spark"); //設定學生與身份證之間的關聯關係 stu.setCer(cer); cer.setStu(stu); StudentDAO.saveObj(stu); } }
下面是與之相關的類BaseDAO、StudentDAO、HibernateUtil:
package persistence; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; /** * @author Administrator * * TODO 要更改今生成的類型註釋的模板,請轉至 窗口 - 首選項 - Java - 代碼樣式 - 代碼模板 */ public class BaseDAO { static Session session = null; static Transaction tx = null; /*------------建立新對象-----------------*/ public static void saveObj(Object o) { try { session = HibernateUtil.currentSession(); // 開啓鏈接 tx = session.beginTransaction(); // 開啓事務 session.save(o); tx.commit(); } catch (HibernateException e) { // 捕捉例外 e.printStackTrace(); tx.rollback(); } finally { if (session != null) HibernateUtil.closeSession(session); } } /*------------刪除對象-----------------*/ public static void delObject(Object o) { try { session = HibernateUtil.currentSession(); // 開啓鏈接 Transaction tx = session.beginTransaction(); // 開啓事務 session.delete(o); tx.commit(); } catch (HibernateException e) { // 捕捉例外 e.printStackTrace(); tx.rollback(); } finally { HibernateUtil.closeSession(session); } } /*------------修改對象-----------------*/ public static void updateObj(Object o) { try { session = HibernateUtil.currentSession(); // 開啓鏈接 Transaction tx = session.beginTransaction(); // 開啓事務 session.update(o); tx.commit(); } catch (HibernateException e) { // 捕捉例外 e.printStackTrace(); tx.rollback(); } finally { HibernateUtil.closeSession(session); } } }
/* * 建立日期 2005-7-2 * * TODO 要更改今生成的文件的模板,請轉至 * 窗口 - 首選項 - Java - 代碼樣式 - 代碼模板 */ package persistence; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.Iterator; import java.util.List; import model.Student; import org.hibernate.FlushMode; import org.hibernate.Hibernate; import org.hibernate.HibernateException; import org.hibernate.Query; import org.hibernate.ScrollableResults; import org.hibernate.Session; import org.hibernate.Transaction; /** * @author Administrator * * TODO 要更改今生成的類型註釋的模板,請轉至 窗口 - 首選項 - Java - 代碼樣式 - 代碼模板 */ public class StudentDAO extends BaseDAO { static Session session = null; static Transaction tx = null; public static void update() { Student stu = null; try { session = HibernateUtil.currentSession(); // 開啓鏈接 tx = session.beginTransaction(); // 開啓事務 Query query = session.getNamedQuery("queryStudent_byAgeAdnName"); query.setInteger("minAge", 25); // 設置「:」號後的minAge變量值 query.setString("likeName", "%clus%");// 設置「:」號後的likeName變量值 List list = query.list(); for (int i = 0; i < list.size(); i++) { stu = (Student) list.get(i); System.out.println(stu.getName()); } tx.commit(); } catch (HibernateException e) { // 捕捉例外 e.printStackTrace(); tx.rollback(); } finally { HibernateUtil.closeSession(session); } } }
package persistence; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtil { private static final SessionFactory sessionFactory; static { try { sessionFactory = new Configuration().configure() .buildSessionFactory(); } catch (HibernateException ex) { throw new RuntimeException("Exception building SessionFactory: " + ex.getMessage(), ex); } } public static Session currentSession() { Session s = sessionFactory.openSession(); return s; } public static void closeSession(Session s) { s.close(); } }
引入MySql驅動,執行BM.java方法,執行一次保存操做後表中存儲的數據有:
mysql> select * from student; +----------------------------------+---------+-----------+-----+ | id | name | cardId | age | +----------------------------------+---------+-----------+-----+ | 40281f815004a9ef015004a9f0860001 | spark | 200211332 | 33 | | ff80808105416d3b0105416d3eca0001 | tomclus | 200512345 | 33 | | ff808081054175b501054175b9190001 | tom | 11111111 | 33 | +----------------------------------+---------+-----------+-----+ 3 rows in set mysql> select * from certificate; +----------------------------------+----------+ | id | describe | +----------------------------------+----------+ | 40281f815004a9ef015004a9f0860001 | spark | | ff80808105416d3b0105416d3eca0001 | tomclus | | ff808081054175b501054175b9190001 | tom | +----------------------------------+----------+ 3 rows in set mysql>
能夠看到一對一的主鍵關聯已經成功實現了。
一對一的第二種實現方式:其實仍是經過外鍵來關聯的(這種實現方式實際上就是退化了的一對多關聯)。重命名當前工做空間下的hibernate2項目,導入風中葉老師的hibernate2(day6),能夠看到Student.java、Certificate.java、Student.hbm.xml都沒用任何變換,惟一變化的是id的生成方式,和刪除了one-to-one標籤增長了many-to-one標籤。
Certificate.hbm.xml:
<?xml version="1.0" encoding="GB2312"?> <!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" > <hibernate-mapping> <class name="model.Certificate" table="certificate" lazy="true"> <id name="id"> <generator class="uuid.hex" /> </id> <property name="describe" column="`describe`" type="string" /> <many-to-one name="stu" class="model.Student" unique="true" <!-- 多對一,而多的一方又是惟一的,暗示着多對一已經退化成了一對一了 --> column="stu_id" <!-- 外鍵 --> /> <!-- 惟一的多對一,實際也就變成一對一關係了 --> </class> </hibernate-mapping>
數據庫schema:
drop database if exists schoolproject; create database schoolproject; use schoolproject; -- -- Table structure for table `certificate` -- DROP TABLE IF EXISTS `certificate`; CREATE TABLE `certificate` ( `id` varchar(100) NOT NULL default '', `describe` varchar(100) default '', `stu_id` varchar(32) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Dumping data for table `certificate` -- /*!40000 ALTER TABLE `certificate` DISABLE KEYS */; LOCK TABLES `certificate` WRITE; INSERT INTO `certificate` VALUES ('5abfa70605c5356f0105c53573360002','tomclus','5abfa70605c5356f0105c535730e0001'); INSERT INTO `certificate` VALUES ('5abfa70605c535a60105c535aa370002','tom','5abfa70605c535a60105c535aa040001'); UNLOCK TABLES; /*!40000 ALTER TABLE `certificate` ENABLE KEYS */; -- -- Table structure for table `student` -- DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `id` varchar(100) NOT NULL default '', `name` varchar(20) default '', `cardId` varchar(20) NOT NULL default '', `age` int(11) default '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Dumping data for table `student` -- /*!40000 ALTER TABLE `student` DISABLE KEYS */; LOCK TABLES `student` WRITE; INSERT INTO `student` VALUES ('5abfa70605c5356f0105c535730e0001','tomclus','200212345',33); INSERT INTO `student` VALUES ('5abfa70605c535a60105c535aa040001','tom','200254321',33); UNLOCK TABLES;
執行BM.java,裏面的代碼跟以前的如出一轍。能夠看到certificate表的stu_id已經和student表的id關聯起來了。
下面咱們來看相對來講最複雜的一種:多對多的映射類型
重命名當前項目下的hibernate3,導入風中葉老師的hibernate3(day6),咱們看一下學生和課程之間的多對多經過hibernate如何實現。
多對多在程序中如何體現:兩個類Student、Course,分別定義兩個集合類型的變量:
package model; import java.util.Set; public class Student { private String id; // 標識id private String cardId; // 學號 private String name; // 學生姓名 private int age; // 歲數 private Set Courses;// 課程 public int getAge() { return age; } public String getName() { return name; } public String getCardId() { return cardId; } private void setId(String id) { this.id = id; } public void setAge(int age) { this.age = age; } public void setName(String stuName) { this.name = stuName; } public void setCardId(String cardId) { this.cardId = cardId; } public String getId() { return id; } public Student() { // 無參的構造函數 } /** * @return 返回 courses。 */ public Set getCourses() { return Courses; } /** * @param courses * 要設置的 courses。 */ public void setCourses(Set courses) { Courses = courses; } }
package model; import java.util.HashSet; import java.util.Set; public class Course { private String id; private String name; private Set Students = new HashSet(); /** * @return 返回 id。 */ public String getId() { return id; } /** * @param id * 要設置的 id。 */ public void setId(String id) { this.id = id; } /** * @return 返回 name。 */ public String getName() { return name; } /** * @param name * 要設置的 name。 */ public void setName(String name) { this.name = name; } /** * @return 返回 students。 */ public Set getStudents() { return Students; } /** * @param students * 要設置的 students。 */ public void setStudents(Set students) { Students = students; } }
而在數據庫中要想體現多對多的關係,就須要使用鏈接表,鏈接表中的內容就是stu_id和course_id。一條這樣的記錄,就表示一個映射:該學生選擇了該課程,該課程被該學生所選。
Student.hbm.xml:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="model.Student" table="student" select-before-update="true"><!--把類和數表關聯起來--> <id name="id" unsaved-value="null"><!--id的產生方式是uuid.hex--> <generator class="uuid.hex" /> </id> <property name="cardId" type="string" /><!--映射號--> <property name="name" type="string" /><!--映射學生名--> <property name="age" type="int" /><!--映射學生歲數--> <!-- 若是不設置inverse爲true的話,會拋出約束違規異常,Duplicate entry。由於inverse的默認值爲false,表示本身維持級聯關係,這樣在執行save操做時,student和course都要維持(向表中插入一條記錄)就會拋異常 --> <!-- cascade絕對不能設爲all或者delete,由於刪除課程不能刪除學生,刪除了一個學生也不該該把這個學生的課程刪除 --> <set name="courses" table="student_course" cascade="none" inverse="true"> <key column="stu_id" /> <!-- 字段stu_id表明中間表student_course中的字段 --> <many-to-many class="model.Course" column="course_id" /> <!-- 字段course_id表明中間表student_course中的字段 --> </set> </class> </hibernate-mapping>
Course.hbm.xml:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="model.Course" table="course" select-before-update="true"><!--把類和數表關聯起來--> <id name="id" unsaved-value="null" ><!--id的產生方式是uuid.hex--> <generator class="uuid.hex" /> </id> <property name="name" type="string" /><!--映射課程名--> <set name="students" table="student_course" cascade="save-update"> <key column="course_id" /> <many-to-many class="model.Student" column="stu_id" /> </set> </class> </hibernate-mapping>
數據庫schema:
drop database if exists schoolproject; create database schoolproject; use schoolproject; -- -- Table structure for table `course` -- DROP TABLE IF EXISTS `course`; CREATE TABLE `course` ( `id` varchar(32) NOT NULL default '', `name` varchar(45) default NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Dumping data for table `course` -- /*!40000 ALTER TABLE `course` DISABLE KEYS */; LOCK TABLES `course` WRITE; INSERT INTO `course` VALUES ('5abfe4c705ca8ee00105ca8ee45d0002','history'); INSERT INTO `course` VALUES ('5abfe4c705ca8f5e0105ca8f62400002','computer'); INSERT INTO `course` VALUES ('5abfe4c705ca8faf0105ca8fb3750002','music'); INSERT INTO `course` VALUES ('5abfe4c705ca901f0105ca9024290002','ecnomic'); INSERT INTO `course` VALUES ('5abfe4c705ca98420105ca98475a0001','politics'); UNLOCK TABLES; /*!40000 ALTER TABLE `course` ENABLE KEYS */; -- -- Table structure for table `student` -- DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `id` varchar(100) NOT NULL default '', `name` varchar(20) default '', `cardId` varchar(20) NOT NULL default '', `age` int(11) default '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Dumping data for table `student` -- /*!40000 ALTER TABLE `student` DISABLE KEYS */; LOCK TABLES `student` WRITE; INSERT INTO `student` VALUES ('5abfe4c705ca8ee00105ca8ee42b0001','tomclus','1',25); INSERT INTO `student` VALUES('5abfe4c705ca8f5e0105ca8f620d0001','tom','2',25); INSERT INTO `student` VALUES('5abfe4c705ca8faf0105ca8fb3390001','spark','3',25); INSERT INTO `student` VALUES('5abfe4c705ca901f0105ca9023f70001','jerry','4',25); UNLOCK TABLES; /*!40000 ALTER TABLE `student` ENABLE KEYS */; -- -- Table structure for table `student_course` -- DROP TABLE IF EXISTS `student_course`; CREATE TABLE `student_course` ( `stu_id` varchar(32) NOT NULL default '', `course_id` varchar(32) NOT NULL default '', PRIMARY KEY (`stu_id`,`course_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Dumping data for table `student_course` -- /*!40000 ALTER TABLE `student_course` DISABLE KEYS */; LOCK TABLES `student_course` WRITE; INSERT INTO `student_course` VALUES ('5abfe4c705ca8ee00105ca8ee42b0001','5abfe4c705ca8ee00105ca8ee45d0002'); INSERT INTO `student_course` VALUES ('5abfe4c705ca8ee00105ca8ee42b0001','5abfe4c705ca8f5e0105ca8f62400002'); INSERT INTO `student_course` VALUES ('5abfe4c705ca8ee00105ca8ee42b0001','5abfe4c705ca8faf0105ca8fb3750002'); INSERT INTO `student_course` VALUES ('5abfe4c705ca8f5e0105ca8f620d0001','5abfe4c705ca8f5e0105ca8f62400002'); INSERT INTO `student_course` VALUES ('5abfe4c705ca8f5e0105ca8f620d0001','5abfe4c705ca901f0105ca9024290002'); INSERT INTO `student_course` VALUES ('5abfe4c705ca8faf0105ca8fb3390001','5abfe4c705ca8f5e0105ca8f62400002'); INSERT INTO `student_course` VALUES ('5abfe4c705ca8faf0105ca8fb3390001','5abfe4c705ca8faf0105ca8fb3750002'); UNLOCK TABLES;
相關類BM.java、StudentDAO.java、BaseDAO、HibernateUtil.java:
package BusinessManager; import org.hibernate.HibernateException; import persistence.StudentDAO; public class BM { public static void main(String[] args) throws HibernateException { StudentDAO.mdfChoice(); } }
/* * 建立日期 2005-7-2 * * TODO 要更改今生成的文件的模板,請轉至 * 窗口 - 首選項 - Java - 代碼樣式 - 代碼模板 */ package persistence; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import model.Course; import model.Student; import org.hibernate.FlushMode; import org.hibernate.Hibernate; import org.hibernate.HibernateException; import org.hibernate.Query; import org.hibernate.ScrollableResults; import org.hibernate.Session; import org.hibernate.Transaction; /** * @author Administrator * * TODO 要更改今生成的類型註釋的模板,請轉至 窗口 - 首選項 - Java - 代碼樣式 - 代碼模板 */ public class StudentDAO extends BaseDAO { static Session session = null; static Transaction tx = null; public static void mdfChoice() { Set set = new HashSet(); Student stu = null; Course course = null; try { session = HibernateUtil.currentSession(); // 開啓鏈接 tx = session.beginTransaction(); // 開啓事務 stu = (Student) session.createQuery( "from Student s where s.name ='tomclus'").uniqueResult(); course = (Course) session.createQuery( "from Course c where c.name='ecnomic'").uniqueResult(); stu.getCourses().add(course); course.getStudents().add(stu); tx.commit(); } catch (HibernateException e) { // 捕捉例外 e.printStackTrace(); tx.rollback(); } finally { HibernateUtil.closeSession(session); } } }
/* * 建立日期 2005-7-2 * * TODO 要更改今生成的文件的模板,請轉至 * 窗口 - 首選項 - Java - 代碼樣式 - 代碼模板 */ package persistence; import model.Student; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; /** * @author Administrator * * TODO 要更改今生成的類型註釋的模板,請轉至 窗口 - 首選項 - Java - 代碼樣式 - 代碼模板 */ public class BaseDAO { static Session session = null; static Transaction tx = null; /*------------建立新對象-----------------*/ public static void createObj(Object o) { try { session = HibernateUtil.currentSession(); // 開啓鏈接 tx = session.beginTransaction(); // 開啓事務 session.save(o); tx.commit(); } catch (HibernateException e) { // 捕捉例外 e.printStackTrace(); tx.rollback(); } finally { if (session != null) HibernateUtil.closeSession(session); } } /*------------刪除對象-----------------*/ public static void delObject(Object o) { try { session = HibernateUtil.currentSession(); // 開啓鏈接 tx = session.beginTransaction(); // 開啓事務 session.delete(o); tx.commit(); } catch (HibernateException e) { // 捕捉例外 e.printStackTrace(); tx.rollback(); } finally { HibernateUtil.closeSession(session); } } /*------------修改對象-----------------*/ public static void mdfObj(Object o) { try { session = HibernateUtil.currentSession(); // 開啓鏈接 tx = session.beginTransaction(); // 開啓事務 session.update(o); tx.commit(); } catch (HibernateException e) { // 捕捉例外 e.printStackTrace(); tx.rollback(); } finally { HibernateUtil.closeSession(session); } } }
package persistence; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtil { private static final SessionFactory sessionFactory; static { try { sessionFactory = new Configuration().configure() .buildSessionFactory(); } catch (HibernateException ex) { throw new RuntimeException("Exception building SessionFactory: " + ex.getMessage(), ex); } } public static Session currentSession() { Session s = sessionFactory.openSession(); return s; } public static void closeSession(Session s) { s.close(); } }
執行BM.java類,學生表和課程表沒有任何變化,惟一變化的是中間表多了一行記錄,用於映射新創建的學生和課程之間的關係。
補充知識點:域對象在持久化層的三種狀態