天天看點

EJB3之查詢

    EJB3的實體查詢 本文 使用的是JPA規範進行操作  産品實作用的是Hibernate

主要涉及到增加、删除、更新、對象查詢帶排序、查詢條件中使用構造器、運算符查詢、字元串函數、計算函數、聚合函數

先來看看 提供EJB服務的無狀态bean

package com.undergrowth.bean.impl;

import java.util.List;

import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import com.undergrowth.bean.Person;
import com.undergrowth.bean.SimplePerson;
import com.undergrowth.bean.service.IPerson;

@Stateless
@Remote(IPerson.class)
public class PersonDao implements IPerson {

	//依賴注入實體管理器
	@PersistenceContext
	EntityManager em;
	
	@Override
	public void save(Person person) {
		// TODO Auto-generated method stub
		//由建立狀态轉為托管
		em.persist(person);
	}

	@Override
	public void delete(Integer personId) {
		// TODO Auto-generated method stub
		//由托管轉為銷毀
		em.remove(getReferencesById(personId));
	}

	@Override
	public void update(Person person) {
		// TODO Auto-generated method stub
		//由遊離轉為托管
		em.merge(person);
	}

	@Override
	public Person getById(Integer personId) {
		// TODO Auto-generated method stub
		return em.find(Person.class, personId);
	}

	@Override
	public Person getReferencesById(Integer personId) {
		// TODO Auto-generated method stub
		//使用懶加載 傳回代理對象  隻有在使用get方法擷取資料時  才加載對象
		return em.getReference(Person.class, personId);
	}

	/**
	 * 通過sql來擷取對象
	 * @param sql
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@Override
	public List<Person> getBySql(String sql) {
		// TODO Auto-generated method stub
		Query query=em.createQuery(sql);
		return (List<Person>)query.getResultList();
	}

	/**
	 * 通過sql來進行删除 添加 修改 資料
	 * @param sql
	 * @return
	 */
	@Override
	public int cudBySql(String sql) {
		// TODO Auto-generated method stub
		Query query=em.createQuery(sql);
		int num=query.executeUpdate();
		return num;
	}
	
	
	@SuppressWarnings("unchecked")
	@Override
	public List<Person> getAllPersons() {
		// TODO Auto-generated method stub
		//使用JPQL進行查詢結果集
	return (List<Person>)em.createQuery("select p from Person p").getResultList();
	}

	/**
	 * 傳回部分對象
	 */
	@SuppressWarnings("unchecked")
	@Override
	public List<SimplePerson> getSimplePersonThroSql(String sql) {
		// TODO Auto-generated method stub
		return (List<SimplePerson>)em.createQuery(sql).getResultList();
	}

	/**
	 * 通過查詢傳回單一的結果集
	 */
	@Override
	public Object getBySqlRetSimple(String sql) {
		// TODO Auto-generated method stub
		Query query=em.createQuery(sql);
		return query.getSingleResult();
	}

	

}
           

對應的遠端接口

package com.undergrowth.bean.service;

import java.util.List;

import javax.persistence.Query;

import com.undergrowth.bean.Person;
import com.undergrowth.bean.SimplePerson;

public interface IPerson {
	
	//增删改查
	public void save(Person person);
	public void delete(Integer personId);
	public void update(Person person);
	/**
	 * 通過sql來進行删除 添加 修改 資料
	 * @param sql
	 * @return
	 */
	public int  cudBySql(String sql);
	public Person getById(Integer personId);
	public Person getReferencesById(Integer personId);
	/**
	 * 通過sql來擷取對象
	 * @param sql
	 * @return
	 */
	public List<Person> getBySql(String sql);
	public List<Person> getAllPersons();
	/**
	 * 擷取隻有id name age的Person
	 * @param sql
	 * @return
	 */
	public List<SimplePerson> getSimplePersonThroSql(String sql);
	public Object getBySqlRetSimple(String sql);
	
	
}
           

一對一的實體bean

package com.undergrowth.bean;

import java.io.Serializable;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;

/*
 * 步驟
 * 1.一對一的互相關聯 各自實體中擁有對方
 * 2.設定關系維護端與被維護端 指定級聯的關系
 * 3.指明外鍵
 * 4.添加資料
 */

@Entity
@Table(name="person_info")
public class Person implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	@Id @GeneratedValue 
	private Integer id;
	@Column(length=10,nullable=false)
	private String name;
	@Column(nullable=false)
	private Integer age;
	//all表示當person進行增删改查的時候 級聯的增删改查idcard
	//optional為false表示外鍵不能為空
	@OneToOne(cascade=CascadeType.ALL,optional=false)
	//JoinColumn指明idcard_id作為外鍵 來維護兩個表的關系
	@JoinColumn(name="idcard_id")
	private IDCard idCard;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	
	public Person(){} //用于給反射機制使用
	public IDCard getIdCard() {
		return idCard;
	}
	public void setIdCard(IDCard idCard) {
		this.idCard = idCard;
	}
	public Person(String name, Integer age, IDCard idCard) {
		super();
		this.name = name;
		this.age = age;
		this.idCard = idCard;
	}
	
	@Override
	public String toString() {
		return "Person [id=" + id + ", name=" + name + ", age=" + age
				+ ", idCard=" + idCard + "]";
	}
	
	
	
}
           
