我的如下://mysqltest.java
package news;
import java.sql.*;
public final class mysqltest
{
protected static mysqltest inst = new mysqltest();
private static final String _url = "proxool.xml-pdjc";   //proxool SourceName nickName
Connection conn = null;
Statement stmt = null;
PreparedStatement pstmt = null;
ResultSet rs = null; //getConn
public Connection getConnection() throws SQLException
{
if(conn == null || conn.isClosed())
{
conn = DriverManager.getConnection(_url);
}
return conn;
} //mysqltest
public mysqltest()
{
//inst.getConnection();
} //pstmt conn
public PreparedStatement getPstmt(String sql)
{
try
{
pstmt = getConnection().prepareStatement(sql);
}
catch(SQLException ex)
{
System.err.println("sql_data.pstmt:"+ex.getMessage());
}

return pstmt;
} //pstmt query
public ResultSet pstmtQuery(String sql)
{
try
{
pstmt = getConnection().prepareStatement(sql);
rs =  pstmt.executeQuery();
}
catch(SQLException ex)
{
System.err.println("sql_data.executeQuery:"+ex.getMessage());
} return rs;
}

//query
public ResultSet executeQuery(String sql)
{
try
{
stmt = getConnection().createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);
rs = stmt.executeQuery(sql);
}
catch(SQLException ex)
{
System.err.println("sql_data.executeQuery:"+ex.getMessage());
} return rs;
} //insert
public void executeInsert(String sql)
{
try
{
stmt = getConnection().createStatement();
stmt.executeUpdate(sql);
stmt.close();
stmt = null;
}
catch(SQLException ex)
{
System.out.println(ex);
}
finally
{
try
{
if (stmt != null) 
{
stmt.close();
stmt = null;
}
}
catch(SQLException e)
{
System.out.println(e);
}
}
}
//update
public void executeUpdate(String sql)
{
try
{
stmt = getConnection().createStatement();
stmt.executeUpdate(sql);
stmt.close();
stmt = null;
}
catch(SQLException ex)
{
System.out.println(ex);
}
finally
{
try
{
if (stmt != null) 
{
stmt.close();
stmt = null;
}
}
catch(SQLException e)
{
System.out.println(e);
}
}
} //delete
public void executeDelete(String sql)
{
try
{
stmt = getConnection().createStatement();
stmt.executeUpdate(sql);
stmt.close();
stmt = null;
}
catch(SQLException ex)
{
System.out.println(ex);
}
finally
{
try
{
if (stmt != null) 
{
stmt.close();
stmt = null;
}
}
catch(SQLException e)
{
System.out.println(e);
}
}
}

//close
public void closeDB() 
{
try
{
if(rs != null)
{
rs.close();
rs = null;
} if(pstmt != null)
{
pstmt.close();
pstmt = null;
} if(stmt != null)
{
stmt.close();
stmt = null;
} if(conn != null)
{
conn.close();
conn = null;
}
}
catch(SQLException e)
{
System.out.println(e);
} finally
{
try
{
if(rs != null)
{
rs.close();
rs = null;
} if(pstmt != null)
{
pstmt.close();
pstmt = null;
} if(stmt != null)
{
stmt.close();
stmt = null;
} if(conn != null)
{
conn.close();
conn = null;
}
}
catch(SQLException e)
{
System.out.println(e);
}
}
}}

