关于 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;
imp
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;
imp
imp
imp
imp
/**
* 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;
imp
imp
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();
}
}
}