package com.undergrowth.bean;

import java.io.Serializable;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;


@Entity
@Table(name="idcard_info")
public class IDCard implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	@Id @GeneratedValue
	private Integer id;
	@Column(length=18,nullable=false)
	private String cardNum;
	@Column(length=20,nullable=false)
	private String issuedBy;
	//mappedBy指定使用person對象的idCard這個屬性來進行維護表間關系 并指明自己是關系的被維護端
	@OneToOne(mappedBy="idCard")
	private Person person;
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getCardNum() {
		return cardNum;
	}
	public void setCardNum(String cardNum) {
		this.cardNum = cardNum;
	}
	public String getIssuedBy() {
		return issuedBy;
	}
	public void setIssuedBy(String issuedBy) {
		this.issuedBy = issuedBy;
	}
	public IDCard(){} //用于給反射機制使用
	public IDCard(String cardNum, String issuedBy) {
		this.cardNum = cardNum;
		this.issuedBy = issuedBy;
	}
	public Person getPerson() {
		return person;
	}
	public void setPerson(Person person) {
		this.person = person;
	}
	
	@Override
	public String toString() {
		return "IDCard [id=" + id + ", cardNum=" + cardNum + ", issuedBy="
				+ issuedBy + "]";
	}
	
	
}
           

封裝部分實體屬性的SimplePerson

package com.undergrowth.bean;

import java.io.Serializable;

public class SimplePerson implements  Serializable{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Integer id;
	private String name;
	private Integer age;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "SimplePerson [id=" + id + ", name=" + name + ", age=" + age
				+ "]";
	}
	public SimplePerson(Integer id, String name, Integer age) {
		super();
		this.id = id;
		this.name = name;
		this.age = age;
	}
	public SimplePerson() {
		super();
	}
	
	
}
           

哦 persistence.xml檔案

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
        version="2.0">
    <persistence-unit name="under" transaction-type="JTA">
    <jta-data-source>java:/myDataSource</jta-data-source>
        <properties>
         <property name="hibernate.hbm2ddl.auto" value="update" />
         <property name="hibernate.show_sql" value="true" />
         <property name="hibernate.format_sql" value="true"/>
        </properties>
    </persistence-unit>
</persistence>
           

ant的編譯build.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- ================================================ -->
<!-- Sample buildfile for jar components -->
<!-- -->
<!-- ================================================ -->
<project name="EJB3QL"  basedir=".">
    <!-- 定義屬性 -->
    <property name="src.dir" value="${basedir}\src" />
	<!--  通路作業系統的環境變量  -->
    <property environment="env"  />
	<!-- 設定jboss的目錄 -->
    <property name="jboss.home" value="${env.JBOSS_HOME}"/>
	<!-- 設定jboss的伺服器名 -->
    <property name="jboss.server.home" value="standalone"  />
    <property name="dep" value="deployments"  />
    <property name="build.dir" value="${basedir}\build"  />

	<!--建構path路徑  -->
    <path id="build.classpath">
    	<fileset dir="${basedir}\lib">
    		<include name="*.jar" />
    	</fileset>
    	<!--<pathelement location="${build.dir}" /> -->
    </path>

	<!-- - - - - - - - - - - - - - -->
	<!-- target: init -->
	<!-- - - - - - - - - - - - - - -->
	<target name="init">
		<delete dir="${build.dir}"></delete>
		<mkdir dir="${build.dir}"></mkdir>
	</target>

	<!-- ========================= -->
	<!-- target: compile -->
	<!-- ========================= -->
	<target name="compile" depends="init"
		description="--> compile  this component" >
         <!--  編譯src目錄下以com開頭的所有子包中的類 
         '*' matches zero or more characters, '?' matches one character.
         When ** is used as the name of a directory in the pattern, it matches zero or more directories
         -->
		<javac srcdir="${src.dir}" destdir="${build.dir}" includes="com/**" includeAntRuntime="false">
			<classpath refid="build.classpath" />
		</javac>
	</target>
	
	<!-- 打包 -->
	<target name="ejbjar" depends="compile" description="打包ejb">
	   <jar jarfile="${basedir}\${ant.project.name}.jar">
	   	<fileset dir="${build.dir}">
	   		<!-- 将build目錄下的所有已class結尾的檔案打包進去 -->
	   		<include name="**/*.class"></include>
	   	</fileset>
	   	<!--将src目錄下的META-INF目錄下的檔案打包進去 -->
	   	<metainf dir="${src.dir}\META-INF"></metainf>
	   </jar>
	</target>
  
    <!-- 部署 -->
    <target name="delopy" depends="ejbjar" description="部署ejb">
    	<copy file="${basedir}\${ant.project.name}.jar"  todir="${jboss.home}\${jboss.server.home}\${dep}\" />
    </target>
    
    <!-- 解除安裝ejb -->
    <target name="undeploy" description="解除安裝ejb">
      <delete file="${jboss.home}\${jboss.server.home}\${dep}\${ant.project.name}.jar"></delete>
    </target>
    
	<!-- 打包接口 -->
	<target name="package_inter" depends="compile" description="打包接口">
		<jar jarfile="${basedir}\${ant.project.name}Interface.jar">
			   	<fileset dir="${build.dir}">
			   		<!-- 将build目錄下中impl目錄下的已class結尾的檔案不打包進去 -->
			   		<exclude name="**/impl/*.class"></exclude>
			   	</fileset>
			   </jar>
	</target>
	
	<!--  删除生成的class和打包的檔案 -->
	<target name="clean" description="清除項目">
		<delete dir="${build.dir}"></delete>
		<delete file="${basedir}\${ant.project.name}.jar"></delete>
		<delete file="${basedir}\${ant.project.name}Interface.jar"></delete>
	</target>
	

