解密ThreadLocal类
转:http://qifuguang.me/2015/09/02/[Java%E5%B9%B6%E5%8F%91%E5%8C%85%E5%AD%A6%E4%B9%A0%E4%B8%83]%E8%A7%A3%E5%AF%86ThreadLocal/
事务操作
在了解完ThreadLocal类的特性之后,之后我们可以根据该类特性实现在事务的操作中Connection的不变问题。
创建一个过滤器TranactionFilter
public class TranactionFilter implements Filter {
public TranactionFilter() { }
public void destroy() { }
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 把连接和当前线程绑定
ConnectionContext.getInstance().bind(connection);
//4. 把请求转给目标 Servlet
chain.doFilter(request, response);
//5. 提交事务
connection.commit();
} catch (Exception e) {
e.printStackTrace();
//6. 回滚事务
try {
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
HttpServletResponse resp = (HttpServletResponse) response;
HttpServletRequest req = (HttpServletRequest) request;
resp.sendRedirect(req.getContextPath() + "/error-1.jsp");
} finally{
//7. 解除绑定
ConnectionContext.getInstance().remove();
//8. 关闭连接
JDBCUtils.release(connection);
}
}
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
}
在web.xml中配置
<filter>
<display-name>TranactionFilter</display-name>
<filter-name>TranactionFilter</filter-name>
<filter-class>bookstore.filter.TranactionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>TranactionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
ConnectionContext类 的实现
public class ConnectionContext {
//私有化构造器,
private ConnectionContext(){}
//单例模式,只创建一个对象
private static ConnectionContext instance = new ConnectionContext();
public static ConnectionContext getInstance() {
return instance;
}
private ThreadLocal<Connection> connectionThreadLocal =
new ThreadLocal<>();
//把参数connection与当前线程绑定
public void bind(Connection connection){
connectionThreadLocal.set(connection);
}
//获取绑定到线程中的connection
public Connection get(){
return connectionThreadLocal.get();
}
//删除线程中的局部属性( 即connection )
public void remove(){
connectionThreadLocal.remove();
}
}
在bookservice类中操作具体的业务,调用不同的DAO实现
public class BookService {
private BookDAO bookDAO = new BookDAOImpl();
private AccountDAO accountDAO = new AccountDAOIml();
private TradeDAO tradeDAO = new TradeDAOImpl();
private UserDAO userDAO = new UserDAOImpl();
private TradeItemDAO tradeItemDAO = new TradeItemDAOImpl();
//业务方法.
public void cash(ShoppingCart shoppingCart, String username,
String accountId) {
//1. 更新 mybooks 数据表相关记录的 salesamount 和 storenumber
bookDAO.batchUpdateStoreNumberAndSalesAmount(shoppingCart.getItems());
//当发生异常,整组业务操作全部rollBack回滚;
int i = 10 / 0;
//2. 更新 account 数据表的 balance
accountDAO.updateBalance(Integer.parseInt(accountId), shoppingCart.getTotalMoney());
//3. 向 trade 数据表插入一条记录
Trade trade = new Trade();
trade.setTradeTime(new Date(new java.util.Date().getTime()));
trade.setUserId(userDAO.getUser(username).getUserId());
tradeDAO.insert(trade);
//4. 向 tradeitem 数据表插入 n 条记录
Collection<TradeItem> items = new ArrayList<>();
for(ShoppingCartItem sci: shoppingCart.getItems()){
TradeItem tradeItem = new TradeItem();
tradeItem.setBookId(sci.getBook().getId());
tradeItem.setQuantity(sci.getQuantity());
tradeItem.setTradeId(trade.getTradeId());
items.add(tradeItem);
}
tradeItemDAO.batchSave(items);
//5. 清空购物车
shoppingCart.clear();
}
}
在DAO中的连接数据库接口的实现方法中connection始终是同一个,即可保证事务安全
业务方法调用层次结构及DAO层获取connection的实现
比如
//2. 更新 account 数据表的 balance
accountDAO.updateBalance(Integer.parseInt(accountId), shoppingCart.getTotalMoney());
转到
public class AccountDAOIml extends BaseDAO<Account> implements AccountDAO {
@Override
public void updateBalance(Integer accountId, float amount) {
String sql = "UPDATE account SET balance = balance - ? WHERE accountId = ?";
update(sql, amount, accountId); //重写的BaseDao中update方法
}
}
再转
public void update(String sql, Object... args) {
Connection connection = null;
try {
connection = ConnectionContext.getInstance().get();//ConnectionContext是个单例类
queryRunner.update(connection, sql, args);
} catch (Exception e) {
e.printStackTrace();
}
}