我正在使用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)交互。
只有一个问题。 Curretly,connection
,preparedStatement
和resultSet
都是特定方法的局部变量。
我可以只在一个地方声明它们作为类成员(实例变量)吗?这样做能保持一致的状态吗?
不需要太多关注核心逻辑。请不要说,最好使用MVC框架:)
答案 0 :(得分:3)
我可以只在一个地方声明它们作为类成员(实例变量)吗?
你可以这样做,但是这个类是线程安全的。调用者不能跨多个线程重用相同的实例,而不会干扰由不一致状态引起的每个单独方法的行为。如果servlet作为调用者,这样您就无法在servlet的init()
中只创建一次实例,并在doXxx()
方法中多次重用它。您将被迫在threadlocal范围内重新创建实例(因此,在doXxx()
方法内)。这应该在类'javadoc中清楚地记录下来。但是,毕竟设计一个threadunsafe DAO类没有意义。坚持当前的设计(或者,如果你不只是徘徊,切换到JPA;))。
这样可以保持一致的状态吗?
没有!相反,它会不一致。您不能跨多个查询共享同一个语句或结果集。每个查询都应该有自己的语句和结果集。对实例的每个方法调用都会更改实例变量,导致其他仍在运行的方法调用在损坏的状态下工作。可以共享连接,但此作业通常已由连接池完成。鉴于您正在使用数据源,您很可能已经拥有了数据源。
那就是说,如果你讨厌重复的代码样板,但是真的想要坚持使用好的JDBC API,请查看Execute Around pattern/idiom和/或Java 7's automatic resource management (ARM)。有了这个,就必须能够创建一个带有一堆接口的辅助DB类,最后得到一个通用的抽象基类DAO类,它的方法只接受SQL查询和参数值-if any。
答案 1 :(得分:1)
您不能将这些变量声明为实例变量。 因为这可能会在某些情况下导致错误。
E.g -
如果在同一个对象上调用此类的两个方法。 一种方法需要两分钟才能执行,另一种方法需要5分钟 在这种情况下,第一个方法关闭连接,第二个方法抛出异常。 还有很多其他原因......
答案 2 :(得分:1)
当然,只要您不在两个或多个不同的线程中共享相同的对象,就可以使用connection,statement和resultset作为成员变量。
在servlet中你将创建一个dao的对象,所以每次命中servlet时都会启动一个新线程,这个新线程将创建一个dao的新对象来执行某些方法。
只有在它可以失败的情况下,你正在创建一个dao对象的servlet中,并将这个相同的对象传递给你手动创建的两个不同的线程来执行两个方法。在这种情况下,一个线程可能正在读取结果集中的所有记录,但同时其他线程执行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();
}
}
然后得到它的一个实例做你的工作并称之为破坏方法。
答案 3 :(得分:1)
答案 4 :(得分:1)
一般事项:
了解术语很重要。实例变量和类变量都是成员变量。它们都是成员变量,因为它们都与特定类相关联。但是,实例变量和类变量之间存在差异。
实例变量
实例变量属于类的实例。另一种说法是instance variables属于一个对象,因为一个对象是一个类的实例。每个对象都有自己的实例变量副本。以下是实例变量的声明:
实例变量
class Taxes
{
int count;
/*...*/
}
类变量
class Taxes
{
static int count;
/*...*/
}
答案 5 :(得分:0)
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>");
答案 6 :(得分:0)
我使用您的示例并想要创建连接。但是当我使用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
答案 7 :(得分:0)
您可以使用此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);
}
}
}
}
答案 8 :(得分:-1)
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);
}
}