</project>
           

将無狀态bean使用ant工具進行釋出到jboss 中  後 即可通過用戶端進行通路無狀态的服務bean了

2、

用戶端

工具類 用于擷取EJB服務

package com.client.undergrowth.util;

import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import com.undergrowth.bean.service.IPerson;



public class JndiUtil {

	/**
	 * 擷取EJB PersonDao的服務
	 * @return
	 * @throws NamingException
	 */
	public static IPerson lookupIPersonRemoteBean() throws NamingException{
	   return (IPerson)lookupRemoteBean("EJB3QL","PersonDao",IPerson.class.getName());
	}
	
	/**
	 * 通過子產品名,Bean名稱,接口名稱擷取遠端服務
	 * @param moduleName
	 * @param beanName
	 * @param viewClassName
	 * @return
	 * @throws NamingException
	 */
	public static Object lookupRemoteBean(String moduleName,String beanName,String viewClassName) throws NamingException {
        final Hashtable jndiProperties = new Hashtable();
        jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
        final Context context = new InitialContext(jndiProperties);
        // The app name is the application name of the deployed EJBs. This is typically the ear name
        // without the .ear suffix. However, the application name could be overridden in the application.xml of the
        // EJB deployment on the server.
        // Since we haven't deployed the application as a .ear, the app name for us will be an empty string
        final String appName = "";
        // This is the module name of the deployed EJBs on the server. This is typically the jar name of the
        // EJB deployment, without the .jar suffix, but can be overridden via the ejb-jar.xml
        // In this example, we have deployed the EJBs in a jboss-as-ejb-remote-app.jar, so the module name is
        // jboss-as-ejb-remote-app
        //final String moduleName = "EJB3QL";
        // AS7 allows each deployment to have an (optional) distinct name. We haven't specified a distinct name for
        // our EJB deployment, so this is an empty string
        final String distinctName = "";
        // The EJB name which by default is the simple class name of the bean implementation class
       // final String beanName = "PersonDao";
        // the remote view fully qualified class name
       // final String viewClassName = HelloWorldRemote.class.getName();
       // final String viewClassName = IPerson.class.getName();
        // let's do the lookup
        return context.lookup("ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName);
        
 }
	
}
           

單元測試類

package com.junit.test;

import static org.junit.Assert.*;

import java.util.Iterator;
import java.util.List;

import org.junit.BeforeClass;
import org.junit.Test;

import com.client.undergrowth.util.JndiUtil;
import com.undergrowth.bean.IDCard;
import com.undergrowth.bean.Person;
import com.undergrowth.bean.SimplePerson;
import com.undergrowth.bean.service.IPerson;

public class PersonDaoTest {

	static IPerson personDao = null;
    final int cudNum=8;
    
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		// 擷取服務
		personDao = JndiUtil.lookupIPersonRemoteBean();
	}

	/**
	 * 儲存
	 */
	@Test
	public void testSave() {
		IDCard idCard = new IDCard("333333333", "太平洋美國");
		// 将關系被維護端的資料傳遞給關系維護端的資料 用于外鍵的更新
		Person person = new Person("奧巴馬", 5, idCard);
		// 因為級聯關系設定了級聯儲存 是以這裡儲存person 同時也會儲存idCard
		personDao.save(person);
	}

