? ? ? ? 在EJB 2.x中。EJB有3種類型的Bean。各自是會話Bean(Session Bean)、消息驅動Bean(Message-Driven Bean)和實體Bean(Entity Bean)。
? ? ? ? 隨著EJB 3的推出,EJB2.x中的實體Bean逐漸被JPA規范所替代,JPA不僅能在EJB環境中使用,并且能在Java SE、Java EE環境中使用。相對于EJB 2.x中的實體Bean,它的使用范圍更廣。
? ? ? ? 但這里我們仍然將其稱做實體Bean。
? ? ? ? 與會話Bean和消息驅動Bean類似,新的實體Bean也是一個加了凝視符(@Entity)的簡單Java對象(POJO),實體關系和O/R映射也是通過凝視符來定義的,并提供幾種不同的數據庫操作規范。
? ? ? ? 一旦被EntityManager訪問,它就成為了一個持久化對象。而且成為了持久化上下文的一部分。此時我們就能夠像使用Hibernate、iBATIS、MYBATIS一樣來使用實體對象了。
? ? ? ? 本文主要將具體解說實體Bean的開發技術。
1、建立與數據庫的連接,演示實體Bean的開發與調用過程。
2、實體管理器:運行數據庫更新的方法。
3、生命周期:實體Bean的監聽和回調。
4、關系實體映射:開發實體的方法。
5、JPQL查詢語言:運行數據庫實體查詢。
6、原生SQL查詢:運行原生SQL語句。
? ? ? ? 它們之間的關系如圖所看到的,通過實體管理器操作實體Bean。來實現對數據庫的更新、JPQL查詢和原生SQL查詢。
實體管理器是工具。實體Bean是數據。
以下首先來解說實體Bean的調用過程。然后通過開發第一個實體Bean。演示該配置與開發的過程,包含以下內容:
1、配置數據源。
2、指定數據源。
3、開發第一個實體Bean--Student.java。
4、開發會話Bean進行調用--StudentDAORemote.java和StudentDAO.java。
5、打包并部署到JBossserver。
6、開發client進行測試--StudentDAOClient.java。
終于實現,通過實體Bean的建立與MySQL數據庫的連接。往數據表中插入一條記錄。
一、實體Bean的工作原理
(1)配置數據源連接。
(2)在配置文件persistence.xml中指定數據源。
(3)開發實體Bean。
(4)在會話Bean、Java SE或Java EE中調用實體Bean。
? ? ? ? 以下我們就依照從底層到上層的順序,來演示創建與數據庫的連接的過程。
connection-url:數據庫連接URL。
driver:數據庫驅動類。
user-name:數據庫登錄username。
password:數據庫登陸password。
我們僅僅須要通過引用JNDI命令KsMysqlDS來引用該數據源。引用的方法非常easy。僅僅須要在persistence.xml中指定該別名就可以
三、指定數據源--persistence.xml
配置文件persistence.xml
當中包括3個配置元素,分別例如以下。
persistence-unit元素:能夠有一個或多個。每一個persistence-unit元素定義了持久化內容名稱、使用的數據源名稱及Hibernate屬性。當中的name屬性用于設置持久化名稱。
jta-data-source元素:用于指定實體Bean使用的數據源名稱KsMysqlDS。當指定數據源名稱時java:/前綴不能缺少,并注意數據源名稱的大寫和小寫。
properties元素:用于指定Hibernate的各項屬性。假設hibernate.hbm2ddl.auto的值設為update,這樣實體Bean加入一個屬性時能同一時候在數據表添加對應字段。
(1)properties元素屬性在各個應用server使用的持久化產品中都不一樣。如JBoss使用Hibernate。WebLogic10使用Kodo,GlassFish/Sun Application Server/Oralce使用Toplink。
(2)JBossserver在啟動或關閉時會引發實體Bean的公布及卸載。
為了開發一個與數據庫表相應的單表實體Bean,我們首先設計一個學生表student的數據結構,該表共包含7個字段。如表6-1所看到的。
學生表student
要開發一個與該表相應的實體Bean非常easy,僅僅須要新建一個POJO類,加入7個與表的字段同名的變量。同一時候使用一些凝視符來表示該實體Bean與數據表student的相應映射關系就可以。
Bean類Student.java。首先我們來看看這個完整的實體類的代碼,例如以下所看到的:
package com.ejb.entitybean; import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table; @SuppressWarnings("serial")
@Entity
@Table(name = "Student")
public class Student implements Serializable { private Integer studentid; //學號 private String name; //姓名 private boolean sex; //性別 private Short age; //年齡 private Date birthday; //出生日期 private String address; //地址 private String telephone //電話 @Id @GeneratedValue public Integer getStudentid() { return studentid; } public void setStudentid(Integer studentid) { this.studentid = studentid; } @Column(name = "name", length = 50) public String getName() { return name; } public void setName(String name) { this.name = name; } @Column(nullable = false) public boolean getSex() { return sex; } public void setSex(boolean sex) { this.sex = sex; } @Column(nullable = false) public Short getAge() { return age; } public void setAge(Short age) { this.age = age; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Column(name = "address", length = 100) public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Column(name = "telephone", length = 20) public String getTelephone() { return telephone; } public void setTelephone(String telephone) { this.telephone = telephone; }
}
實體Bean通常須要實現Serializable接口。這樣就能夠有EJBclient創建該對象,并將該對象傳送到服務端,否則將引發java.io.InvalidClassException例外。
該類是一個Java POJO類,當中包括了7個變量,并為每一個變量加入了getter/setter函數。
為了將該POJO類表現為一個實體Bean,加入了一些凝視符。來與數據表student進行相應。這些凝視例如以下。
@Entity凝視指明這是一個實體Bean,每一個實體Bean類映射數據庫中的一個表。
@Table凝視的name屬性指定映射的數據表名稱,Student類映射的數據表為Student。
@Column凝視定義了映射到列的全部屬性,如列名是否唯一,是否同意為空,是否同意更新等,其屬性介紹例如以下。
name:映射的列名。如映射Student表的name列,能夠在name屬性的getName()方法上面增加@Column(name = "name"),假設不指定映射列名,則容器會將屬性名稱作為默認的映射列名。
unique:是否唯一。
length:對于字符型列,length屬性指定列的最大字符長度。
insertable:是否同意插入。
updatable:是否同意更新。
columnDefinition:定義建表時創建此列的DDL。
secondaryTable:從表名。假設此列不建在主表上(默認建在主表上),則該屬性定義該列所在的從表的名字。
@Lob凝視指定某一個字段為大的文本字段類型。
@Id凝視指定studentid屬性為表的主鍵。
@GeneratedValue凝視定義了標識字段的生成方式,本例中的studentid的值由MySQL數據庫自己主動生成。它能夠有下面多種生成方式。
TABLE:容器指定用底層的數據表確保唯一。
SEQUENCE:使用數據庫的SEQUENCE 列來保證唯一。
IDENTITY:使用數據庫的INDENTIT列來保證唯一。
AUTO:由容器挑選一個合適的方式來保證唯一。
NONE:容器不負責主鍵的生成,由調用程序來完畢。
比如:
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getId() { return this.id;
}
這樣就開發完實體Bean了。它除了在POJO上加入了一些凝視外。與普通的POJO類沒有不論什么差別。
1、開發會話Bean進行調用--StudentDAORemote.java和StudentDAO.java? ? ? ?。
? ? ? ? 以下我們來開發一個遠程的會話Bean組件,通過調用實體Bean類Student.java,來實現往數據表student中插入一條記錄。
? ? ? ? 首先在項目EntityBeanTest中新建一個包com.ejb.dao,然后依照會話Bean的開發方法。在該包中新建一個遠程的會話Bean組件StudentDAO。新建完后會產生一個遠程接口類StudentDAORemote.java和實現類StudentDAO.java。
1)遠程接口類StudentDAORemote.java
? ? ? ? 通過凝視符@Remote進行標識。
? ? ? ? 函數insert()運行插入student功能
遠程接口類StudentDAORemote.java
<span style="font-family:SimSun;">package com.ejb.dao; import java.util.List;
import javax.ejb.Remote;
import com.ejb.entitybean.Student; @Remote
public interface StudentDAORemote { public boolean insert(Student student);
} </span>
2)實現類StudentDAO.java
? ? ? ? 實現了遠程接口StudentDAORemote.java,并通過@Stateless標識為無狀態會話Bean。
? ? ? ? 首先它包括了一個EntityManager類型的變量em。EntityManager是實體管理器。顧名思義。它是實體Bean的管理容器。通過該對象,我們可以實現與數據庫的各種交互,包括增、刪、改、查等。
? ? ? ? 該實體變量em還通過凝視@PersistenceContext來實現動態注入EntityManager對象,假設persistence.xml文件里配置了多個不同的持久化內容。則還須要指定持久化名稱注入EntityManager 對象,能夠通過@PersistenceContext凝視的unitName屬性進行指定,比如:
@PersistenceContext(unitName="exam-entity")
EntityManager em;
假設僅僅有一個持久化內容配置。則不須要明白指定。
? ? ? ? 然后開發該類實現接口中的函數insert(),僅僅須要調用em的persist()函數。就行將Student對象持久化到數據庫中。即往數據庫中新增一條記錄。
實現類StudentDAO.java
package com.ejb.dao; import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import com.ejb.entitybean.Student; @Stateless
public class StudentDAO implements StudentDAORemote { @PersistenceContext protected EntityManager em; public boolean insert(Student student) { try { em.persist(student); } catch (Exception e) { e.printStackTrace(); return false; } return true; }
}
六、打包并部署到JBOSSserver
打成jar包并部署到JBossserver。JBossserver就會自己主動載入該服務。形成JNDI服務供外部訪問了。
該公布步驟例如以下:
1、載入persistence.xml文件。
2、創建數據庫表student,此時查看MySQL數據庫就會看到新建的表student。
3、公布JNDI服務StudentDAO/remote。
這樣我們就能夠通過client訪問JNDI服務StudentDAO/remote了。
七、開發client進行測試-StudentDAOClient.java
? ? ? ? 首先將實體類Student.java和接口類StudentDAORemote.java復制加入到測試項目EJBTestJava的相應包中,然后新建測試類
測試類StudentDAOClient.java
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Properties; import javax.naming.InitialContext;
import javax.naming.NamingException; import com.ejb.dao.StudentDAORemote;
import com.ejb.entitybean.Student; public class StudentDAOClient { public static void main(String[] args) throws NamingException { Properties props = new Properties(); props.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory"); props.setProperty("java.naming.provider.url", "localhost:1099"); props.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming"); try { InitialContext ctx = new InitialContext(props); StudentDAORemote studentDAO = (StudentDAORemote) ctx.lookup("StudentDAO/remote"); Student student = new Student(); student.setName("劉中兵"); student.setSex(true); student.setAge((short)25); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); student.setBirthday(format.parse("1981-05-04")); student.setTelephone("12345678"); student.setAddress("北京"); studentDAO.insert(student); System.out.println("已經插入一個學生記錄!"); } catch (NamingException e) { e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); } }
}
? ? ? ? 該類通過訪問遠程JNDI服務StudentDAO/remote,取得了遠程會話Bean實例studentDAO。然后創建了一個Student實體對象。調用insert()函數插入該對象。執行該程序后,會在控制臺中輸出例如以下信息:
? ? ? ? 已經插入一個學生記錄!
? ? ? ? 這就表明client的Java類已正確地將Student對象提交到遠程會話Bean組件中了。