<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>supttkl</title>
    <description></description>
    <link>http://supttkl.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>Jdbc   BaseDao</title>
        <author>supttkl</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://supttkl.javaeye.com">supttkl</a>&nbsp;
          链接：<a href="http://supttkl.javaeye.com/blog/181480" style="color:red;">http://supttkl.javaeye.com/blog/181480</a>&nbsp;
          发表时间: 2008年04月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">

package com.oa.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.oa.core.DynaForm;
import com.oa.dao.Dao;
import com.oa.jdbc.ConnectionFactory;
import com.oa.jdbc.DaoAccessException;
import com.oa.jdbc.DybaBean;
import com.oa.jdbc.JdbcPage;
import com.oa.jdbc.Page;
import com.oa.jdbc.RowsDynaClass;

/**
 * 基类DAO，实现一些基本共有方法
 * 
 * @author Gao_wx Mar 26, 2008
 */
public class BaseDao implements Dao {
	protected Log logger = LogFactory.getLog(BaseDao.class);

	// 获取数据库链接
	protected Connection getConnection() {
		return ConnectionFactory.getConnection();
	}

	// 在此链接上，根据sql语句获取List
	protected List&lt;DybaBean> getList(Connection conn, String sql)
			throws DaoAccessException {
		try {
			Statement st = conn.createStatement(
					ResultSet.TYPE_SCROLL_INSENSITIVE,
					ResultSet.CONCUR_READ_ONLY);
			ResultSet rs = st.executeQuery(sql);
			return getList(rs);
		} catch (SQLException e) {
			throw new DaoAccessException(sql, e);
		}
	}

	// 根据Result获取List
	protected List&lt;DybaBean> getList(ResultSet rs) throws SQLException {
		RowsDynaClass rsdc = new RowsDynaClass(rs);
		return rsdc.getRows();

	}

	// 根据sql语句获取List
	protected List&lt;DybaBean> getList(String sql) throws DaoAccessException {
		Connection conn = getConnection();
		return getList(conn, sql);
	}

	// 在此连接上，根据sql语句，id加载一条记录
	protected DybaBean loadById(Connection conn, String sql, int id)
			throws DaoAccessException {
		try {
			PreparedStatement pst = conn.prepareStatement(sql,
					ResultSet.TYPE_SCROLL_INSENSITIVE,
					ResultSet.CONCUR_READ_ONLY);
			pst.setInt(1, id);
			ResultSet rs = pst.executeQuery();
			List list = getList(rs);
			if (list.size() > 1) {
				logger.warn("加载了2条以上的记录，请检查sql：" + sql);
			}
			if (list.size() == 0) {
				logger.warn("数据库没有此记录！");
				return null;
			} else {
				return (DybaBean) list.get(0);
			}
		} catch (SQLException e) {
			throw new DaoAccessException(sql, e);
		}
	}

	// 根据sql语句，id，加载一条记录
	protected DybaBean loadById(String sql, int id) throws DaoAccessException {
		Connection conn = getConnection();
		return loadById(conn, sql, id);
	}

