java - 在 JSF 中构建简单的事务

标签 java mysql jsf tomcat jsf-2

我是 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 中的“传输”按钮),则会抛出此错误。当我尝试运行 TransferBean.execute 函数时会出现此问题,因此我为此方法编写了一个简单的测试,直到我弄清楚这里发生了什么。我正在使用 Eclipse、Apache Tomcat 7、带有 DataSource 连接的 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 ran\nsourceId: " +sourceId + "\ndestinationId: " + destinationId + "\namount: " + amount + "\n");
    }
}

数据库管理器.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);
  }

}

登录.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>

最佳答案

错误出现在 DatabaseManager.javafinally block @ close(getConnection()) 中。这是修复。

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;
}

关于java - 在 JSF 中构建简单的事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23851416/

相关文章:

php - 为什么我不能将 php time() 用于时间戳列?

mysql - 创建基于多列值计算总值的 View 表

java - 使用 JMeter 测试 JSF 时提取 ViewState

java - EJB 检索重复行

jsf - 用于链接/导航到其他 JSF 页面的 URL

java - Jackson 循环依赖只是通过深度而不是同时通过深度和广度

java - 如何让 StringTemplate V4 忽略 < 作为分隔符?

java - 使用DatatypeConverter.parseBase64Binary的异常

java - Maven Plugin子模块的集成测试

php - 如何检查 mysqli_query 是否删除了任何行