在JSF中构建简单的事务



我是Java和JSF的新手,不知道如何构建事务。我有一个很好的理解,但似乎我不能让我的webApp运行一个请求不止一次没有错误:

WARNING: javax.el.ELException: /accounts.xhtml @38,125 value="#{login.accounts}": Error reading 'accounts' on type edu.pcc.cis234j.assign08.LoginBean
Caused by: javax.el.ELException: Error reading 'accounts' on type edu.pcc.cis234j.assign08.LoginBean
SEVERE: org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object
Caused by: java.util.NoSuchElementException: Timeout waiting for idle object

所以当我第一次登录时,一切都显示良好,但似乎如果我执行LoginBean.getAccounts不止一次(单击accounts.xhtml中的Transfer按钮),这个错误抛出。当我尝试运行TransferBean.execute函数时,就会出现这个问题,所以我为这个方法写了一个简单的测试,直到我能弄清楚这里发生了什么。我使用的是Eclipse、Apache Tomcat 7、带数据源连接的MySQL和JSF2。我的最后一步是让我的管理bean设置为@SessionScoped,因为传输功能将结果在多个HTTP请求,我想保留登录信息,我认为这会解决我的问题,但现在我卡住了!有些事我不明白。提前感谢您的帮助:-).

LoginBean.Java:

@ManagedBean(name = "login")
@SessionScoped
public class LoginBean implements Serializable {
    private static final long serialVersionUID = 1L;
    private String userName = null;
    private String pwd = null;
    private int uId = 0;
    private List<Account> accounts;
    private DatabaseManager manager;
    public LoginBean() {
        manager = new DatabaseManager();
    }
    public String getUsername() {
        return userName;
    }
    public String getPassword() {
        return pwd;
    }
    public void setUsername(String userName) {
        this.userName = userName;
    }
    public void setPassword(String pwd) {
        this.pwd = pwd;
    }
    public void setUserId(int uId) {
        this.uId = uId;
    }   
    public List<Account> getAccounts() throws Exception {
          accounts = new ArrayList<Account>();
          String sql = "SELECT * FROM accounts WHERE UserId IN ( SELECT UserId FROM users WHERE UserName = '" + userName + "' )";
          ResultSet rs = manager.executeQuery(sql);
          while(rs.next()) {
              accounts.add( new Account(rs.getInt("AccountId"), rs.getString("AccountName"), rs.getFloat("LastDeposit"), rs.getFloat("Balance")) );  
          }
          return accounts;
    }
}

TransferBean.java

@ManagedBean(name = "transfer")
@SessionScoped
public class TransferBean implements Serializable {
    private static final long serialVersionUID = 1L;
    private int sourceId;
    private int destinationId;
    private float amount;
    public TransferBean() {}
    public int getSourceId() {
        return sourceId;
    }
    public int getDestinationId() { 
        return destinationId;
    }
    public float getAmount() {
        return amount;  
    }
    public void setSourceId(int sourceId) {
        this.sourceId = sourceId;
    }
    public void setDestinationId(int destinationId) {
        this.destinationId = destinationId;
    }
    public void setAmount(float amount) {
        this.amount = amount;
    }
    // TEST METHOD - will envoke DatabaseManager.executeTransaction
    public void execute() throws Exception {        
        System.out.print("execute method rannsourceId: " +sourceId + "ndestinationId: " + destinationId + "namount: " + amount + "n");
    }
}

DatabaseManager.java:

public class DatabaseManager {
    private int rowsAffected;
    public DatabaseManager() {}
    public ResultSet executeQuery(String sql) throws Exception {
        ResultSet result = null;
        CachedRowSetImpl cachedResult = null;
        try {
            result = getConnection().createStatement().executeQuery(sql);
            cachedResult = new CachedRowSetImpl();
            cachedResult.populate(result);
        } catch (SQLException e) {
            System.err.println("ERROR: " + e.getMessage());
            e.printStackTrace();
        } finally {
            closeConnection(getConnection());
        }
        return cachedResult;
    }
    public int executeUpdate(String sql) throws Exception {
        try {
            rowsAffected = getConnection().createStatement().executeUpdate(sql);
        } catch (SQLException e) {
            System.err.println("ERROR: " + e.getMessage());
            e.printStackTrace();
        } finally {
            closeConnection(getConnection());
        }
        return rowsAffected;
    }
    public Connection getConnection() throws Exception {    
        Context context = new InitialContext();
        DataSource source = (DataSource)context.lookup("java:comp/env/jdbc/cis234j");
        return source.getConnection();
    }
    private void closeConnection(Connection connection) {
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {}
        }
    }
    public int executeTransaction(String[] sqls) throws Exception {
        int rowCount = 0;
        Connection con = getConnection();
        try {
            con.setAutoCommit(false);
            for(String sql : sqls) {
                con.createStatement().executeUpdate(sql);
            }       
            con.commit();
        } catch (Exception e) {
            con.rollback();
        }
        return rowCount;
    }
}

java:会

public class Account {
  private int id;
  private String name;
  private float lastDeposit;
  private float balance;
  private DatabaseManager manager;
  public Account(int id, String name, float lastDeposit, float balance) {
      this.id = id;
      this.name = name;
      this.lastDeposit = lastDeposit;
      this.balance = balance;
      manager = new DatabaseManager();
  }
  public int getId() {
      return id;
  }
  public String getName() {
      return name;
  }
  public float getLastDeposit() {
      return lastDeposit;
  }
  public float getBalance() {
      return balance;
  }
  public void setId(int id) {
      this.id = id;
  }
  public void setName(String name) {
      this.name = name;
  }
  public void setLastDeposit(float lastDeposit) {
      this.lastDeposit = lastDeposit;
  }
  public void setBalance(float balance) {
      this.balance = balance;
  }
  public void deposit(float amount) throws Exception {
      manager.executeUpdate("UPDATE accounts"
              + "               SET   LastDeposit = " + amount + ","
              + "                     Balance = " + (getBalance() + amount)
              + "             WHERE AccountId = " + id);
  }
  public void withdraw(float amount) throws Exception {
      deposit(-amount);
  }
}