解决方案 »

  1.   

    package util;//mysqltest.java
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;import com.chinaMobile.model.Customer;public final class Mysqltest {
    protected static Mysqltest inst = null;
    private static final String _url = "proxool.xml-pdjc"; // proxool SourceName
    // nickName
    // 第0处修改去掉一些的成员变量
    // Connection conn = null;
    // Statement stmt = null;
    // PreparedStatement pstmt = null;
    // ResultSet rs = null;
    private ThreadLocal<Connection> connLocal = new ThreadLocal<Connection>(); // mysqltest
    /**
     * 第①处修改 public变成private 不允许外部new mysqltest();单例模式必须的
     */
    private Mysqltest() {
    // inst.getConnection();
    } /**
     * 第②处修改,外部调用必须要通过这个得到对象,要不然不能new 怎么出来对象呢
     * 
     */ public Mysqltest getMysqltest() {
    if (null == inst) {
    inst = new Mysqltest();
    }
    return inst; } /**
     * 第③处修改加上ThreadLocal管理conn,
     * 并且conn不能自动提交,因为这里是最原子的地方,所以我们要在上层方法中来做事务,所以conn.setAutoCommit(false);
     * 如果可以加上异常捕获在抛出一个自定义的runtime异常,这样可以在上层对异常进行处理了 参考
     * public class DatabaseException extends RuntimeException {
     * 
     * private Exception nestedException;
     * 
     * public Exception getNestedException() { return nestedException; }
     * 
     * public DatabaseException(Exception e, String msg) { super(msg);
     * nestedException = e; }
     * 
     * }
     * 
     * @return
     * @throws SQLException
     */
    // getConn
    public Connection getConnection() throws DatabaseException {
    Connection conn = connLocal.get();
    if (conn == null) {
    try {
    if (conn == null || conn.isClosed()) {
    conn = DriverManager.getConnection(_url);
    conn.setAutoCommit(false);//这里的事务不能自动提交
    // 放到ThreadLocal里面的对象,可见性仅限于当前线程
    connLocal.set(conn);
    System.out.println("获得数据库 #" + conn.hashCode());
    }
    } catch (SQLException e) {
    e.printStackTrace();
    throw new DatabaseException(e, "不能获得数据库连接");
    }
    } return conn;
    } // pstmt conn
    /**
     * 第④处 如果sql有参数怎么办,所以修改一下,加上 Object[] params
     * 这里可以不错异常处理,因为我们还不关心这里是否出现了异常,不过管了也不错但是管了就必须抛出自定义的异常,要不然上层程序怎么知道出现异常了呢
     * 关于异常什么时候抛出什么时候捕获,捕获后怎么办请参看百度,谷歌的高效java开发
     * 
     * @param sql
     * @return
     */
    public PreparedStatement getPstmt(String sql, Object[] params) {
    PreparedStatement pstmt = null;
    try {
    pstmt = getConnection().prepareStatement(sql);
    if (params.length > 0)// 有参数
    {
    for (int i = 0; i < params.length; i++) {
    // params里面参数的顺序,必须符合sql里面的顺序
    pstmt.setObject(i + 1, params[i]);
    }
    }
    System.out.println("执行SQL:" + sql);
    } catch (SQLException ex) {
    System.err.println("sql_data.pstmt:" + ex.getMessage());
    } return pstmt;
    } /**
     * 第⑤处就是我们比较关心的了,发现没有你的getPstmt方法似乎没有用到吧,所以问题就在这里了getConnection().
     * prepareStatement(sql),去掉改成getPstmt 然后因为我们参数有了所以改一下
     *   因为我们去掉了成员变量而pstmt和rs要随用随关闭,如果用这个方法就做不到了,所以我们可以不用这个方法
     * @param sql
     * @return
     */
    // pstmt query
    public ResultSet pstmtQuery(String sql, Object... params) {
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    try {
    pstmt = getPstmt(sql, params);
    rs = pstmt.executeQuery();
    //因为要返回rs显然这里关闭不科学,以后的方法我们都是PreparedStatement stmt = getPstmt(sql, params); ResultSet rs = stmt.executeQuery();
                // 都用这个方法代替
    // pstmt.close();
    //         rs.close();
    } catch (SQLException ex) {
    System.err.println("sql_data.executeQuery:" + ex.getMessage());
    } return rs;
    } /**
     * 第⑥处修改 因为预编译sql不这个高效所以这个可以去掉了 executeQuery(String sql)
     * 
     * @param sql
     * @return
     */
    // query
    // public ResultSet executeQuery(String sql)
    // {
    // try
    // {
    // stmt =
    // getConnection().createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);
    // rs = stmt.executeQuery(sql);
    // }
    // catch(SQLException ex)
    // {
    // System.err.println("sql_data.executeQuery:"+ex.getMessage());
    // }
    //
    // return rs;
    // } /**
     * 第⑦处同样用到getPstmt,当然如果你在sql中已经组装好了各种参数就不需要params这个了,但是我们为什么要费时间自己去组装sql呢
     * insert update delete 同一个方法就可以了
     * 把stmt改成预编译好的pstmt,并且去掉成员变量,做到随用随关闭。不影响其他人使用 添加返回值
     * 在执行sql语句的时候其实我们并不关心他的异常,我们要让上层程序知道有异常了,并且做出反应比如回滚
     * 
     * @param sql
     * @throws SQLException
     */
    // insert update delete 同一个方法就可以了
    public int executeInsert(String sql, Object... params) throws SQLException {
    PreparedStatement pstmt = null;
    pstmt = getPstmt(sql, params);// 注意这里的stmt成员变量会导致线程不安全,别人在用的时候可能被你关掉了,因为这是个单例类
    int returnValue = pstmt.executeUpdate(sql);
    pstmt.close();
    pstmt = null;
    return returnValue;
    } /**
     * 与上面的方法重复去掉
     * 
     * @param sql
     */
    // update
    // public void executeUpdate(String sql)
    // {
    //
    // stmt = getConnection().createStatement();
    // stmt.executeUpdate(sql);
    // stmt.close();
    // stmt = null;
    //
    //
    // } // delete
    // public void executeDelete(String sql)
    // {
    // try
    // {
    // stmt = getConnection().createStatement();
    // stmt.executeUpdate(sql);
    // stmt.close();
    // stmt = null;
    // }
    // catch(SQLException ex)
    // {
    // System.out.println(ex);
    // }
    // finally
    // {
    // try
    // {
    // if (stmt != null)
    // {
    // stmt.close();
    // stmt = null;
    // }
    // }
    // catch(SQLException e)
    // {
    // System.out.println(e);
    // }
    // }
    // }
    /**
     * 第⑧处修改,增加返回list,和Object对象的方法,就是获取一组数据和一个数据的方法
     * 因为我们的原则是stmt和rs都是随用随关,所以我们要把rs处理才行,这里我们用一个接口
     * import java.sql.ResultSet;
           public interface RowProccess {
          public Object processRow(ResultSet rs) throws Exception;
    }
          为什么用接口口呢,因为我们不知道这个rs怎么处理
     * 
     */
    public List query(String sql, RowProccess rp, Object... params) {
    try {
    PreparedStatement stmt = getPstmt(sql, params);
    ResultSet rs = stmt.executeQuery();
    List results = new ArrayList();
    while (rs.next()) { results.add(rp.processRow(rs));
    }
    rs.close();
    stmt.close();
    return results;
    } catch (Exception e) {
    e.printStackTrace();
    throw new DatabaseException(e, "执行查询失败:" + sql);
    }
    }
    public Object querySingle(String sql, RowProccess rp, Object... params) {
    try {
    PreparedStatement stmt = getPstmt(sql, params);
    ResultSet rs = stmt.executeQuery();
    Object object = null;
    if (rs.next()) { object = rp.processRow(rs);
    }
    rs.close();
    stmt.close();
    return object;
    } catch (Exception e) {
    e.printStackTrace();
    throw new DatabaseException(e, "执行查询失败:" + sql);
    }
    }


    /**
     * 第⑨处修改 成员变量去掉就改成这样子
     */
    // close
    public void closeDB() {
    Connection connection = connLocal.get();
    if (connection != null) {
    connLocal.set(null);
    try {
    connection.close();
    System.out.println("关闭数据库连接 #" + connection.hashCode());
    } catch (SQLException e) {
    e.printStackTrace();
    }
    }
    }
      /**
       * 第⑩处修改增加事务提交和回滚方法
       * 
       */
    public void commit() {
    Connection connection = connLocal.get();
    if (connection != null) {
    try {
    connection.commit();
    } catch (SQLException e) {
    e.printStackTrace();
    throw new DatabaseException(e, "事务提交失败");
    }
    }
    }
    public void rollback() {
    Connection connection = connLocal.get();
    if (connection != null) {
    try {
    connection.rollback();
    } catch (SQLException e) {
    e.printStackTrace();
    throw new DatabaseException(e, "事务回滚失败");
    }
    }
    }
    /**
     * 最后看一个调用Mysqltest的方法RowProccess这里叫做内部匿名类,只有在查找数据的时候才用的到save,update,delete的时候用不到的
     * private Mysqltest db = Mysqltest.getMysqltest(); public Customer findCustomerByIDTypeAndID(final int idtype, final String id) {
    String sql = "select cid,cname,birthdate,sex,address "
    + "from customers where idtype=? and idnumber=?";
    return (Customer) db.querySingle(sql, new RowProccess() { public Object processRow(ResultSet rs) throws Exception {
    Customer c = new Customer();
    c.setId(id);
    c.setIdType(idtype);
    c.setCid(rs.getString("cid"));
    c.setName(rs.getString("cname"));
    c.setSex(rs.getInt("sex"));
    c.setAddress(rs.getString("address"));
    c.setBirthDate(rs.getDate("birthdate"));
    return c;
    } }, idtype, id); }
     */
    }
      

  2.   

    package util;//mysqltest.java
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;import com.chinaMobile.model.Customer;public final class Mysqltest {
    protected static Mysqltest inst = null;
    private static final String _url = "proxool.xml-pdjc"; // proxool SourceName
    // nickName
    // 第0处修改去掉一些的成员变量
    // Connection conn = null;
    // Statement stmt = null;
    // PreparedStatement pstmt = null;
    // ResultSet rs = null;
    private ThreadLocal<Connection> connLocal = new ThreadLocal<Connection>(); // mysqltest
    /**
     * 第①处修改 public变成private 不允许外部new mysqltest();单例模式必须的
     */
    private Mysqltest() {
    // inst.getConnection();
    } /**
     * 第②处修改,外部调用必须要通过这个得到对象,要不然不能new ,怎么出来对象呢
     * 
     */ public Mysqltest getMysqltest() {
    if (null == inst) {
    inst = new Mysqltest();
    }
    return inst; } /**
     * 第③处修改加上ThreadLocal管理conn,
     * 并且conn不能自动提交,因为这里是最原子的地方,所以我们要在上层方法中来做事务,所以conn.setAutoCommit(false);
     * 如果可以加上异常捕获在抛出一个自定义的runtime异常,这样可以在上层对异常进行处理了 参考
     * public class DatabaseException extends RuntimeException {
     * 
     * private Exception nestedException;
     * 
     * public Exception getNestedException() { return nestedException; }
     * 
     * public DatabaseException(Exception e, String msg) { super(msg);
     * nestedException = e; }
     * 
     * }
     * 
     * @return
     * @throws SQLException
     */
    // getConn
    public Connection getConnection() throws DatabaseException {
    Connection conn = connLocal.get();
    if (conn == null) {
    try {
    if (conn == null || conn.isClosed()) {
    conn = DriverManager.getConnection(_url);
    conn.setAutoCommit(false);//这里的事务不能自动提交
    // 放到ThreadLocal里面的对象,可见性仅限于当前线程
    connLocal.set(conn);
    System.out.println("获得数据库 #" + conn.hashCode());
    }
    } catch (SQLException e) {
    e.printStackTrace();
    throw new DatabaseException(e, "不能获得数据库连接");
    }
    } return conn;
    } // pstmt conn
    /**
     * 第④处 如果sql有参数怎么办,所以修改一下,加上 Object[] params
     * 这里可以不做异常处理,因为我们还不关心这里是否出现了异常,不过管了也不错但是管了就必须抛出自定义的异常,要不然上层程序怎么知道出现异常了呢
     * 关于异常什么时候抛出什么时候捕获,捕获后怎么办请参看百度,谷歌的高效java开发
     * 
     * @param sql
     * @return
     */
    public PreparedStatement getPstmt(String sql, Object[] params) {
    PreparedStatement pstmt = null;
    try {
    pstmt = getConnection().prepareStatement(sql);
    if (params.length > 0)// 有参数
    {
    for (int i = 0; i < params.length; i++) {
    // params里面参数的顺序,必须符合sql里面的顺序
    pstmt.setObject(i + 1, params[i]);
    }
    }
    System.out.println("执行SQL:" + sql);
    } catch (SQLException ex) {
    System.err.println("sql_data.pstmt:" + ex.getMessage());
    } return pstmt;
    } /**
     * 第⑤处就是我们比较关心的了,发现没有你的getPstmt方法似乎没有用到吧,所以问题就在这里了getConnection().
     * prepareStatement(sql),去掉改成getPstmt 然后因为我们参数有了所以改一下
     *   因为我们去掉了成员变量而pstmt和rs要随用随关闭,如果用这个方法就做不到了,所以我们可以不用这个方法
     * @param sql
     * @return
     */
    // pstmt query
    public ResultSet pstmtQuery(String sql, Object... params) {
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    try {
    pstmt = getPstmt(sql, params);
    rs = pstmt.executeQuery();
    //因为要返回rs显然这里关闭不科学,以后的方法我们都是PreparedStatement stmt = getPstmt(sql, params); ResultSet rs = stmt.executeQuery();
                // 都用这个方法代替
    // pstmt.close();
    //         rs.close();
    } catch (SQLException ex) {
    System.err.println("sql_data.executeQuery:" + ex.getMessage());
    } return rs;
    } /**
     * 第⑥处修改 因为预编译sql比这个高效所以这个可以去掉了 executeQuery(String sql)
     * 
     * @param sql
     * @return
     */
    // query
    // public ResultSet executeQuery(String sql)
    // {
    // try
    // {
    // stmt =
    // getConnection().createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_READ_ONLY);
    // rs = stmt.executeQuery(sql);
    // }
    // catch(SQLException ex)
    // {
    // System.err.println("sql_data.executeQuery:"+ex.getMessage());
    // }
    //
    // return rs;
    // } /**
     * 第⑦处同样用到getPstmt,当然如果你在sql中已经组装好了各种参数就不需要params这个了,但是我们为什么要费时间自己去组装sql呢
     * insert update delete 同一个方法就可以了
     * 把stmt改成预编译好的pstmt,并且去掉成员变量,做到随用随关闭。不影响其他人使用 添加返回值
     * 在执行sql语句的时候其实我们并不关心他的异常,我们要让上层程序知道有异常了,并且做出反应比如回滚
     * 
     * @param sql
     * @throws SQLException
     */
    // insert update delete 同一个方法就可以了
    public int executeInsert(String sql, Object... params) throws SQLException {
    PreparedStatement pstmt = null;
    pstmt = getPstmt(sql, params);// 注意这里的stmt成员变量会导致线程不安全,别人在用的时候可能被你关掉了,因为这是个单例类
    int returnValue = pstmt.executeUpdate(sql);
    pstmt.close();
    pstmt = null;
    return returnValue;
    } /**
     * 与上面的方法重复去掉
     * 
     * @param sql
     */
    // update
    // public void executeUpdate(String sql)
    // {
    //
    // stmt = getConnection().createStatement();
    // stmt.executeUpdate(sql);
    // stmt.close();
    // stmt = null;
    //
    //
    // } // delete
    // public void executeDelete(String sql)
    // {
    // try
    // {
    // stmt = getConnection().createStatement();
    // stmt.executeUpdate(sql);
    // stmt.close();
    // stmt = null;
    // }
    // catch(SQLException ex)
    // {
    // System.out.println(ex);
    // }
    // finally
    // {
    // try
    // {
    // if (stmt != null)
    // {
    // stmt.close();
    // stmt = null;
    // }
    // }
    // catch(SQLException e)
    // {
    // System.out.println(e);
    // }
    // }
    // }
    /**
     * 第⑧处修改,增加返回list,和Object对象的方法,就是获取一组数据和一个数据的方法
     * 因为我们的原则是stmt和rs都是随用随关,所以我们要把rs处理才行,这里我们用一个接口
     * import java.sql.ResultSet;
           public interface RowProccess {
          public Object processRow(ResultSet rs) throws Exception;
    }
          为什么用接口口呢,因为我们不知道这个rs怎么处理
     * 
     */
    public List query(String sql, RowProccess rp, Object... params) {
    try {
    PreparedStatement stmt = getPstmt(sql, params);
    ResultSet rs = stmt.executeQuery();
    List results = new ArrayList();
    while (rs.next()) { results.add(rp.processRow(rs));
    }
    rs.close();
    stmt.close();
    return results;
    } catch (Exception e) {
    e.printStackTrace();
    throw new DatabaseException(e, "执行查询失败:" + sql);
    }
    }
    public Object querySingle(String sql, RowProccess rp, Object... params) {
    try {
    PreparedStatement stmt = getPstmt(sql, params);
    ResultSet rs = stmt.executeQuery();
    Object object = null;
    if (rs.next()) { object = rp.processRow(rs);
    }
    rs.close();
    stmt.close();
    return object;
    } catch (Exception e) {
    e.printStackTrace();
    throw new DatabaseException(e, "执行查询失败:" + sql);
    }
    }


    /**
     * 第⑨处修改 成员变量去掉就改成这样子
     */
    // close
    public void closeDB() {
    Connection connection = connLocal.get();
    if (connection != null) {
    connLocal.set(null);
    try {
    connection.close();
    System.out.println("关闭数据库连接 #" + connection.hashCode());
    } catch (SQLException e) {
    e.printStackTrace();
    }
    }
    }
      /**
       * 第⑩处修改增加事务提交和回滚方法
       * 
       */
    public void commit() {
    Connection connection = connLocal.get();
    if (connection != null) {
    try {
    connection.commit();
    } catch (SQLException e) {
    e.printStackTrace();
    throw new DatabaseException(e, "事务提交失败");
    }
    }
    }
    public void rollback() {
    Connection connection = connLocal.get();
    if (connection != null) {
    try {
    connection.rollback();
    } catch (SQLException e) {
    e.printStackTrace();
    throw new DatabaseException(e, "事务回滚失败");
    }
    }
    }
    /**
     * 最后看一个调用Mysqltest的方法RowProccess这里叫做内部匿名类,只有在查找数据的时候才用的到save,update,delete的时候用不到的
     * private Mysqltest db = Mysqltest.getMysqltest(); public Customer findCustomerByIDTypeAndID(final int idtype, final String id) {
    String sql = "select cid,cname,birthdate,sex,address "
    + "from customers where idtype=? and idnumber=?";
    return (Customer) db.querySingle(sql, new RowProccess() { public Object processRow(ResultSet rs) throws Exception {
    Customer c = new Customer();
    c.setId(id);
    c.setIdType(idtype);
    c.setCid(rs.getString("cid"));
    c.setName(rs.getString("cname"));
    c.setSex(rs.getInt("sex"));
    c.setAddress(rs.getString("address"));
    c.setBirthDate(rs.getDate("birthdate"));
    return c;
    } }, idtype, id); }
     */
    }
      

  3.   

    你导入的import com.chinaMobile.model.Customer;是什么意思?DatabaseException报异常RowProccess接口异常能否直接编译没有任何问题的
      

  4.   

    package com.chinaMobile.model;import java.io.Serializable;
    import java.sql.Date;public class Customer implements Serializable { private String cid;// 客户id
    private String id;// 证件号码
    private int idType;// 证件类型 1、身份证,2、护照 3、军官证 private String name;
    private int sex;// 1 male,2 female
    private String address;
    private Date birthDate; public Date getBirthDate() {
    return birthDate;
    } public void setBirthDate(Date birthDate) {
    this.birthDate = birthDate;
    } public String getId() {
    return id;
    } public void setId(String id) {
    this.id = id;
    } public int getIdType() {
    return idType;
    } public void setIdType(int idType) {
    this.idType = idType;
    } public String getName() {
    return name;
    } public void setName(String name) {
    this.name = name;
    } public int getSex() {
    return sex;
    } public void setSex(int sex) {
    this.sex = sex;
    } public String getAddress() {
    return address;
    } public void setAddress(String address) {
    this.address = address;
    } public String getCid() {
    return cid;
    } public void setCid(String cid) {
    this.cid = cid;
    }}
      

  5.   

    package util;
    public class DatabaseException extends RuntimeException { private Exception nestedException; public Exception getNestedException() {
    return nestedException;
    } public DatabaseException(Exception e, String msg) {
    super(msg);
    nestedException = e;
    }}
      

  6.   

    package util;import java.sql.ResultSet;public interface RowProccess { public Object processRow(ResultSet rs) throws Exception;
    }