Okrem vykonávania rôznych biznis metód, má entitná trieda najviac práce so synchronizovaním svojho stavu s korešpondujúcimi dátami v podkladovej databáze. K tomuto účelu sú určené dve špeciálne metódy, ejbLoad a ejbStore.

Implementácia metódy ejbLoad

EJB kontajner obvykle zavolá túto metódu pri aktivácii entity, kedy je bezpodmienečne nutné zabezpečiť jej synchronizáciu s tým, čo je v databáze. Nasledujúci výpis zobrazuje obsah metódy ejbLoad entitnej triedy EnglishAuctionBean.

/* EnglishAuctionBean.java */
public void ejbLoad() {
 Connection con = null;
 PreparedStatement stmt = null;
 ResultSet rs = null;
 try {
  con = DSConnectionHelper.getConnection(„auctionSource“);
  // vytvoríme príkaz SELECT pre jednotlivé polia aukcie
  stmt = con.prepareStatement(„SELECT Name, Description,
   Status, StartingBid, MinBidIncrement, ReserveAmount,
   StartDate, ScheduledEndDate, ActualEndDate, LeadingBidId,
   WinningBidId, ItemId, Quantity FROM auction WHERE id=?“);
  Integer primaryKey = (Integer)ctx.getPrimaryKey();
  stmt.setInt(1,primaryKey.intValue());
  // vykonáme príkaz SELECT
  rs = stmt.executeQuery();
  if (rs.next()) {
   // vložíme hodnoty výsledkov do jednotlivých premenných inštancie
   id = primaryKey;
   name = rs.getString(„Name“);
   description = rs.getString(„Description“);
   status = rs.getString(„Status“);
   // typ SQL numeric je vrátený ako BigDecimal
   BigDecimal bd = rs.getBigDecimal(„StartingBid“);
   startingBid = bd != null ? new Double(bd.doubleValue()) : null;
   bd = rs.getBigDecimal(„MinBidIncrement“);
   minBidIncrement = bd != null ? new Double(bd.doubleValue()) : null;
   bd = rs.getBigDecimal(„ReserveAmount“);
   reserveAmount = bd != null ? new Double(bd.doubleValue()) : null;
   startDateTime = rs.getTimestamp(„StartDate“);
 scheduledEndDateTime = rs.getTimestamp(„ScheduledEndDate“);
   actualEndDateTime = rs.getTimestamp(„ActualEndDate“);
   leadingBidId = (Integer)rs.getObject(„LeadingBidId“);
   winningBidId = (Integer)rs.getObject(„WinningBidId“);
   itemId = (Integer)rs.getObject(„ItemId“);
   quantity = (Integer)rs.getObject(„Quantity“);
   item = null;
   setBids(null);
   leadingBid = null;
   winningBid = null;
  }
  else {
   throw new EJBException(„Chyba pri načítaní dát.“);
  }
 }
 catch (SQLException e) {
  throw new EJBException;
 }
 finally {
  DSConnectionHelper.cleanup(stmt, con);
 }
}

Vo vnútri metódy ejbLoad môžete využiť inštanciu triedy EntityContext za účelom získania jej primárneho kľúča. Následne môžete vytvoriť príkaz SELECT, ktorý vytiahne požadované hodnoty atribútov z databázy. Entitná trieda ešte obvykle potrebuje získať referencie na asociované objekty, alebo aspoň zistiť stav ich kľúčových hodnôt, aby ich mohla neskôr v prípade potreby využiť.

Všimnite si, že metóda ejbLoad momentálne nedrží zoznam všetkých vykonaných ponúk. Stane sa tak až v prípade, keď ich bude treba. Podobne aj čo sa týka poslednej a víťaznej ponuky, nepoznáme ich hodnoty, iba vlastníme odkaz na primárne kľúče spomínaných objektov. Z toho vyplýva, že je iba na vás, čo konkrétne bude metóda ejbLoad „vyťahovať“ z podkladovej databázy.

Implementácia metódy ejbStore