	/**
	 * 删除
	 */
	@Test
	public void testDelete() {
		personDao.delete(cudNum);
	}

	/**
	 * 更新
	 */
	@Test
	public void testUpdate() {
		Person person=personDao.getById(cudNum);
		person.setName("普京");
		personDao.update(person);
	}

	/**
	 * 通過id擷取對象
	 */
	@Test
	public void testGetById() {
		System.out.println(personDao.getById(cudNum));
	}

	/**
	 * 擷取對象代理
	 */
	@Test
	public void testGetReferencesById() {
		//可避免資料庫加載的持久化開銷 
		//因為傳回的是代理對象  沒有持久化操作 是以這裡會報錯  無法擷取對象
		//System.out.println(personDao.getReferencesById(8));
	}

	/**
	 * 對象查詢
	 */
	@Test
	public void testGetBySql() {
		String sqlString="select p from Person p where p.age>12";
		outListPerson(personDao.getBySql(sqlString));
	}
	
	/**
	 * 對象查詢帶排序
	 * order by asc/desc
	 */
	@Test
	public void testGetBySqlOrderBy() {
		String sqlString="select p from Person p order by p.age desc";
		outListPerson(personDao.getBySql(sqlString));
	}

	/**
	 * 查詢條件中使用構造器 傳回構造器對象的結果集
	 */
	@Test
	public void testGetSimplePersonThroSql() {
		String sqlString="select new com.undergrowth.bean.SimplePerson(p.id,p.name,p.age) from Person p where p.age>8 order by p.age desc";
		outListSimplePerson(personDao.getSimplePersonThroSql(sqlString));
	}
	
	/**
	 * 測試運算符 not 、between and 、like、in、is null、exists
	 */
	@Test
	public void testOperatorBetween() {
		String sqlString="select p from Person p where p.age between 2 and 15";
		outListPerson(personDao.getBySql(sqlString));
	}
	
	/**
	 * 測試運算符 not 、between and 、like、in、is null、exists
	 */
	@Test
	public void testOperatorLike() {
		String sqlString="select p from Person p where p.name like '%奧%' ";
		outListPerson(personDao.getBySql(sqlString));
	}
	
	/**
	 * 測試運算符 not 、between and 、like、in、is null、exists
	 */
	@Test
	public void testOperatorExists() {
		String sqlString="select p from Person p where  exists(select pe from IDCard pe where pe.id>13) ";
		outListPerson(personDao.getBySql(sqlString));
	}
	
	/**
	 * 測試字元串函數  upper lower concat length substring trim locate
	 */
	@Test
	public void testStrFunc() {
		String sqlString="select p from Person p where  length(p.name)>2 ";
		outListPerson(personDao.getBySql(sqlString));
	}
	
	/**
	 * 測試計算函數  abs mod sqrt size
	 */
	@Test
	public void testNumberFunc() {
		String sqlString="select p from Person p where  mod(p.age,10) > 1 ";
		outListPerson(personDao.getBySql(sqlString));
	}
	
	/**
	 * 傳回單一的結果集 聚合函數 count max min avg sum
	 */
	@Test
	public void testGetBySqlRetSimple() {
		//這裡不能使用count(1) 因為這是基于對象的查詢 1被當做值 導緻報錯
		String sqlString="select count(*) from Person p where p.age>8";
		System.out.println("年齡大于8歲的人有"+personDao.getBySqlRetSimple(sqlString));
	}
	
	/**
	 * 使用語句進行更新 删除 增加
	 */
	@Test
	public void testCudBySql() {
		String sqlUpdateString="update Person p set p.name='劉德華' where p.age=20";
		System.out.println("影響結果集為:"+personDao.cudBySql(sqlUpdateString)+"條");
	}

	/**
	 * 擷取所有對象
	 */
	@Test
	public void testGetAllPersons() {
		List<Person> list=personDao.getAllPersons();
		outListPerson(list);
	}

	/**
	 * 周遊輸出結果集
	 * @param list
	 */
	private void outListPerson(List<Person> list) {
		// TODO Auto-generated method stub
		for (Person person : list) {
			System.out.println(person);	
			}
	}
	
	/**
	 * 輸出SimplePerson
	 * @param list
	 */
	private void outListSimplePerson(List<SimplePerson> list) {
		// TODO Auto-generated method stub
		for (SimplePerson person : list) {
			System.out.println(person);	
			}
	}
	
	

}
           

用戶端連接配接jboss的jndi配置檔案

jboss-ejb-client.properties

endpoint.name=client-endpoint  
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false  
   
remote.connections=default  
   
remote.connection.default.host= localhost
remote.connection.default.port = 4447
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS=false  
  
remote.connection.default.username=qq     
remote.connection.default.password=q