Posts Tagged ‘ database

解决Jsp插入Mysql,设置UTF8依然乱码问题

问题描述:
JSP网页里是charset=UTF-8: 

<%@ page contentType= “text/html; charset=UTF-8 ” language= “java ” import= “java.sql.* ” errorPage= “error.jsp ” %> 

Mysql5里存取的数据库的charset也设成了UTF-8,可是通过JSP网页存取中文还是显示乱码 

解决方案:加个过滤类 

package com.bx.util; 

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; 

public class SetEncodingFilter implements Filter { 

    // ----------------------------------------------------- Instance  Variables 

    /**
     * The default character encoding to set for requests that pass through this
     * filter.
     */
    protected String encoding = null; 

    /**
     * The filter configuration object we are associated with. If this value is
     * null, this filter instance is not currently configured.
     */
    protected FilterConfig filterConfig = null; 

    /**
     * Should a character encoding specified by the client be ignored?
     */
    protected boolean ignore = true; 

    // --------------------------------------------------------- Public Methods 

    /**
     * Take this filter out of service.
     */
    public void destroy() {
        this.encoding = null;
        this.filterConfig = null;
    } 

    /**
     * Select and set (if specified) the character encoding to be used to
     * interpret request parameters for this request.
     *
     * @param request
     * The servlet request we are processing
     * @param result
     * The servlet response we are creating
     * @param chain
     * The filter chain we are processing
     *
     * @exception IOException
     * if an input/output error occurs
     * @exception ServletException
     * if a servlet error occurs
     */
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        // Conditionally select and set the character encoding to be used
        if (ignore || (request.getCharacterEncoding() == null)) {
            String encoding = selectEncoding(request);
            if (encoding != null) {
                request.setCharacterEncoding(encoding);
            }
        } 

        // Pass control on to the next filter
        chain.doFilter(request, response);
    } 

    /**
     * Place this filter into service.
     *
     * @param filterConfig
     * The filter configuration object
     */
    public void init(FilterConfig filterConfig) throws ServletException { 

        this.filterConfig = filterConfig;
        this.encoding = filterConfig.getInitParameter("encoding");
        String value = filterConfig.getInitParameter("ignore");
        if (value == null) {
            this.ignore = true;
        } else if (value.equalsIgnoreCase("true")) {
            this.ignore = true;
        } else if (value.equalsIgnoreCase("yes")) {
           this.ignore = true;
        } else {
           this.ignore = false;
        }
    } 

    // ------------------------------------------------------ Protected Methods 

    /**
     * Select an appropriate character encoding to be used, based on the
     * characteristics of the current request and/or filter initialization
     * parameters. If no character encoding should be set, return
     * <code>null</code>.
     * <p>
     * The default implementation unconditionally returns the value configured
     * by the <strong>encoding</strong> initialization parameter for this
     * filter.
     *
     * @param request
     * The servlet request we are processing
     */
    protected String selectEncoding(ServletRequest request) {
        return (this.encoding);
    }
}

然后在web.xml文件中配置一下就可以了 

<filter>
    <filter-name>Set Character Encoding</filter-name>
    <filter-class>com.bx.util.SetEncodingFilter类的路径</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>Set Character Encoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

测试PreparedStatement的批处理效率

今天研究了一下Java中PreparedStatement的批处理能力.

测试环境如下:

jdk1.6.0_21 +Mysql 5.1

Core 2 Duo T5470 (1.60GHz) + 3G内存

测试的是实现最简单的插入:

INSERT INTO `testdb` (`id`, `value`) VALUES (123456, ‘http://www.pptv.com’)

共插入20万条数据, 每个测试前都把数据库清空, 然后执行插入, 从开始插入进行计时.每项测试跑3次取平均值.

分为两项测试: 1个是不使用批处理, 逐条插入; 一个是使用addBatch(), 分别按50, 100, 500, 1000, 5000, 10000, 50000, 100000的划分方式进行批量插入. 关键代码如下:

逐行插入:

for (int times = 0; times &lt; TEST_TIMES; times++) {
    cleanDB();
    conn = DBMgr.getDBconn(&quot;testdb&quot;);
    long starttime = System.currentTimeMillis();
    for (int i = 0; i &lt; MAX_COUNT; i++) {
        pstmt = conn.prepareStatement(SQL);
        pstmt.executeUpdate();
        pstmt.close();
        System.out.println(&quot;working: &quot; + i + &quot;/&quot; + MAX_COUNT);
    }
    long endtime = System.currentTimeMillis();
    LOG.info(&quot;第&quot; + (times + 1) + &quot;次测试, 耗时&quot; + (endtime - starttime) + &quot;ms&quot;);
    alltime += endtime - starttime;
}
LOG.info(&quot;平均耗时: &quot; + (alltime / TEST_TIMES) + &quot;ms&quot;);

批处理操作

for (int times = 0; times &lt; TEST_TIMES; times++) {
    cleanDB();
    conn = DBMgr.getDBconn(&quot;testdb&quot;);
    conn.setAutoCommit(false);
    int num = 0;
    long starttime = System.currentTimeMillis();
    pstmt = conn.prepareStatement(SQL);
    for (int i = 0; i &lt; MAX_COUNT; i++) {
        pstmt.addBatch();
        num++;
        if (num % count == 0 || num == MAX_COUNT) {
            pstmt.executeBatch();
            pstmt.clearBatch();
            pstmt.close();
            pstmt = conn.prepareStatement(SQL);
        }
        System.out.println(&quot;working: &quot; + i + &quot;/&quot; + MAX_COUNT);
    }
    long endtime = System.currentTimeMillis();
    LOG.info(&quot;第&quot; + (times + 1) + &quot;次测试, 耗时&quot; + (endtime - starttime) + &quot;ms&quot;);
    alltime += endtime - starttime;
}
LOG.info(&quot;平均耗时: &quot; + (alltime / TEST_TIMES) + &quot;ms&quot;);

记录的log如下:

11:59:25,703 DBTestMulti test  *** 以100000为一次批量操作, 执行批处理语句  ***
11:59:25,703 BaseDBTest cleanDB 初始化数据库
11:59:58,984 DBTestMulti test 第1次测试, 耗时33000ms
11:59:58,984 BaseDBTest cleanDB 初始化数据库
12:01:21,687 DBTestMulti test 第2次测试, 耗时32594ms
12:01:21,687 BaseDBTest cleanDB 初始化数据库
12:02:44,640 DBTestMulti test 第3次测试, 耗时32562ms
12:02:44,640 DBTestMulti test 平均耗时: 32718ms
12:02:47,093 DBTestMulti test  *** 以50000为一次批量操作, 执行批处理语句  ***
12:02:47,093 BaseDBTest cleanDB 初始化数据库
12:03:19,734 DBTestMulti test 第1次测试, 耗时32625ms
12:03:19,734 BaseDBTest cleanDB 初始化数据库
12:04:43,406 DBTestMulti test 第2次测试, 耗时33328ms
12:04:43,406 BaseDBTest cleanDB 初始化数据库
12:06:06,687 DBTestMulti test 第3次测试, 耗时32609ms
12:06:06,687 DBTestMulti test 平均耗时: 32854ms
12:06:09,125 DBTestMulti test  *** 以10000为一次批量操作, 执行批处理语句  ***
12:06:09,125 BaseDBTest cleanDB 初始化数据库
12:06:40,921 DBTestMulti test 第1次测试, 耗时31781ms
12:06:40,921 BaseDBTest cleanDB 初始化数据库
12:08:03,125 DBTestMulti test 第2次测试, 耗时32032ms
12:08:03,125 BaseDBTest cleanDB 初始化数据库
12:09:26,859 DBTestMulti test 第3次测试, 耗时32781ms
12:09:26,859 DBTestMulti test 平均耗时: 32198ms
12:09:29,296 DBTestMulti test  *** 以5000为一次批量操作, 执行批处理语句  ***
12:09:29,296 BaseDBTest cleanDB 初始化数据库
12:10:00,406 DBTestMulti test 第1次测试, 耗时31094ms
12:10:00,406 BaseDBTest cleanDB 初始化数据库
12:11:23,031 DBTestMulti test 第2次测试, 耗时31953ms
12:11:23,031 BaseDBTest cleanDB 初始化数据库
12:12:46,265 DBTestMulti test 第3次测试, 耗时32187ms
12:12:46,265 DBTestMulti test 平均耗时: 31744ms
12:12:48,718 DBTestMulti test  *** 以1000为一次批量操作, 执行批处理语句  ***
12:12:48,718 BaseDBTest cleanDB 初始化数据库
12:13:20,468 DBTestMulti test 第1次测试, 耗时31750ms
12:13:20,468 BaseDBTest cleanDB 初始化数据库
12:14:43,703 DBTestMulti test 第2次测试, 耗时32625ms
12:14:43,703 BaseDBTest cleanDB 初始化数据库
12:16:06,203 DBTestMulti test 第3次测试, 耗时32125ms
12:16:06,203 DBTestMulti test 平均耗时: 32166ms
12:16:08,656 DBTestMulti test  *** 以500为一次批量操作, 执行批处理语句  ***
12:16:08,656 BaseDBTest cleanDB 初始化数据库
12:16:40,906 DBTestMulti test 第1次测试, 耗时32235ms
12:16:40,906 BaseDBTest cleanDB 初始化数据库
12:18:03,625 DBTestMulti test 第2次测试, 耗时32547ms
12:18:03,625 BaseDBTest cleanDB 初始化数据库
12:19:27,343 DBTestMulti test 第3次测试, 耗时33265ms
12:19:27,343 DBTestMulti test 平均耗时: 32682ms
12:19:30,406 DBTestMulti test  *** 以100为一次批量操作, 执行批处理语句  ***
12:19:30,406 BaseDBTest cleanDB 初始化数据库
12:20:53,875 DBTestMulti test 第1次测试, 耗时32782ms
12:20:53,875 BaseDBTest cleanDB 初始化数据库
12:22:17,765 DBTestMulti test 第2次测试, 耗时33687ms
12:22:17,765 BaseDBTest cleanDB 初始化数据库
12:23:41,609 DBTestMulti test 第3次测试, 耗时33531ms
12:23:41,609 DBTestMulti test 平均耗时: 33333ms
12:23:44,421 DBTestMulti test  *** 以50为一次批量操作, 执行批处理语句  ***
12:23:44,421 BaseDBTest cleanDB 初始化数据库
12:25:07,578 DBTestMulti test 第1次测试, 耗时32500ms
12:25:07,578 BaseDBTest cleanDB 初始化数据库
12:26:31,796 DBTestMulti test 第2次测试, 耗时33718ms
12:26:31,796 BaseDBTest cleanDB 初始化数据库
12:27:55,640 DBTestMulti test 第3次测试, 耗时33562ms
12:27:55,640 DBTestMulti test 平均耗时: 33260ms
12:27:58,468 BaseDBTest cleanDB 初始化数据库
14:08:25,484 DBTestSingle test 第1次测试, 耗时5976406ms
14:08:25,484 BaseDBTest cleanDB 初始化数据库
15:47:18,828 DBTestSingle test 第2次测试, 耗时5882735ms
15:47:18,828 BaseDBTest cleanDB 初始化数据库

其中批处理都是执行3次取平均值, 而逐行操作, 一次执行时间就要1个半小时, 所以只跑了两次. 日志筛选如下:

每次100000条, 分2次处理: 32718ms

每次50000条, 分4次处理: 32854ms

每次10000条, 分20次处理: 32198ms

每次5000条, 分40次处理: 31744ms

每次1000条, 分200次处理: 32166ms

每次500条, 分400次处理: 32682ms

每次100条, 分2000次处理: 33333ms

每次50条, 分4000次处理: 33260ms

而最后的两条是没有使用批处理跑出来的 用时近600000ms, 近1小时40分钟, 完全不是一个数量级的.

相比较而言, 批处理语句在量的划分上差别并不明显, 在千级的划分只有一点点的减少.

详细测试间测试代码(已上传).

点击下载: db-batch-test - 已下载 214 次

JSP解决session过期时写入数据库操作

背景如下:

我在做一个系统的时候希望实现当用户点击jsp页面上的注销按钮时实现在数据库中保存用户注销的时间. 另外如果用户没有正常退出, 则在session超时时自动记录超时时候的时间.

仿照找到的关于利用HttpSessionListener实现在线人数统计的方法来处理:

对每一个正在访问的用户, J2EE应用服务器会为其建立一个对应的HttpSession对象. 当一个浏览器第一次访问网站的时候, J2EE应用服务器会 新建一个HttpSession对象, 并触发HttpSession创建事件, 如果注册了HttpSessionListener事件监听器, 则会调用 HttpSessionListener事件监听器的sessionCreated方法. 相反,当这个浏览器访问结束超时的时候, J2EE应用服务器会销 毁相应的HttpSession对象, 触发HttpSession销毁事件, 同时调用所注册HttpSessionListener事件监听器的 sessionDestroyed方法.

可见, 对应于一个用户访问的开始和结束, 相应的有sessionCreated方法和sessionDestroyed方法执行. 因此, 我们只需在 HttpSessionListener实现类的sessionDestroyed方法中让其执行数据库的更新操作就可以了.

下面是示例代码:

package libms.session;

import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import libms.service.UserServiceImpl;

public class UserOnlineListener
        implements HttpSessionListener {

    private static long userId = 0;

    public static void setUserId(long id) {
        userId = id;
    }

    public void sessionCreated(HttpSessionEvent event) {
    }

    public void sessionDestroyed(HttpSessionEvent event) {
        if (userId > 0) {
            // 这里写更新数据库的操作
        }
    }
}

在web.xml文件中注册一个监听器:

<listener>
    <listener-class>com.online.OnlineCountListener</listener-class>
</listener>

在用户登录的时候, 把用户的id使用UserOnlineListener .setUserId (id)的方法保存下来. 当用户点击注销按钮的时候, 调用session.invalidate ()的方法清空session, 就会触发监听器sessionDestroyed(HttpSessionEvent event)方法了, 同样, 如果用户非正常退出, 则在session超时的时候, 也会出发该方法.