Náprotivkom metódy ejbLoad je metóda ejbStore. EJB kontajner volá túto metódu obvykle v dvoch možných prípadoch. Buď vtedy, keď transakcia obsahujúca entitný objekt bude potvrdená (commit), alebo vtedy, keď má byť entita pasivovaná. Podobne ako pri metóde ejbLoad, aj tu si musíte zabezpečiť implementáciu metódy ejbStore vo vlastnej réžii (keďže ide o BMP mechanizmus). Nasledujúci fragment zobrazuje implementáciu metódy ejbStore pre entitu EnglishAuctionBean.

/* EnglishAuctionBean.java */
private Collection bidsToStore = new ArrayList();
// v tejto časti sa naplní kolekcia bidsToStore

public void ejbStore() {
 Connection con = null;
 PreparedStatement stmt = null;
 try {
  con = DSConnectionHelper.getConnection(„auctionSource“);
  if (!bidsToStore.isEmpty()) {
   // uložíme ponuky pridané počas tejto transkacie
   stmt = con.prepareStatement(
   „INSERT INTO bid (id, AuctionId, BidderId, BidDateTime,
   Amount, TransactionId) VALUES (?,?,?,?,?,?)“);
   Iterator iter = bidsToStore.iterator();
   while (iter.hasNext()) {
    Bid newBid = (Bid)iter.next();
    stmt.setInt(1, newBid.getId().intValue());
    stmt.setInt(2, newBid.getAuctionId().intValue());
    stmt.setInt(3, newBid.getBidderId().intValue());
    stmt.setTimestamp(4, newBid.getDateTimeSubmitted());
    stmt.setDouble(5, newBid.getAmount().doubleValue());
    stmt.setString(6, newBid.getTransactionId());
    
    int rowsInserted = stmt.executeUpdate();
    if (rowsInserted != 1) {
     throw new EJBException(
      „Nemôžem vložiť ponuku do DB.“);
    }
   }
   bidsToStore.clear();
   stmt.close();
  }
  
  // vytvoríme UPDATE a uložíme stav aukcie do DB
  stmt = con.prepareStatement(
   „UPDATE auction SET Name = ?, Description = ?,
   Status = ?, StartingBid = ?, MinBidIncrement = ?,
   ReserveAmount = ?, StartDate = ?, ScheduledEndDate = ?,
   ActualEndDate = ?, LeadingBidId = ?, WinningBidId = ?,
   ItemId = ?, Quantity = ? FROM auction WHERE id = ?“);
  stmt.setString(1, getName());
  stmt.setString(2, getDescription());
  stmt.setString(3, getStatus());
  if (getStartingBid() != null) {
   stmt.setDouble(4, getStartingBid().doubleValue());
  }
  else {
   stmt.setNull(4, java.sql.Types.DOUBLE);
  }
  if (getMinBidIncrement() != null) {
   stmt.setDouble(5, getMinBidIncrement().doubleValue());
  }
  else {
   stmt.setNull(5, java.sql.Types.DOUBLE);
  }
  if (getReserveAmount() != null) {
   stmt.setDouble(6, getReserveAmount().doubleValue());
  }
  else {
   stmt.setNull(6, java.sql.Types.DOUBLE);
  }
  stmt.setTimestamp(7, getStartDateTime());
  stmt.setTimestamp(8, getScheduledEndDateTime());
  stmt.setTimestamp(9, getActualEndDateTime());
  if (getLeadingBid() != null) {
   stmt.setInt(10, getLeadingBid().getId().intValue());
  }
  else {
   stmt.setNull(10, java.sql.Types.INTEGER);
  }
  if (getWinningBid() != null) {
   stmt.setInt(11, getWinningBid().getId().intValue());
  }
  else {
   stmt.setNull(11, java.sql.Types.INTEGER);
  }
  if (getItemId() != null) {
   stmt.setInt(12, getItemId().intValue());
  }
  else {
   stmt.setNull(12, java.sql.Types.INTEGER);
  }
  if (getQuantity() != null) {
   stmt.setInt(13, getQuantity().intValue());
  }
  else {
   stmt.setNull(13, java.sql.Types.INTEGER);
  }
  // nastavíme PK pre WHERE klauzulu
  stmt.setInt(14, getId().intValue());
  
  // vykonáme update a ak zlyhá, vyhodíme výnimku
  int rowsUpdated = stmt.executeUpdate();
  if (rowsUpdated != 1) {
   throw new EJBException(„Chyba pri ukladaní dát.“);
  }
 }
 catch (SQLException e) {
  // vyhodíme výnimku ak nastane chyba prístupu k DB
  throw new EJBException;
  }
 finally {
  // uzatvoríme spojenie
  DSConnectionHelper.cleanup(stmt, con);
 }
}

