使用Servlet/JSP执行CRUD操作



我使用Servlet和JSP执行CRUD操作。以下类用于从服务器(Tomcat)维护的连接池中检索连接。

public final class DatabaseConnection {
private static final DataSource dataSource;
static {
try {
Context initContext = new InitialContext();
Context context = (Context) initContext.lookup("java:/comp/env");
dataSource = (DataSource) context.lookup("jdbc/assignment_db");
} catch (NamingException e) {
Logger.getLogger(DatabaseConnection.class.getName()).log(Level.SEVERE, null, e);
throw new ExceptionInInitializerError("DataSource not initialized.");
}
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}

下面的类(DAO)中的方法执行CRUD操作。

public final class CountryDao {
public Long getCurrentRow(Long id) throws SQLException {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = DatabaseConnection.getConnection();
preparedStatement = connection.prepareStatement("select rownum from (select @rownum:=@rownum+1 as rownum, tbl.country_id from country_tbl tbl, (select @rownum:=0)t order by tbl.country_id desc)t where country_id=?");
preparedStatement.setLong(1, id);
resultSet = preparedStatement.executeQuery();
return resultSet.next() ? resultSet.getLong("rownum") : 1;
} finally {
if (connection != null) {connection.close();}
if (resultSet != null) {resultSet.close();}
if (preparedStatement != null) {preparedStatement.close();}
}
}
public Long rowCount() throws SQLException {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = DatabaseConnection.getConnection();
preparedStatement = connection.prepareStatement("select count(*) as cnt from country_tbl");
resultSet = preparedStatement.executeQuery();
resultSet.next();
return resultSet.getLong("cnt");
} finally {
if (connection != null) {connection.close();}
if (resultSet != null) {resultSet.close();}
if (preparedStatement != null) {preparedStatement.close();}
}
}
public List<CountryBean> getData(Long currentPage, Long pageSize) throws SQLException {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
List<CountryBean> countryBeans = new ArrayList<CountryBean>();
try {
connection = DatabaseConnection.getConnection();
preparedStatement = connection.prepareStatement("select * from country_tbl order by country_id desc limit ?,?");
//preparedStatement.setMaxRows(pageSize);
preparedStatement.setLong(1, currentPage);
preparedStatement.setLong(2, pageSize);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
CountryBean countryBean = new CountryBean();
countryBean.setCountryId(resultSet.getLong("country_id"));
countryBean.setCountryName(resultSet.getString("country_name"));
countryBean.setCountryCode(resultSet.getString("country_code"));
countryBeans.add(countryBean);
}
} finally {
if (connection != null) {connection.close();}
if (resultSet != null) {resultSet.close();}
if (preparedStatement != null) {preparedStatement.close();}
}
return countryBeans;
}
public boolean delete(Long id) throws SQLException {
boolean status = false;
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = DatabaseConnection.getConnection();
preparedStatement = connection.prepareStatement("delete from country_tbl where country_id=?");
preparedStatement.setLong(1, id);
if (preparedStatement.executeUpdate() == 1) {
status = true;
}
} finally {
if (connection != null) {connection.close();}
if (preparedStatement != null) {preparedStatement.close();}
}
return status;
}
public boolean delete(Long[] ids) throws SQLException {
boolean status = false;
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = DatabaseConnection.getConnection();
connection.setAutoCommit(false);
preparedStatement = connection.prepareStatement("delete from country_tbl where country_id=?");
int len = ids.length;
for (int i = 0; i < len; i++) {
preparedStatement.setLong(1, ids[i]);
preparedStatement.addBatch();
}
preparedStatement.executeBatch();
connection.commit();
status = true;
} finally {
if (connection != null) {connection.close();}
if (preparedStatement != null) {preparedStatement.close();}
}
return status;
}
public boolean insert(String countryName, String countryCode) throws SQLException {
boolean status = false;
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = DatabaseConnection.getConnection();
preparedStatement = connection.prepareStatement("insert into country_tbl(country_name, country_code)values(?,?)");
preparedStatement.setString(1, countryName);
preparedStatement.setString(2, countryCode);
preparedStatement.executeUpdate();
status = true;
} finally {
if (connection != null) {connection.close();}
if (preparedStatement != null) {preparedStatement.close();}
}
return status;
}
public boolean update(Long countryId, String countryName, String countryCode) throws SQLException {
boolean status = false;
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
connection = DatabaseConnection.getConnection();
preparedStatement = connection.prepareStatement("update country_tbl set country_name=?, country_code=? where country_id=?");
preparedStatement.setString(1, countryName);
preparedStatement.setString(2, countryCode);
preparedStatement.setLong(3, countryId);
preparedStatement.executeUpdate();
status = true;
} finally {
if (connection != null) {connection.close();}
if (preparedStatement != null) {preparedStatement.close();}
}
return status;
}
}

