网 上 书 城

1. 添加事务

  • 如果我们将saveOrder的SQL语句故意写错,模拟一个数据库出现异常的情况,订单将不能正常插入到数据库中,同时,由于订单号不存在,订单项也将不能插入进数据库。但是,图书的库存销量却发生了改变。
  • 所以我们要在项目中添加事务控制
  • 我们在结账的操作中分别调用了三个DAO,OrderDao、OrderItemDao、BookDao。对数据库做操作,三次操作就是一事务,三个操作要么都成,要么都失败。
  • 事务控制的关键在同一个事务中,不同的操作要求使用同一个的数据库连接

2.1使用ThreadLocal<T>对象保证一个线程对应一个数据库连接

  • 在Java中有一个类叫ThreadLocal,在ThreadLocal的内部实际维护着一个Map,这个Map的Key就是当前线程对象,值就是你想存的的对象,所以我们一般使用ThreadLocal来在同一个线程中共享数据,他的作用有点像域对象。
  • ThreadLocal<T>中常用的方法
    • void set(T t) →向ThreadLocal保存一个对象
    • Tget() → 获取当前线程中保存的对象
    • void remove() →移除当前线程中保存的对象

2.2使用过滤器Filter控制事务

  • 我们在项目中添加一个TransactionFilter,用于控制事务,我们在Filter中先获取数据库连接,然后开启事务,接着放行请求,当响应回来的时候,还会回到Filter,这时我们的Filter可以对异常进行捕获,如果出现异常则回滚事务,如果没出现则提交事务。
  • 如果添加TransactionFilter,那么所有的数据连接的关闭操作都应该在Filter中统一处理,而不应该再在DAO中操作,所以BaseDao中所有释放数据库连接的代码,全都应该注释掉。
  • 我们在Filter统一处理事务,那么就希望异常可以一直抛到Filter中,然后Filter一旦捕获到异常就可以自动的回滚。但是我们发现异常在BaseDao中都被try…catch捕获了,如果直接throws向上抛异常那么它的父类也需要throws,比较麻烦!
  • 所以我们就需要在BaseDao中将所有捕获到SQLException转换为RuntimeException向上抛。
  • 当我们在BaseDao中将异常向上抛以后,又出现了这么一个异常:
    • lang.reflect.InvocationTargetException
    • 这个异常一般在通过反射调用一个方法时,当那个方法有异常时,会导致抛出该异常。
  • 我们在BaseServlet中通过反射调用Servlet中的方法,当方法有异常以后,又被BaseServlet捕获了,所以我们需要在BaseServlet中继续将异常向上抛。
  • 当我们在BaseServlet中将异常向上抛以后,的确出现变化了,但是页面并没有转到错误页面,也是说异常并没有被Filter捕获到,而是出现500,证明异常被服务器捕获了。
  • 原因:我们在Filter中捕获的是SQLException,但是异常过来的时候是RuntimeExeption,所以我们Filter没有捕获该异常,这里我们需要修改Filter捕获的异常类型为Exception。

3. 使用Ajax

3.1注册页面使用Ajax验证用户名是否可用

3.2修改购物车中图书数量使用Ajax