	// 在此连接上，根据Sql和id删除一条记录，返回影响行数
	protected int deleteById(Connection conn, String sql, int id)
			throws SQLException {
		PreparedStatement pst = conn.prepareStatement(sql,
				ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
		pst.setInt(1, id);
		int del = pst.executeUpdate();
		return del;
	}

	// 根据sql语句，id删除一条记录
	protected int deleteById(String sql, int id) throws DaoAccessException {
		Connection conn = getConnection();
		try {
			int del = deleteById(conn, sql, id);
			return del;
		} catch (SQLException e) {
			throw new DaoAccessException(sql, e);
		}

	}

	protected Page getPage(DynaForm form, String sql) throws DaoAccessException {
		Connection conn = getConnection();
		Page page = getPage(conn, form, sql);
		return page;
	}

	// 获取分页对象
	protected Page getPage(Connection conn, DynaForm form, String sql)
			throws DaoAccessException {
		int p = form.getInt("p");
		if (p &lt; 1) {
			p = 1;
		}
		int size = form.getInt("size");
		if (size &lt; 10) {
			size = 10;
		}
		Page page;
		try {
			page = new JdbcPage(conn, sql, p, size);
		} catch (SQLException e) {
			throw new DaoAccessException(sql, e);
		}
		return page;
	}
}
</pre><br />所有的select sql，不管是一对多，还是一对一，还是多对一，尽可能通过视图操作数据库！<br />数据库要改动的时候，改动视图即可！<br />如果表经常可能改动。那么请用动态表<br />http://supttkl.javaeye.com/admin/blogs/181411
          <br/>
          <span style="color:red;">
            <a href="http://supttkl.javaeye.com/blog/181480#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 10 Apr 2008 22:29:04 +0800</pubDate>
        <link>http://supttkl.javaeye.com/blog/181480</link>
        <guid>http://supttkl.javaeye.com/blog/181480</guid>
      </item>
      <item>
        <title>浅谈对jdbc和jtds的一些认识</title>
        <author>supttkl</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://supttkl.javaeye.com">supttkl</a>&nbsp;
          链接：<a href="http://supttkl.javaeye.com/blog/181471" style="color:red;">http://supttkl.javaeye.com/blog/181471</a>&nbsp;
          发表时间: 2008年04月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          最近做项目用SQLSERVER2000的数据库，使用JTDS开源的驱动，跟大家谈谈个人对JDBC的一些理解。<br />一个DateSource可以获取多个Connection，一个Connection可以打开多个Statement，一个Statement可以打开多个ResultSet。如果我直接<br /><br />conn.close();仔细翻看jtds源代码。在底层是这样实现的。<br />Connection------------------------close方法<br /><pre name="code" class="java">
 synchronized public void close() throws SQLException {
        if (!closed) {
            try {
                //
                // Close any open statements
                //
                ArrayList tmpList;

                synchronized (statements) {
                    tmpList = new ArrayList(statements);
                    statements.clear();
                }

                for (int i = 0; i &lt; tmpList.size(); i++) {
                    WeakReference wr = (WeakReference)tmpList.get(i);

                    if (wr != null) {
                        Statement stmt = (Statement) wr.get();
                        if (stmt != null) {
                            try {
                                stmt.close();
                            } catch (SQLException ex) {
                                // Ignore
                            }
                        }
                    }
                }

                try {
                    // Tell the server the session is ending
                    baseTds.closeConnection();
                    // Close network connection
                    baseTds.close();
                    // Close cached TdsCore
                    if (cachedTds != null) {
                        cachedTds.close();
                        cachedTds = null;
                    }
                } catch (SQLException ex) {
                    // Ignore
                }

                socket.close();
            } catch (IOException e) {
                // Ignore
            } finally {
                closed = true;
            }
        }
    }


statement------------------------close方法

