网 上 书 城
发布日期:2018-12-10 作者:atguigu 1615人浏览
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