2010-12-29

共用EJB - Remote 篇

先前寫了共用EJB - Local 篇. 後來,要把他運用在同一個container Server , 不同的EJB3 或者 web 上時, 發現他根本不能work . 會一直跑出 Wrong target Eroror message. 研究了一下, 發現應該是不同的 EJB package 不能共用 local ,要用 remote 的方式.

另外就是, 如果你是不同的EJB package 採用 resource inject 方式, 那如果被引用的 EJB shutdown. 引用別人的 EJB or web 在 jboss 6 上面會掛掉, 得重新啟動才有辦法繼續運作. 所以. 建議方式是採用 InitialContext 方式去 引用外部的 EJB resource, 不然一天到晚你要記得去 restart .


在 Session Bean 部份的寫法


package test;

import javax.ejb.Stateless;

@Stateless(name="test/TestSessionBean")
public class TestSessionBean implements TestSessionBeanRLocal,TestSessionBeanRemote {

@Override
public void test() {
System.out.println("Hello Test Bean");
}

}


引用 共用 SessionBean 的寫法(Resource Injection)


package test;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import test.TestSessionBeanLocal;


@Stateless
public class TestBean implements TestBeanLocal {

@EJB(mappedName = "test/TestSessionBean/remote")
TestSessionBeanRemote testBean;

@Override
public void testBean() {
testBean.test();
}
}



上面標注紅色字體部份, 就是在jboss 下面可以正常運做的 code.
主要在 引用共用session bean 那邊的設定, 需要多加一個 /remote , 這是跟local 不一樣的地方.



引用 共用 SessionBean 的寫法(jndi lookup)


package test;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import test.TestSessionBeanLocal;
import javax.naming.InitialContext;

@Stateless
public class TestBean implements TestBeanLocal {

TestSessionBeanRemote testBean;

@Override
public void testBean() {
InitialContext ctx = new InitialContext();
testBean = (TestSessionBeanRemote)ctx.lookup("
test/TestSessionBean/remote");
testBean.test();
}
}

2010-12-03

Query by Page on JPA

在Query 大量的資料時, 如果沒有將資料作 page的動作, 一次抓回來會在吃掉大量的記憶體去產生相關的 class. 如果, 只需要部份資料慢慢取回處理, 可以採用page 的方式去截去資料.
在 JPA 中, Query 這一個物件有
  • setFirstResult(int startPosition)
  • setMaxResults(int maxResult)
運用這兩個 method 就可以達到 Page Query 的方法了.

在 Pro JPA 2 page. 194 提到, 可用 stateful session 來達到用 存放在 http session 中, 讓 jsp or javaServer faces 可以 作到 PageQuery


@Stateful
public class ResultPagerBean implements ResultPager {
@PersistenceContext(unitName="QueryPaging")
private EntityManager em;

private String reportQueryName;
private long currentPage;
private long maxResults;
private long pageSize;

public long getPageSize() {
return pageSize;
}
public long getMaxPages() {
return maxResults / pageSize;
}

public void init(long pageSize, String countQueryName,
String reportQueryName) {
this.pageSize = pageSize;
this.reportQueryName = reportQueryName;
maxResults = em.createNamedQuery(countQueryName, Long.class)
.getSingleResult();
currentPage = 0;
}

public List getCurrentResults() {
return em.createNamedQuery(reportQueryName)
.setFirstResult(currentPage * pageSize)
.setMaxResults(pageSize)
.getResultList();
}

public void next() {
currentPage ;
}

public void previous() {
currentPage--;
if (currentPage < 0) {
currentPage = 0;
}
}

public long getCurrentPage() {
return currentPage;
}

public void setCurrentPage(long currentPage) {
this.currentPage = currentPage;
}

@Remove
public void finished() {}
}

Read-Only entity for JPA

開發系統時會有一些只有Query 不會去 modify 的db query . 在jpa 中 每一個entity 產生後都是會被 managed. 所以, 要怎樣作到 不會被 managed 來造乘Query locked. 在Pro JPA 2 page.191 有提到一個 Optimizing Read-Only Queries 提到兩種方式 :
1. Outside of a Transaction : 將 entity query 的程式段落, 不要包涵在transaction 中. 但是對於 application-managed or extends entity managers 就不是用了.
2. 將Query 封裝在一個 stateless session facade , 在method 宣告 NOT_SUPPORTED. 只要執行到這一個method code, 任何 transaction 都會被 suspended. 已達到read-only 最佳化.

@Stateless
public class QueryServiceBean implements QueryService {
@PersistenceContext(unitName="EmployeeService")
EntityManager em;

@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public List<Department> findAllDepartmentsDetached() {
return em.createQuery("SELECT d FROM Department d",
Department.class)
.getResultList();
}

// ...
}