【问题标题】:initializing a database connection object once and reusing it - jboss一次初始化数据库连接对象并重用它 - jboss
【发布时间】:2012-05-15 10:04:17
【问题描述】:

我使用 jboss 服务器和 postgresql 作为数据库。现在我每次都在 servlet 中连接到数据库,如下所示:

public void doPost(HttpServletRequest req, HttpServletResponse resp)
{
Connection conn =null; // Create connection object
             String database = "jbossdb"; // Name of database
             String user = "qwerty"; //
             String password = "qwerty";
             String url = "jdbc:postgresql://localhost:5432/" + database;
             ResultSet rs = null;
             ResultSetMetaData rsm = null;
             ObjectInputStream in=new ObjectInputStream(req.getInputStream());
             String input=(String) in.readObject();
             String[] s_input=input.split(",");

              try{
                    Class.forName("org.postgresql.Driver").newInstance();
                    //.newInstance()
                 } catch(Exception e) 
                    {
                    System.err.println(e);
                    }

            try{
                conn = DriverManager.getConnection(url, user, password);

                }catch(SQLException se) 
                 {
                        System.err.println(se);
                 }

此代码存在于我的每个服务器中。对于每个请求,都会创建一个新的连接对象。这会影响性能吗?在 jboss 中有什么方法可以只初始化一次连接(可能在启动时),然后在需要时传递给 servlet?我应该把它放在servlet的init()方法中吗?

【问题讨论】:

    标签: java servlets jboss


    【解决方案1】:

    您在这里可能不是一个好的解决方案。当您使用 servlet 来执行应用程序加载的操作时,您可以拥有侦听器。你要做的是,首先创建一个实现ServletContextListener的类。

    public class ContextListener implements ServletContextListener {
    
        public void contextInitialized(ServletContextEvent sce) {
            ServletContext context=sce.getServletContext();
            String dburl=context.getInitParameter("dbUrl");
            String dbusername=context.getInitParameter("dbUserName");
            String dbpassword=context.getInitParameter("dbPassword");
            
            DBConnector.createConnection(dburl, dbusername, dbpassword);
            System.out.println("Connection Establised.........");
        }
    
        public void contextDestroyed(ServletContextEvent sce) {
            DBConnector.closeConnection();
        }
        
    }
    

    之后,您可以创建另一个类来在应用程序加载时创建连接。

    public class DBConnector {
        
        private static Connection con;
        
        public static void createConnection(String dbUrl,String dbusername,String dbPassword){
            try {
                Class.forName("org.postgresql.Driver");
                con=DriverManager.getConnection(dbUrl, dbusername, dbPassword);     
            } catch (Exception ex) {
                ex.printStackTrace();
            }    
        }
        
        public static Connection getConnection(){
            return con;
        }
        
        public static void closeConnection(){
            if(con!=null){
                try {
                    con.close();
                } catch (SQLException ex) {
                     ex.printStackTrace();
                }
            }
        
        }
        
        
        
    }
    

    然后,当您想要获取数据库连接时,您可以调用静态 getConnection 方法并获取它。 为了调用你的监听器类,你必须在 web.xml 中添加监听器标签。

    <context-param>
        <param-name>dbUrl</param-name>
        <param-value>jdbc:postgresql://localhost:5432/jbossdb</param-value>
    </context-param>
    <context-param>
        <param-name>dbUserName</param-name>
        <param-value>qwerty</param-value>
    </context-param>
    <context-param>
        <param-name>dbPassword</param-name>
        <param-value>qwerty</param-value>
    </context-param>
    <listener>
        <listener-class>com.icbt.bookstore.listener.ContextListener</listener-class>
    </listener>
    

    硬编码您的数据库用户名和密码不是一个好习惯。相反,您可以在 web.xml 中使用 servlet 初始化参数,如图所示。

    希望,这回答了你的问题。

    【讨论】:

    • 很好的答案!我不知道这些可以做到。你能给我一个链接,我可以在其中了解更多关于可以放入 web.xml 文件的内容。还有一个问题 - 请参阅我对 Jaydee 回答的评论
    • shop.oreilly.com/product/9780596516680.do 这是一本很好的书,你可以学习 servlet 和 jsps。如果您想了解 web.xml 标签,请阅读 docs.oracle.com/cd/E13222_01/wls/docs81/webapp/web_xml.html
    • 这取决于您的应用程序的大小。如果您有很多数据库操作,那么您将不得不使用@Jaydee 解释的数据库连接池。
    • 是的,可以做到。但是您不想将凭据放在 web.xml 中,而是可以使用领域(JDBC/内存)。无论如何,首先您应该了解身份验证和授权在 servlet 和 jsps 中是如何工作的。作为评论,我无法发布如何做到这一点。如果你真的想知道你可以开始一个新的问题,如果没有任何相关的问题已经
    • 既然您提出了一个单独的问题,我已将其发布在 stackoverflow.com/questions/10612231/… 。已经有两个人给出了答案。但不是解释。
    【解决方案2】:

    一个更好的方法是使用连接池。您还需要确保正确关闭连接(如果发生这种情况,您的代码尚不清楚,仍然需要使用池来完成)。至于存储连接,这并不是一个好主意,因为您的 servlet 是多线程的(我很难学到这一点),并且您需要同步所有访问,这将是一场灾难。

    http://geekexplains.blogspot.co.uk/2008/06/what-is-connection-pooling-why-do-we.html

    http://confluence.atlassian.com/display/DOC/Configuring+a+PostgreSQL+Datasource+in+Apache+Tomcat

    http://www.devdaily.com/blog/post/java/how-configure-tomcat-dbcp-connection-pool-pooling-postgres

    --编辑-- 为什么不在“init()”中做呢?

    了解“servlet 的生命周期”。

    init() 仅在容器设置 servlet 时调用一次。

    每个请求都使用相同的 servlet,而不是每个请求的新实例。所以 init() 不会被请求调用。

    由于每个请求都由同一个 servlet 实例处理,因此您的代码需要是多线程的。

    【讨论】:

    • 这可以做到吗 - 在 servlet 的 init() 方法中创建一个结果集作为 SCROLL_SENSITIVE 和 CONCUR_UPDATABLE。 servlet 中不会进行任何删除。只是检查表中是否存在特定条目。 SCROLL_SENSITIVE 将确保所做的任何更新也将反映在结果集中。这个想法有什么问题?
    • @Jaydee : init() 方法只会被调用一次。但是在init中创建了一个结果集对象
    • 您可以这样做,然后将值保存到变量中。
    • @Jaydee :我没有得到你。您是说我在 init 中使用 SCROLL_SENSITIVE 和 CONCUR_UPDATABLE 属性创建结果集。并在 init 本身中执行查询。然后将init结果集赋值给本地结果集对象并使用?
    • 您必须记住,对结果集的任何访问都需要考虑到 servlet 的多线程特性。因此,如果结果集在线程中更新,则每个线程需要一个单独的实例。如果它没有在线程中更新,您也可以在 init() 中执行它并分配给整个系统可访问的对象。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-14
    相关资源
    最近更新 更多