今筆者が作っているWEBアプリケーションのDB周り実装です。
インフラ的には、主にWLS12+OracleDBとなっていますが、社内特定部署に利用が限定されたアプリケーションなので、DBセッションは「節約したい」という微妙な要件です。さらに、WLSデータソース設定はしたくないとの希望です。
せっかくEE使うんで、JPA前提でやる事にしますが、WEBに出てる殆どのネタがWLSのデータソースを使っているんですよね。
セッションプールは別途OracleUCPの独自実装があるので、persistance.xmlで指定せずに、UCPのデータソースをプログラム上からエンティティマネージャに指定するというイメージなんですが、WEBで調べながら実際に動くまで結構時間掛かりました。。
まず、EclipseのプロジェクトファセットにJPAを追加するとpersistence.xmlが出来ますが、データソースをここでは設定しないのでエンティティクラス定義のみ書きます。
1 2 3 4 5 6 7 8 |
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.0" 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"> <persistence-unit name="DBresource" transaction-type="RESOURCE_LOCAL"> <class>jp.xxx.zzz.model.user.LoginUser</class> 他クラス定義省略 <exclude-unlisted-classes>true</exclude-unlisted-classes> </persistence-unit> </persistence> |
次にエンティティクラス(テーブル定義みたいなもの)
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@Table(name="USER_MST") @Entity public class LoginUser implements Serializable{ private static final long serialVersionUID = 1L; /** ユーザーID*/ @Id @NotNull @Size(max=20,min=7) private String USER_ID; /** ユーザーパスワード*/ private String USER_PASS; /** ユーザー種別*/ @NotNull private String USER_TYPE; 以下、項目とゲッタセッタは省略 |
その次が、データアクセスインターフェース(データ操作定義)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
/** * ログインユーザーマスタ * Data access object interface * */ public interface LoginUserDao { /*** * データ1件取得 * @return キー * */ public LoginUser find(Object id); /*** * データ新規作成 * */ public void create(LoginUser entitiy); /** * データ更新 * */ public void update(LoginUser entitiy); /** * データ全件取得 * */ public List<LoginUser> getAll(); /** * データ件数取得 * */ public long getAllCnt(); } |
さらに上記インターフェースをJPA実装したデータアクセスオブジェクト(DAO)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
/** * ログインユーザーマスタ * Data access object (JPA) * */ @Stateless //@TransactionAttribute(TransactionAttributeType.REQUIRED) public class LoginUserDaoJpa implements LoginUserDao{ protected static Logger logger = LogManager.getLogger(); public EntityManager em = null; /** * コンストラクタ * */ public LoginUserDaoJpa() { super(); em = DBEntityManager.getEntityManager(); } /** * データ検索 * @param id (key) * @return LoginUser * */ @Override public LoginUser find(Object id) { return em.find(LoginUser.class, id); } /** * データ新規登録 * @param ServerConf * */ @Override public void create(LoginUser entity) { EntityTransaction txn = em.getTransaction(); txn.begin(); if ( ! em.getTransaction().isActive() ){ em.getTransaction().begin(); } em.persist(entity); txn.commit(); } /** * ユーザーマスタの全取得 * @return ログインユーザーマスタのリスト * */ @SuppressWarnings("unchecked") @Override public List<LoginUser> getAll() { //後日追加 em.clear(); List<LoginUser> result = em.createQuery("SELECT c FROM LoginUser c WHERE c.STATUS_FLG < :SFLG ORDER BY c.USER_ID") .setParameter("SFLG", "9") .getResultList(); return result; } /** * ユーザーマスタより業務メンバーの取得 * @return ログインユーザーマスタのリスト * */ @SuppressWarnings("unchecked") public List<LoginUser> getBizMember() { //後日追加 em.clear(); List<LoginUser> result = em.createQuery("SELECT c FROM LoginUser c WHERE c.USER_TYPE < '5' AND c.STATUS_FLG < :SFLG ORDER BY c.USER_ID") .setParameter("SFLG", "9") .getResultList(); return result; } /** * データ更新 * @param ServerConf * */ @Override public void update(LoginUser entity) { EntityTransaction txn = em.getTransaction(); txn.begin(); if ( ! em.getTransaction().isActive() ){ em.getTransaction().begin(); } em.merge(entity); txn.commit(); } /** * 件数取得 * */ public long getAllCnt() { return em.createQuery("SELECT c FROM UserMaster c").getMaxResults(); } } |
上記DAOのコンストラクタで読んでいるEntityManagerを取得するシングルトンクラス
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public class DBEntityManager { protected static Logger logger = LogManager.getLogger(); private static Map<String, Object> configOverrides; static { Map<String, Object> map = new HashMap<String, Object>(); try { //ここのDBConnectionMgrとは、UCPを使用してデータソースを戻す独自実装です・・ //独自実装内で各種JDBC設定がされています・・ map.put("javax.persistence.nonJtaDataSource", DBConnectionMgr.getDataSource()); } catch (SQLException e) { logger.error("DBConnectionPool JpaEntityManager put Error!", e); } configOverrides = Collections.unmodifiableMap(map); } /** * EntityManagerを返します * */ public static EntityManager getEntityManager(){ return Persistence.createEntityManagerFactory("DBresource", configOverrides).createEntityManager(); } } |
上記を呼び出しているJava画面ソース
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
/** * ユーザーマスタ管理画面処理(ユーザー作成・更新・削除・パスワード変更共通) * * */ @ManagedBean(name="UserManager") @ViewScoped public class UserManager implements Serializable { private static final long serialVersionUID = 1L; @EJB private LoginUserDao dao; List<LoginUser> List; @ManagedProperty("#{userDto}") LoginUserDto user; public LoginUserDto getUser() { return user; } public void setUser(LoginUserDto user) { this.user = user; } /** 以下画面項目 */ public List<LoginUser> getList() { List = dao.getAll(); return List; } public void setList(List<LoginUser> list) { List = list; } 以下省略 |
最後に上記呼び出し箇所のXHMLの抜粋
1 2 3 4 5 6 |
<h:dataTable var="item" value="#{UserManager.list}" columnClasses="userid,username" > <h:column> <f:facet name="header">#{words.Label_UserID}</f:facet> <h:outputText value="#{item.USER_ID}" /> </h:column> </h:dataTable> |
後で、テストしたところ、DB更新は出来ていてもクエリーでデータを取得すると反映していませんでした。永続化コンテキストからみの事象と思われますが、細かい仕様を調査するのは骨が折れるので、、、クエリー取得前にEntityManagerをclearする事で対処としました。