TheadLocal 中文叫做线程局部变量,它为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。
其实主要想讲的是它的数据库连接方面的作用,就是保证一个线程一个事务一个session。由于请求中的一个事务涉及多个 DAO 操作,而这些 DAO 中的 Connection
不能从连接池中获得,如果是从连接池获得的话,两个 DAO 就用到了两个Connection,这样的话是没有办法完成一个事务的。DAO 中的 Connection 如果是从 ThreadLocal 中获得 Connection 的话那么这些 DAO 就会被纳入到同一个 Connection 之下。当然了,这样的话,DAO 中就不能把 Connection 给关了,关掉的话,下一个使用者就不能用了。
public class DataSourceFactory{ private static DataSource ds = null; private static final ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>(); /** * 使用JNDI方式获得数据库源 * 需要在tomcat/conf/context.xml中配置数据源,如下: * <Resource name="jdbc/forceviewDB" type="javax.sql.DataSource" username="forceview" password="forceview" url="jdbc:postgresql://localhost/forceview?autoReconnect=true&useUnicode=true&characterEncoding=utf-8" driverClassName="org.postgresql.Driver" maxIdle="3" maxWait="-1" maxActive="50" validationQuery="select 1" testOnBorrow="true" testOnReturn="true" testWhileIdle="true" removeAbandoned="true" removeAbandonedTimeout="180" logAbandoned="true" timeBetweenEvictionRunsMillis="180000" minEvictableIdleTimeMillis = "180000" /> *注意相关jar包的引入 * @param jndi */ public static void init(String jndi) { if(jndi==null||"".equals(jndi)){ jndi="java:/comp/env/jdbc/forceviewDB"; } try { Context initContext = new InitialContext(); ds = (DataSource) initContext.lookup(jndi); } catch (Exception e) { DhccLogger.error("", e); } } /** * 使用从spring的ApplicationContext对象中得到的数据源给ds赋值 * @param ctx */ public static void init(ApplicationContext ctx) { try { ds = (DataSource) ctx.getBean("dataSource"); } catch (RuntimeException e) { DhccLogger.error("", e); } } /** * 使用数据库源给ds赋值 * @param dataSource */ public static void init(DataSource dataSource) { ds=dataSource; } /** * 获取数据库连接 * 如果threadLocal中没有连接,或者其中的连接已经关闭, * 则从数据库连接池中获得,并保存于threadLocal中 * @return */ public static Connection getConnection() { Connection conn = threadLocal.get(); try { if (conn == null || conn.isClosed()) { conn = ds.getConnection(); threadLocal.set(conn); } } catch (Exception e) { DhccLogger.error("", e); } return conn; } /** * 关闭数据库连接 * 此方法不进行任何操作,在操作数据库时,习惯最后关闭数据库连接, * 应用此类取得的数据库连接最好不要立即关闭,为了习惯,可以使用此方法来代替connection.close()方法 */ public static void closeConnection() { } /** * 关闭数据库连接,把数据库连接归还连接池, * 此连接对应于连接池中的连接并没有真正关闭,仍由连接池维护 */ public static void close() { Connection conn = (Connection) threadLocal.get(); threadLocal.set(null); if (conn != null) { try { conn.close(); } catch (SQLException e) { DhccLogger.error("", e); } } } }