login.xhtml:

<div class="wrapper">
<h:form>
    <div class="login">
        <h:outputLabel class="label" value="User Name" />
        <h:inputText id="user_id" title="User Name" value="#{login.username}" /> 
        <h:outputText value="&lt;br/&gt;" escape="false" /> 
        <h:outputText value="&lt;br/&gt;" escape="false" />
        <h:outputLabel class="label" value="Password" />
        <h:inputSecret id="password" title="Password" value="#{login.password}" />
        <h:outputText value="&lt;br/&gt;" escape="false" />
        <h:outputText value="&lt;br/&gt;" escape="false" />
        <h:commandButton id="login" value="Login" action="accounts" />
    </div>
</h:form>
</div><!-- .wrapper -->

accounts.xhtml:

<div class="wrapper">
<h2><h:outputText value="Hello, " />#{login.username}!</h2>
<h3><h:outputText value="Here is your PCC bank account information:" /></h3>
<h3>TEST - Here is your set Password: #{login.password}</h3>
<h:dataTable class="account-table" value="#{login.accounts}" var="act" border="3" width="100%">
    <h:column>
        <f:facet name="header">Account ID</f:facet>
        #{act.id}
    </h:column>
    <h:column>
        <f:facet name="header">Account Name</f:facet>
        #{act.name}
    </h:column>
    <h:column>
        <f:facet name="header">Last Deposit</f:facet>
        $#{act.lastDeposit}
    </h:column>
    <h:column>
        <f:facet name="header">Current Balance</f:facet>
        $#{act.balance}
    </h:column>
</h:dataTable>
<br />
<h:form class="trans-form">
     <h3>Transfer Money:</h3> 
     <div class="trans-cont">         
         <h:outputLabel class="label" value="From:" />
         <h:selectOneMenu class="select-menu float-r" value="#{transfer.sourceId}" converter="omnifaces.SelectItemsConverter">
            <f:selectItem itemLabel="Choose Account" noSelectionOption="false" />
            <f:selectItems value="#{login.accounts}" var="act" itemLabel="#{act.id} - #{act.name}" itemValue="#{act.id}" />     
         </h:selectOneMenu>
     </div>
     <div class="trans-cont">         
         <h:outputLabel class="label" value="To:" />
         <h:selectOneMenu class="select-menu float-r" value="#{transfer.destinationId}" converter="omnifaces.SelectItemsConverter">
            <f:selectItem itemLabel="Choose Account" noSelectionOption="false" />
            <f:selectItems value="#{login.accounts}" var="act" itemLabel="#{act.id} - #{act.name}" itemValue="#{act.id}" />     
         </h:selectOneMenu>
     </div>
     <div class="trans-cont">
        <h:inputText id="user_id" title="User Name" value="#{transfer.amount}" /> 
     </div>
     <div class="trans-cont">   
         <h:commandButton class="btn pad10 float-r" value="Transfer Now" action="#{transfer.execute}">
            <f:ajax execute="@form" />
         </h:commandButton>         
     </div>
</h:form>
<br /><br />
<div class="btn-container">
    <h:outputLink value="login.xhtml">
        <input class="btn float-r" type="button" value="Logout" />
    </h:outputLink>
</div>
</div><!-- .wrapper  -->

web . xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>assign08</display-name>
<welcome-file-list>
  <welcome-file>login.jsf</welcome-file>
</welcome-file-list>
<servlet>
  <servlet-name>Faces Servlet</servlet-name>
  <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>Faces Servlet</servlet-name>    
    <!-- tomcat -->
    <!-- <url-pattern>*.jsf</url-pattern> -->
    <!-- eclipse -->    
    <url-pattern>*.xhtml</url-pattern>  
</servlet-mapping>
<context-param>
  <param-name>javax.faces.PROJECT_STAGE</param-name>
  <param-value>Development</param-value>
</context-param>
<context-param>
  <description>State saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description>
  <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
  <param-value>client</param-value>
</context-param>
<context-param>
  <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
  <param-value>resources.application</param-value>
</context-param>
<!-- Resource Reference  -->
<resource-ref>
<res-ref-name>jdbc/cis234j</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<listener>
  <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
</web-app>

context.xml

<context>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<Resource name="jdbc/cis234j" 
          auth="Container" 
          type="javax.sql.DataSource" 
          maxActive="8" 
          maxIdle="3" 
          maxWait="1000" 
          username="student" 
          password="pencil1" 
          driverClassName="com.mysql.jdbc.Driver" 
          url="jdbc:mysql://localhost/cis234j" />
</context>

这个bug是在finally块@ close(getConnection())DatabaseManager.java中。

DatabaseManager.java

public ResultSet executeQuery(String sql) throws Exception {
    ResultSet result = null;
    CachedRowSetImpl cachedResult = null;
    Connection con = getConnection();
    try {
        result = con.createStatement().executeQuery(sql);
        cachedResult = new CachedRowSetImpl();
        cachedResult.populate(result);
        return cachedResult;
    } catch (SQLException e) {
        System.err.println("ERROR: " + e.getMessage());
        e.printStackTrace();
    } finally {
        closeConnection(con);
    }
    return cachedResult;
}

相关内容

  • 没有找到相关文章

最新更新