  public void close() throws SQLException {
        if (!closed) {
            SQLException closeEx = null;
            try {
                closeAllResultSets();
            } catch (SQLException ex) {
                if (!"HYT00".equals(ex.getSQLState())
                        && !"HY008".equals(ex.getSQLState())) {
                    // Only throw exceptions not caused by cancels or timeouts
                    closeEx = ex;
                }
            } finally {
                SQLException releaseEx = null;
                try {
                    if (!connection.isClosed()) {
                        connection.releaseTds(tds);
                    }
                    // Check for server side errors
                    tds.getMessages().checkErrors();
                } catch (SQLException ex) {
                    // Remember any exception thrown
                    releaseEx = ex;
                    // Queue up any result set close exceptions
                    if (closeEx != null) {
                        releaseEx.setNextException(closeEx);
                    }
                } finally {
                    // Clean up everything
                    closed = true;
                    tds = null;
                    connection.removeStatement(this);
                    connection = null;

                    // Re-throw any caught exception
                    if (releaseEx != null) {
                        throw releaseEx;
                    }
                }
            }
            // Throw any exception caught during result set close
            if (closeEx != null) {
                throw closeEx;
            }
        }
    }
</pre><br />看起来是如果关闭Connection，那么在此Connection上打开的所有Statement会关闭，如果关闭Statement那么在此Statement上打开的所有的<br /><br />ResultSet也会关闭。如果没有特殊需要，直接关闭Connection即可。<br /><br />那么在什么情况下需要先关闭ResultSet，然后关闭Statement。然后关闭Connection呢？<br /><br />仔细翻看Jtds的文档。找到了以下内容:<br />JDBC Concurrency  :                CONCUR_UPDATABLE+1<br />SQL Server Concurrency:            Pessimistic concurrency, updatable<br />Row Locks:                         Yes <br />Description :                 Row integrity isensured by locking rows <br /><br /><br />意思就是当<br />Statement st=Connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,<br />                                      ResultSet.CONCUR_UPDATABLE+1);<br />ResultSet rs=st.executeQuery("SELECT * FROM TABLE2 where id=1");<br />rs.updateString(1,"test");<br />rs.updateRow() ;<br /><br />该结果集就会锁定当前行，其他ResultSet不得访问。<br />这个时候ResultSet应当尽可能早的close()。以便释放资源。<br /><br />web服务器会为每次请求创建一个线程。也就是说一次request打开一次连接即可！在一次连接上创建多个Statement。<br />写一个监听器，每次销毁request的时候释放数据库连接。<br />http://supttkl.javaeye.com/admin/blogs/181419<br /><br />JTDS虽然实现了数据源，但是没有实现实现连接池。所以还要借助中间件的连接池，如dbcp。。。<br /><br />ConnectionJDBC2没有实现Savepoint保存点。ConnectionJDBC3实现了保存点.<br />那么什么时候使用保存点事务呢？<br />个人理解：<br />a向b借钱，b当时没有钱，然后到银行取出钱后委托给c，又c将钱转交给a<br />等c将钱转交给a的时候，发生了意外。那么钱应该在c手中，事务应该回滚到c，而不应该回滚到b。因为钱已经在c手中。<br />Connection conn=getConnetion();<br />conn.setAutoCommit(false);//启动事务<br />//b取钱<br />PreparedStatement pst=conn.prepareStatement("select * from money where bid=1");<br />ResultSet rs=pst.exeQuery();<br />int money=rs.getInt("money");<br />Savepoint savepoint=conn.setSavepoint("pointc");<br />//b将钱转交给c<br />PreparedStatement pst2=conn.prepareStatement("update table set money + ?");<br />pst2.setInt(1, money);<br />pst2.execute();<br />//c将钱转交给a的时候，出现了异常，如a不在家。<br />try{<br />PreparedStatement pstc=conn.prepareStatement("update table set money - ?");<br />pstc.setInt(money);<br />pstc.execute();<br />PreparedStatement psta=conn.prepareStatement("update table set money + ?");<br />psta.setInt(money);<br />psta.execute();<br />}catch(SQLException e){<br />  //回滚到c<br />   conn.rollback(savepoint) <br /><br />}
          <br/>
          <span style="color:red;">
            <a href="http://supttkl.javaeye.com/blog/181471#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 10 Apr 2008 22:12:39 +0800</pubDate>
        <link>http://supttkl.javaeye.com/blog/181471</link>
        <guid>http://supttkl.javaeye.com/blog/181471</guid>
      </item>
      <item>
        <title>实现jdbcOpenConnectionInView</title>
        <author>supttkl</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://supttkl.javaeye.com">supttkl</a>&nbsp;
          链接：<a href="http://supttkl.javaeye.com/blog/181419" style="color:red;">http://supttkl.javaeye.com/blog/181419</a>&nbsp;
          发表时间: 2008年04月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          嘿嘿！看了看spring代码。自己写了个jdbc的连接<br />贴出来代码。<br /><br /><pre name="code" class="java">