在执行验证之后,这些方法会从Servlet中适当地调用。Servlet反过来与JSP(以及JSTL/EL)交互。

只有一个问题。通常,connectionpreparedStatementresultSet都是特定方法的局部变量

我可以只在一个地方将它们声明为类成员(实例变量)吗?这样做能准确地保持一致的状态吗?

没有必要过于关注核心逻辑。请不要只是说,最好使用MVC框架:)

我可以只在一个地方将它们声明为类成员(实例变量)吗

您可以这样做,但该类将是线程不安全的。调用程序无法在多个线程中重用同一实例,而不会干扰由不一致状态引起的每个单独方法的行为。在servlet作为调用者的情况下,这样就不能在servlet的init()中只创建一次实例,并在doXxx()方法中多次重用它。您将被迫在threadlocal作用域中重新创建实例(因此,在doXxx()方法内部)。这应该清楚地记录在类"javadoc"中。但是,毕竟,设计一个线程不安全的DAO类是没有意义的。坚持当前的设计(或者,如果你不只是在闲逛,可以改用JPA;)。


这样做能准确地保持一致的状态吗

不!相反,这是不一致的。不能在多个查询中共享同一个语句或结果集。每个查询都应该有自己的语句和结果集。实例上的每个方法调用都会更改实例变量,导致其他仍在运行的方法调用处于损坏状态。共享连接是可能的,但此作业通常已由连接池完成。假设您正在使用一个数据源,那么您很可能已经有了一个。


也就是说,如果你讨厌重复的代码样板,但真的想坚持使用好的"ol JDBC API",那么看看Execute Around模式/习惯用法和/或Java 7的自动资源管理(ARM)。这样,就必须能够创建一个带有一堆接口的helper DB类,并最终得到一个通用的抽象基DAO类,该类的方法只接受SQL查询和参数值(如果有的话)。

不能将这些变量声明为实例变量。因为这可能在某些情况下导致错误。

E.g-

如果在同一个对象上调用此类的两个方法。一种方法执行需要两分钟,另一种方法需要5分钟在这种情况下,第一个方法关闭连接,第二个方法抛出异常。还有许多其他原因。。。

当然,只要在两个或多个不同的线程中不共享相同的对象,就可以使用连接、语句和结果集作为成员变量。

在servlet中,您将创建dao的一个对象,因此每次servlet被命中时,都会启动一个新线程,这个新线程将创建一个dao的新对象来执行一些方法。

唯一可能失败的情况是,在servlet中,您正在创建一个dao对象,并将同一对象传递给您手动创建的两个不同线程,以执行两个方法。在这种情况下,可能一个线程正在读取结果集中的所有记录,但就在同一时间,另一个线程执行get查询并试图重置结果集,这将导致异常。

更有趣的是,正如@Manjeet所说,第一个线程仍然在从结果集中读取数据,而第二个线程刚刚关闭了连接。但他忘了提到,只有当你创建两个线程时,才会发生这种情况。若要在同一个线程中执行两个方法,那个么它肯定是一个接一个的。因为没有其他方法可以在不创建两个线程的情况下同时执行两个方法。

然而,如果您的意图只是删除样板代码,那么您还有其他几种方法。您可以创建一个名为样板的类,如

class Boilerplate{
private Connection con;
private PreparedStatement ps;
public Boilerplate(String query){
//initialize connection, ps and resultset
con=DatabaseConnection.getConnection();
ps=connection.prepareStatement(query);
}
destroy void Boilerplate(){
if(con!=null)
con.close()
if(ps!=null)
ps.close();
}
}

然后让它的一个实例来完成您的工作,并调用它的destroy方法。

一般事项:

了解术语很重要。实例变量和类变量都是成员变量。它们都是成员变量,因为它们都与特定的类相关联。但是,实例变量和类变量之间存在差异。

实例变量

实例变量属于一个类的实例。另一种说法是实例变量属于对象,因为对象是类的实例。每个对象都有自己的实例变量副本。以下是实例变量的声明:

实例变量

