• TOMCAT封装DBCP



    ## 数据源 ##

    #Tomcat封装的DBCP;

    >> 基本知识;
    tomcat在默认情况下已经集成了DBCP;

    >> JNDI;
    |-- 基本概念;
    在tomcat启动的时候会根据用户的要求创建好
    数据源,并根据名字将数据源绑定;它内部维护一个
    Map集合,Key是一个由路径和名字构成的字符串,Value是
    绑定的数据源对象;
    <-??->什么是数据源;
    |-- 优势;
    提高获取连接的效率;

    >> 基本开发步骤;
    |-- 将数据库需要的驱动jar包放到lib目录下;
    |-- 将登录需要的用户名和密码的XML配置文件放到META-INF目录下;
    |-- 位置;
    > doc --> JNDI --> Confige context...>

    |-- 启动tomcat;
    |-- 特别注意;
    > 对于数据源的测试不要放到main方法当中测试;


    ## 元数据 ##

    # 基本概念;
    数据库,表,列等定义的信息;
    简单来说就是对于Java来说,用于描述数据库的信息;

    # 基本操作;

    >> 基本方法接口 --- Connection

    Connection.getMetaData()获取关于数据库的整体综合信息。

    DataBaseMetaData 元数据对象

    getURL():返回一个String类对象,代表数据库的URL。

    getUserName():返回连接当前数据库管理系统的用户名。

    getDatabaseProductName():返回数据库的产品名称。(告诉habuneite方言是什么)

    getDatabaseProductVersion():返回数据库的版本号。

    getDriverName():返回驱动驱动程序的名称。

    getDriverVersion():返回驱动程序的版本号。

    isReadOnly():返回一个boolean值,指示数据库是否只允许读操作。

    >> 具体Demo --- 参见MetaDateTest.java

    # 实际应用;
    因为可以通过获取元数据方式,获取到数据库中对应的列名;
    由此可以和domain中UserBean对应的属性相对应;
    由此可以简化DAO层中的CRUD操作;

    ## 自定义框架 ##

    # ORM 对象关系映射;

    >> Object; JavaBean对象;
    >> Relation:关系型数据库;
    >> Mapping;映射(存储应对关系);


    ## DBUtils ##

    # 基本使用;
    >> 导包;
    >> 定义DAO接口及实现类;
    >> 直接获取QuerRunner对象便可以直接使用;

    ## 实际开发中的事物控制 ##

    # 案例 --- 转账;

    >> 基本步骤;
    |-- DAO层中建立转账方法;
    |-- DAO实现类中实现具体的转账方法;
    |-- 具体分析;
    > 源账户数据减少;
    > 目标账户数据增加;

    > 更新 update;
    > 问题 --- 如何获取连接;
    |-- QueryRunner支持无参构造;
    |-- update支持重载方法中,在执行中放入链接;
    > 两个update是否需要同一个链接;

    > 提交事务;
    |-- 如果出现异常需要进行回滚;

    |-- 测试事务是否保持;
    |-- 修改Client类;// 这是一个测试类,测试main方法在当中;

    |-- 问题 --- DAO层中出现了业务逻辑代码;
    |-- 建立一个Service类;
    > 改写DAO层;
    |-- 根据账户名查询得到一个账户;
    |-- 根据账户名更新账户的金额;

    |-- 在Service实现类中完成业务逻辑代码;
    |-- 根据账户名得到账户对象;
    |-- 调用DAO中方法;

    |-- 根据目标对象名,得到一个目标账户;
    |-- 调用DAO中方法;

    |-- 更新余额;
    |-- 调用对象中的方法,源账户减少,目标账户增加;

    |-- 问题:链接不确定;--- 无法确保查询和更新使用的链接是同一个;
    |-- 解决方案:
    > 在DAO的实现类中建立一个链接;
    > 通过构造参数接收一个链接;

    |-- 将数据封装到表中;

    > 问题 : 如何开启事务;
    |-- 该怎么开怎么开;

    > 处理异常;
    > 提交事务;

    |-- 将setAutoCommit(true); 放到finally当中
    <-??-> 这是啥?

    |-- 进行测试,看事务状态是否能够保持住;
    |-- 临时问题:
    在回滚操作时,捕获的异常应该是Exception;

    |-- 最终问题:
    |-- Connection作为数据库连接应该出现在DAO中,
    如果connection不存在,开启事务的代码应该不执行;
    所以开启事务的代码不能放在业务层;

    |-- 结论:开启事务的逻辑代码不应该放在业务层;

    |-- 重新建立一个工程;
    |-- 修改Service实现类;
    |-- 将提交事务相关的方法都删除;

    |-- 问题:事务应该放在哪一层?
    |-- 解决方案;
    > 参见新知识点;ThreadLocal

    > 推论:
    因为两次调用find方法和update方法
    都在main开启的主线程当中,
    所以可以考虑将它们全部封入一个
    ThreadLocal线程当中,然后再将
    Connection放入,好像可以解决问题...
    <-??-> 我还是不知道事务应该放在哪一层;

    > 去掉DAO实现类当中的con;

    > 分离事务控制代码,专门用一个类来进行事务的处理;
    |-- 传说中的"方面代码";专注于处理某个方面的代码;
    |-- 建立一个获取Connection的方法;
    |-- 比较重要的部分,如果没有链接后面的方法都无法工作;
    |-- 详细分析;
    > 问题 --- 已经有连接池了,为何还需要自己获取链接?
    |-- 为了保证获取到的链接的一致性;

    > 引入ThreadLocal ;//用于放入Connection,并保证使用的是唯一的Connection
    > 从线程局部变量中取出一个connection;
    > 从连接池中取出一个链接;
    > 将线程池中的链接放入线程局部变量;

    |-- 建立一个开启事务的方法;
    |-- 获取链接;
    |-- 开启事务;

    |-- 建立一个提交事务的方法;
    |-- 获取链接;
    |-- 提交事务;

    |-- 建立一个回滚的方法;
    |-- 获取链接;
    |-- 回滚;

    |-- 更新Service类;
    >> 在第一行调用事务类的开启事务功能;

    |-- 对DAO的实现类进行修改;
    >> 修改对应的获取事务和链接的部分;

    |-- 问题 --- 虽然进行了独立封装,但控制事务的代码依然放在业务层当中;
    |-- 分析解决方案;
    |-- 新建一个工程;

    |-- 最终版本;
    >> 分析;
    |-- 新建一个BeanFactory类;
    |-- 提供一个方法,返回一个AccountService对象;
    |-- AOP 新知识点;(面向切面/方面编程)
    > 基本概念;
    将事物的某个方面的功能代码抽取出来,
    进行集中实现,当系统需要用到该功能的时候,
    重新将方面代码加入到系统当中;
    忽略了原有继承体系的纵向结构,可以在需要的时候
    横向插入关键代码;

    > 实现原理;
    如何完成将代码实现横向织入;
    |-- 动态代理;

    > 适用场景;
    |-- 事务控制;
    |-- 日志控制;
    |-- 权限集中管理;
    |-- 积分功能;

    |-- 实现动态代理;
    |-- Proxy.newProxyInstance(loader,interface,h){

    }
    |-- loader --- 需要代理的类加载器;
    |-- interface --- 类所实现的接口;
    |-- h
    > 代理类自己的实现方法,实质上是一个
    匿名内部类;

    |-- 进行判断,如果方法名为需要代理的方法;
    |-- 需要保证原有方法能够执行;
    |-- 横向加入事务开启的方法;
    |-- 进行事务的常规处理;

    |-- 改写Client类;
    |-- 在创建对象时不再使用new,而是使用BeanFactory的方法;


    ## ThreadLocal ##

    # 基本概念;
    内部维护一个Map集合,Key是当前线程对象,Value是一个Object对象;
    由于一个线程中的值只能有当前线程能够获取;


    # 基本操作方式;
    >> set(Object value);
    |-- 解释;
    之所以只需要传入Value就可以使用,
    是因为key默认的是当前线程对象,所以只需要传入
    对应的value就可以设置当前线程对象的值;
    >> remove();
    >> get();

    # 使用测试;
    >> 建立一个main的测试类;
    |-- 因为main默认开启了一个主线程;

    >> 建立一个ThreadLocal对象;
    |-- 简单测试;
    > 自己放入一个值,可以自己进行获取;

    >> 建立一个子线程;
    |-- 通过构造方法,从父类接收一个ThreadLocal对象;
    |-- 测试是否无法让其他对象访问该线程;
    |-- 通过子线程调用get方法去获取main线程当中存入的值,看是否能够成功输出;


  • 相关阅读:
    医学影像
    阿里云九卿 大数据产业化
    陈海青 阿里
    店铺高频问题主动生成知识点机器 大脑+人脑 知识库
    数据总线和流计算在城市大脑中的应用
    无推荐不APP
    ww
    业务架构
    jd算法大赛 一个user_id只需映射到一个sku_id, 但是一个sku_id能否映射到多个user_id
    短URL DH 密钥交换算法
  • 原文地址:https://www.cnblogs.com/bwcx1375/p/7123489.html
Copyright © 2020-2023  润新知