關於 ThreadLocal
? 通過ThreadLocal.set() 將對象的引用保存到各線程的自己的一個 map 中,每個線程都有這樣一個map,執行ThreadLocal.get()時,各線程從自己的map中取出放進去的對象,因此取出來的是各自自己線程中的對象,ThreadLocal 實例是作爲map的key來使用的。
? 一般情況下,通過ThreadLocal.set() 到線程中的對象是該線程自己使用的對象,其他線程是不需要訪問的
? ThreadLocal 不是用來解決共享對象的多線程訪問問題的:如果ThreadLocal.set() 進去的東西本來就是多個線程共享的同一個對象,那麼多個線程的 ThreadLocal.get() 取得的還是這個共享對象本身,還是有併發訪問問題。
? ThreadLocal的應用場合:按線程多實例(每個線程對應一個實例)的對象的訪問。
ThreadLocalContext.java
package com.sherman.bookstore.web;
import java.sql.Connection;
public class ThreadLocalContext {
private ThreadLocal<Connection> connectionThreadLocal = new ThreadLocal<>();
private static ThreadLocalContext instance = newThreadLocalContext();
private ThreadLocalContext(){}
public static ThreadLocalContext getInstance(){
return instance;
}
public void bind(Connection connection){
connectionThreadLocal.set(connection);
}
public Connection getConnetion(){
return connectionThreadLocal.get();
}
public void remove(){
connectionThreadLocal.remove();
}
}
TransactionFilter.java
package com.sherman.bookstore.filter;
import java.io.IOException;
import ……;
import com.sherman.bookstore.db.JDBCUtils;
import com.sherman.bookstore.web.ThreadLocalContext;
/**
* Servlet Filter implementation classTransactionFilter
*/
@WebFilter("/*")
public class TransactionFilter implements Filter {
public TransactionFilter() {
// TODO Auto-generated constructor stub
}
public void destroy() {
// TODO Auto-generatedmethod stub
}
/**
* @seeFilter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,ServletException {
Connection connection = null;
try {
//1. 獲取連接
connection = JDBCUtils.getConnection();
//2. 開啓事務
connection.setAutoCommit(false);
//3. 利用 ThreadLocal 把當前線程與數據庫連接綁定
ThreadLocalContext.getInstance().bind(connection);
//4. 把請求轉發給對應的 Servlet
chain.doFilter(request, response);
//5. 提交事務
connection.commit();
} catch (Exception e) {
//6. 捕獲異常,回滾事務,跳轉至錯誤頁面
e.printStackTrace();
try {
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
resp.sendRedirect(req.getContextPath() + "/error-1.jsp");
}finally{
//7. 解除綁定
ThreadLocalContext.getInstance().remove();
//8. 關閉連接
JDBCUtils.release(connection);
}
}
public void init(FilterConfig fConfig) throws ServletException{
// TODO Auto-generatedmethod stub
}
}
BaseDAO.java
package com.sherman.bookstore.dao.impl;
import java.lang.reflect.ParameterizedType;
import ……;
public class BaseDAO<T> implements DAO<T> {
private QueryRunner queryRunner = new QueryRunner();
private Class<T> genericType = null;
@SuppressWarnings("unchecked")
public BaseDAO(){
Type type = this.getClass().getGenericSuperclass();
if(type instanceof ParameterizedType){
ParameterizedType paraType = (ParameterizedType)type;
genericType = (Class<T>)paraType.getActualTypeArguments()[0];
}
}
@Override
public long insert(String sql, Object... args) {
int id = 0;
Connection conn = null;
PreparedStatement psmt = null;
ResultSet rs = null;
try {
conn = ThreadLocalContext.getInstance().getConnetion();
psmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
if(args != null){
for (int i = 0; i < args.length; i++) {
psmt.setObject(i+1, args[i]);
}
}
psmt.executeUpdate();
rs = psmt.getGeneratedKeys();
if(rs.next()){
id = rs.getInt(1);
}
} catch (Exception e) {
throw new DBException();
} finally{
JDBCUtils.release(rs, psmt);
}
return id;
}
@Override
public void update(String sql, Object... args) {
Connection conn = null;
try {
conn = ThreadLocalContext.getInstance().getConnetion();
queryRunner.update(conn, sql, args);
} catch (Exception e) {
throw new DBException();
}
}
@Override
public T query(String sql, Object... args) {
T entity = null;
Connection conn = null;
try {
conn = ThreadLocalContext.getInstance().getConnetion();
entity = queryRunner.query(conn, sql, new BeanHandler<>(genericType), args);
} catch (Exception e) {
throw new DBException();
}
return entity;
}
@Override
public List<T> queryForList(String sql, Object... args) {
List<T> entityList = null;
Connection conn = null;
try {
conn = ThreadLocalContext.getInstance().getConnetion();
entityList = queryRunner.query(conn, sql, new BeanListHandler<>(genericType), args);
} catch (Exception e) {
throw new DBException();
}
return entityList;
}
@Override
public <V> V getSingleVal(String sql, Object... args) {
Connection conn = null;
try {
conn = ThreadLocalContext.getInstance().getConnetion();
return queryRunner.query(conn, sql, new ScalarHandler<V>(), args);
} catch (Exception e) {
throw new DBException();
}
}
@Override
public void batch(String sql, Object[]... params) {
Connection conn = null;
try {
conn = ThreadLocalContext.getInstance().getConnetion();
queryRunner.batch(conn, sql, params);
} catch (Exception e) {
throw new DBException();
}
}
}