Okrem úlohy vykonávať update stavu aukcie, zabezpečuje metóda ejbStore aj vkladanie nových ponúk (objektov triedy Bid) do databázy. Nasledujúci výpis zobrazuje implementáciu triedy Bid.

/**
* File: Bid.java
* Title: Bid
* Description: An auction bid
*/

import java.sql.Timestamp;
public class Bid {
 private Integer id;
 private Integer auctionId;
 private Integer bidderId;
 private Timestamp dateTimeSubmitted;
 private Double amount;
 private String transactionId;
 
 public Bid() {}
 
 public Bid(Integer newId, Integer newAuctionId,
   Integer newBidderId, Timestamp newDateTimeSubmitted,
   Double newAmount, String newTransactionId) {
  setId(newId);
  setAuctionId(newAuctionId);
  setBidderId(newBidderId);
  setDateTimeSubmitted(newDateTimeSubmitted);
  setAmount(newAmount);
  setTransactionId(newTransactionId);
 }
 public Integer getId() {
  return id;
 }
 
 protected void setId(Integer newId) {
  if (newId != null) {
   id = newId;
  }
  else {
   throw new IllegalArgumentException(„Bid nesmie byť null“);
  }
 }
 
 public Integer getAuctionId() {
  return auctionId;
 }
 
 public void setAuctionId(Integer newAuctionId) {
  if (newAuctionId != null) {
   auctionId = newAuctionId;
  }
  else {
   throw new IllegalArgumentException(„Bid nesmie byť null“);
  }
 }
 
 public Integer getBidderId() {
  return bidderId;
 }
 
 public void setBidderId(Integer newBidderId) {
  if (newBidderId != null) {
   bidderId = newBidderId;
  }
  else {
   throw new IllegalArgumentException(„Bid nesmie byť null“);
  }
 }
 
 public Timestamp getDateTimeSubmitted() {
  return dateTimeSubmitted;
 }
 
 public void setDateTimeSubmitted(Timestamp newDateTimeSubmitted) {
  if (newDateTimeSubmitted != null) {
   dateTimeSubmitted = newDateTimeSubmitted;
  }
  else {
   throw new IllegalArgumentException(„Bid nesmie byť null“);
  }
 }
 
 public Double getAmount() {
  return amount;
 }
 public void setAmount(Double newAmount) {
  if((newAmount != null)&&(newAmount.doubleValue() >= 0.0)) {
   amount = newAmount;
  }
  else {
   throw new IllegalArgumentException(
    „Bid nesmie byť null alebo záporné číslo“);
  }
 }
 
 public String getTransactionId() {
  return transactionId;
 }
 
 public void setTransactionId(String newTransactionId) {
  if (newTransactionId != null) {
   transactionId = newTransactionId;
  }
  else {
   throw new IllegalArgumentException(„Bid nesmie byť null“);
  }
 }
 
 public BidView getView() {
  BidView view = new BidView(getAuctionId(), getBidderId(),
   getDateTimeSubmitted(), getAmount(), getTransactionId());
  return view;
 }
}

Ako môžete vidieť, najkomplikovanejšou časťou ejbStore pre aukčnú entitu je kontrola null hodnôt jej jednotlivých atribútov a potom ešte volanie vhodných metód objektu PreparedStatement.

Problémom tejto jednoduchej implementácie metódy ejbStore je to, že nie je veľmi efektívna. Pretože zapisuje do databázy vždy, keď je zavolaná, a vždy zapisuje všetky atribúty, bez ohľadu na to, či sa zmenili alebo nie. V niektorom z budúcich článkov si ukážeme, ako tento výkonnostný problém riešiť.

Žádný příspěvek v diskuzi

Odpovědět