class Taxes
{
int count;
/*...*/
}

类变量

class Taxes
{
static int count;
/*...*/
}
res.setContentType("text/html");
// Ask for a 16K byte response buffer; do not set the content length
res.setBufferSize(16 * 1024);
PrintWriter out = res.getWriter();
out.println("<HTML>");
out.println("<HEAD><TITLE>Hello World</TITLE></HEAD>");
out.println("<BODY>");
out.println("<BIG>Less than 16K of response body</BIG>");
out.println("</BODY></HTML>");

我使用您的示例,并希望创建一个连接。但当我使用junit测试它时,它显示了一个NoInitialContextException。我该如何修复它?下面是我的代码。

public final class DataSourceUtil {                     
private static Context initCtx;
private static Context envCtx; 
private static DataSource dataSource;                 
static {
try {                                               
// Initial a datasource for pooled connections.    
initCtx = new InitialContext();                   
envCtx = (Context) initCtx.lookup("java:/comp/env");     
dataSource = (DataSource) envCtx.lookup("jdbc/ServletDB");                                                 
} catch (NamingException e) {                       
Logger.getLogger(DataSourceUtil.class.getName()).log(Level.SEVERE, null, e);                               
throw new ExceptionInInitializerError("DataSource not initialized.");
}                                                   
}                                           
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}

测试代码

public class ConnectionTest() {
@Test
public void connectionTest2() {
try {
Connection connection = DataSourceUtil.getConnection();
} catch (Exception e) {e.printStackTrace();}
}

以及错误消息:

Dec 23, 2015 9:06:46 PM com.wxz.server.dao.DataSourceUtil <clinit>
SEVERE: null
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial

您可以使用这个java类创建对象,并分别调用这个st、con和rs

{
import java.sql.*;
public class connectDb {
public Statement st;
public Connection con;
public ResultSet rs;
public ResultSet rs1;
public Statement st1;
public connectDb() {
try {
String driver="com.mysql.jdbc.Driver";
String url="jdbc:mysql://localhost:3306/test1db";
String username="root";
String password="";
Class.forName(driver);

Connection con=DriverManager.getConnection(url,username,password);
System.out.println("connected to database");
st=con.createStatement();
st1=con.createStatement();

}catch(Exception e) {
System.out.println("ERROR" +e);
}
}
}
}
FlightHandler.java
package com.trainee.handler;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.trainee.dao.FlightDao;
import com.trainee.flight.Flight;
public class FlightHandler extends HttpServlet {
private static String INSERT = "/user.jsp";
private static String Edit = "/edit.jsp";
private static String FlightRecord = "/listFlight.jsp";
private FlightDao dao;
public FlightHandler() {
super();
dao = new FlightDao();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String redirect="";
String Id = request.getParameter("id"); 
String TotalSeat =  request.getParameter("totalseat");
String action = request.getParameter("action");
if(!((Id)== null) && action.equalsIgnoreCase("insert"))
{
int id = Integer.parseInt(Id);
Flight f = new Flight();
f.setId(id);
f.setName(request.getParameter("name"));
int totalseat = Integer.parseInt(TotalSeat);
f.setTotalSeat(totalseat);
f.setCity(request.getParameter("city"));
f.setStatus(request.getParameter("status"));
dao.addFlight(f);
redirect = FlightRecord;
request.setAttribute("users", dao.getAllFlight());    
System.out.println("Record Added Successfully");
}

else if (action.equalsIgnoreCase("delete")){
String id = request.getParameter("flightId");
int fid = Integer.parseInt(id);
dao.removeFlight(fid);
redirect = FlightRecord;
request.setAttribute("users", dao.getAllFlight());
System.out.println("Record Deleted Successfully");
}
else if (action.equalsIgnoreCase("editform")){          
redirect = Edit;            
} else if (action.equalsIgnoreCase("edit")){
String fId = request.getParameter("flightId");
int id = Integer.parseInt(fId);            
Flight f = new Flight();
f.setId(id);
f.setCity(request.getParameter("city"));
dao.editFlight(f);
request.setAttribute("user", f);
redirect = FlightRecord;
System.out.println("Record updated Successfully");
}
else if (action.equalsIgnoreCase("listFlight")){
redirect = FlightRecord;
request.setAttribute("users", dao.getAllFlight());
} else {
redirect = INSERT;
}
RequestDispatcher rd = request.getRequestDispatcher(redirect);
rd.forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}

最新更新