package com.jy.jdbc;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import net.sourceforge.jtds.jdbcx.JtdsDataSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ConnectionFactory {
	private final static String USER = "";
	private final static String PWD = "";
	private final static String IP = "";
	private final static String DATABASE="";
	private final static Log logger = LogFactory.getLog(ConnectionFactory.class);
	private final static ThreadLocal&lt;Connection> threadLocal = new ThreadLocal&lt;Connection>();
	private  static DataSource dst=null;
	// jtds数据源
	 static   {
		JtdsDataSource ds = new JtdsDataSource();
		ds.setServerType(1);// SQL SERVER
		ds.setServerName(IP);
		ds.setDatabaseName(DATABASE);
		ds.setPortNumber(1433);
		ds.setXaEmulation(true);
		try {
			ds.setSocketTimeout(3000);
		} catch (SQLException e1) {
			logger.error(e1);
		}
		ds.setMaxStatements(500);
		ds.setUser(USER);
		ds.setBatchSize(50);
		ds.setCacheMetaData(true);
		ds.setPassword(PWD);
		dst=ds;
	}
	 
	public static Connection getConnection() {
		Connection conn = threadLocal.get();
		if (conn == null) {
			try {
				conn = dst.getConnection();
				threadLocal.set(conn);
			} catch (SQLException e) {
				logger.error("从连接池获取连接失败！:" + e.getMessage());
			}
		}
		return conn;
	}
//dbcp连接池
//	public static DataSource getDataSource() {
//		BasicDataSource ds = new BasicDataSource();
//		ds.setDriverClassName(CLASSNAME);
//		ds.setUsername(USER);
//		ds.setPassword(PWD);
//		ds.setUrl(URL);
//		ds.setMaxActive(50);
//		ds.setMaxIdle(50);
//		ds.setMaxWait(3000); // 10 seconds
//		ds.setMaxOpenPreparedStatements(500);
//		System.out.println("NumActive: " + ds.getNumActive() + ","
//				+ "NumIdle: " + ds.getNumIdle());
//
//		return ds;
//	}

	


	// 关闭连接
	public static void closeConnection() {
		Connection conn = threadLocal.get();
		threadLocal.set(null);
		try {
			if (conn != null && !conn.isClosed()) {
				conn.close();
			}
		} catch (SQLException e) {
			logger.error("关闭连接失败！" + e.getMessage());
		}
	}


	public static void main(String[] args) {
		for (int i = 0; i &lt; 2; i++) {
			Connection conn = getConnection();
			try {
				Statement st=conn.createStatement();
				ResultSet rs=st.executeQuery("select * from test");
				while(rs.next()){
					System.out.println(rs.getInt("id"));
				}
				closeConnection();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		
	}
}
</pre><br />写个request监听器<br />package com.tool;<br /><pre name="code" class="java">
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;

import com.jinyu.jdbc.ConnectionFactory;
public class ListenterCloseConnection implements ServletRequestListener{

	public void requestDestroyed(ServletRequestEvent arg0) {
		ConnectionFactory.closeConnection();
	}

	public void requestInitialized(ServletRequestEvent arg0) {
		
	}


}
</pre><br /><br />在web.xml<br />配置如下<br /><pre name="code" class="xml">
&lt;!-- 监听器，关闭Connection -->
&lt;listener>
  &lt;listener-class>
    com.tool.ListenterCloseConnection
  &lt;/listenerclass>
&lt;/listener>
</pre><br />那么同一次request请求，只打开一次连接！所以不论采用Struts还是Servlet还是直接用jsp。只打开连接。不需关闭连接。
          <br/>
          <span style="color:red;">
            <a href="http://supttkl.javaeye.com/blog/181419#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 10 Apr 2008 18:36:31 +0800</pubDate>
        <link>http://supttkl.javaeye.com/blog/181419</link>
        <guid>http://supttkl.javaeye.com/blog/181419</guid>
      </item>
      <item>
        <title>动态表</title>
        <author>supttkl</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://supttkl.javaeye.com">supttkl</a>&nbsp;
          链接：<a href="http://supttkl.javaeye.com/blog/181411" style="color:red;">http://supttkl.javaeye.com/blog/181411</a>&nbsp;
          发表时间: 2008年04月10日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          表：学校 xx<br />id  学校id 主键 自增<br />name 学校名称<br /><br />表：学校完整信息表 xx2<br />id 学校完整信息表id 主键 自增<br />xx_id 学校id<br />attr_id 属性id<br />arrt_value 属性值<br /><br />表：额外属性表 arrt<br />arrt_id 属性id 主键 不自增<br />arrt_name 属性名称<br /><br />视图<br />all_xx查看图片附件<br /><br />添加记录<br />地址,电话，详细信息，校长名字，到额外属性表 arrt<br /><br />下面是静态的sql语句:<br /><br />select name,<br />   max (case arrt_name when '地址' then arrt_value else '0' end) as '地址',<br />   max (case arrt_name when '电话' then arrt_value else '0' end) as '电话' <br />from all_xx group by name<br /><br />下面是动态的sql语句<br />DECLARE @Sql VARCHAR(8000)<br />DECLARE @TypeName VARCHAR(10)<br />SET @Sql = 'SELECT name'<br />DECLARE curType CURSOR READ_ONLY FORWARD_ONLY FOR (<br /> SELECT Distinct arrt_name FROM all_xx)<br />OPEN curType<br />FETCH NEXT FROM curType INTO @TypeName<br />WHILE @@Fetch_Status = 0<br />BEGIN<br /> SET @Sql = @Sql + Char(13) + Char(10) + ', MAX(Case When arrt_name=''' + @TypeName + ''' Then arrt_value Else null End) AS ' + @TypeName<br /><br /> FETCH NEXT FROM curType INTO @TypeName<br />END<br />CLOSE curType<br />DEALLOCATE curType<br />SET @Sql = @Sql + Char(13) + Char(10) + 'FROM all_xx GROUP BY name'<br />PRINT @Sql<br />Exec(@Sql)<br /><br />运行效果看图片！<br /><br /><br />这样做的好处是：<br />当学校的属性变化多端，我们要做的是维护数据库，而不是去修改代码.
          <br/>
          <span style="color:red;">
            <a href="http://supttkl.javaeye.com/blog/181411#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 10 Apr 2008 18:21:27 +0800</pubDate>
        <link>http://supttkl.javaeye.com/blog/181411</link>
        <guid>http://supttkl.javaeye.com/blog/181411</guid>
      </item>
  </channel>
</rss>