高效掌握JDBC技术(三) 三层架构理念 书写符合事务特性的工具类 JUnit测试框架 JDBC项目开发步骤(2)

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  1. 书写Service
package com.bz.service;

public interface UserService {
    /\*\*
 \* 用户登录
 \* @param username 用户输入的账号名
 \* @param pwd 用户输入的密码
 \* @return 是否登录成功
 \*/
    boolean login(String username,String pwd) throws Exception;
}

  1. 书写ServiceImpl
package com.bz.service.impl;

import com.bz.dao.UserDao;
import com.bz.dao.impl.UserDaoImpl;
import com.bz.service.UserService;

public class UserServiceImpl implements UserService {
    //创建Dao对象
    private UserDao ud=new UserDaoImpl();

    @Override
    public boolean login(String username, String pwd)throws Exception {
        if (ud.selectUser(username, pwd)!=null) {
            return true;
        }else{
            return false;
        }
    }
}


  1. 书写view
package com.bz.view;

import com.bz.service.UserService;
import com.bz.service.impl.UserServiceImpl;

import java.util.Scanner;

/\*\*
 \* 用户登录
 \*/
public class UserloginTest {
    public static void main(String[] args) throws Exception{

        UserService us=new UserServiceImpl();

        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String username=sc.next();
        System.out.println("请输入密码:");
        String pwd=sc.next();

        //调用Service方法判断登录是否成功
        if (us.login(username,pwd)){
            System.out.println("登录成功!");
        }else {
            System.out.println("登录失败");
        }


    }
}


2、事务及JDBCUtils最终版

  • 回顾事务概念:将多个操作步骤归为同一个原子操作,要么同时成功,要么同时失败

开启事务

执行操作

结束事务:commit rollback

  • 通常需要添加在Service层,Service层的所有功能方法都应该配套事务

2.1、事务基本操作与问题解决

  1. 开启事务:Connection对象.setAutoCommit(false)
  2. 结束事务:
    • 提交:Connection对象.commit();
    • 回滚:Connection对象.rollback();
2.1.1、存在问题

操作事务和操作数据库数据的数据库连接不是同一个,或导致事务回滚不会影响数据库内容

2.1.2、解决方案:ThreadLocal
  • 思路: 放入线程的存储空间中,ServiceDAO不再自行创建conn,如有需要,直接从线程存储空间中取出

  • 实现:

    1. 确保工具类只会创建一个conn对象
    2. 使用ThreadLocal将工具类创建的conn对象放入存储空间

    ThreadLocal:可以操作线程存储空间的工具,可以对空间的数据进行添加、获取、删除

    添加:ThreadLocal对象.set(数据)

    获取:ThreadLocal对象.get()

    删除:ThreadLocal对象.remove()

  • 使用:

    • 由于DAO和Service共用同一个conn,并且Service一定晚于DAO执行结束,所以为了确保Service的执行,DAO中不能关闭conn,该操作应由Service完成

2.2、JDBCUtils-最终版

package com.bz.util;

import java.io.InputStream;
import java.sql.\*;
import java.util.Properties;

/\*\*
 \* 工具类:方便方法调用,所有方法都应为静态方法
 \*/
public class JDBCUtils {
    //提升集合的作用范围,确保getConnection方法中也能使用
    private static Properties p=null;
    //创建操作线程存储空间的工具对象
    private static ThreadLocal<Connection> tl=new ThreadLocal<>();

    //把流对象的创建放入静态初始代码块,确保在工具类类加载时执行
    static{
        try(
                //通过类对象.getResourseAsStream()获取一个字节输入流对象
                //当前配置文件在src之下
                InputStream is=JDBCUtils.class.getResourceAsStream("/jdbc.properties");
        ){
            //创建用来接收的Properties集合
            p=new Properties();
            //调用方法加载配置文件的内容至集合中
            p.load(is);
            //1. 加载驱动
            Class.forName(p.getProperty("driverClassName"));
        }catch (ClassNotFoundException e) {
            System.out.println("驱动路径不正确");
        } catch (Exception e){
            e.printStackTrace();
        }

    }

    /\*\*
 \* 获取Connection连接
 \* @return
 \*/
    public static Connection getConnection(){
        Connection conn =tl.get();
        try {
            if (conn==null) {//这里如果线程存储空间里没有conn就创建conn并存入线程空间
                //2. 获取连接
                //连接的url
                String url = p.getProperty("url");
                //用户名
                String username = p.getProperty("username");
                //密码
                String pwd = p.getProperty("password");
                conn = DriverManager.getConnection(url, username, pwd);
                //将新创建的conn放入线程的存储空间
                tl.set(conn);
            }
        } catch (SQLException e) {
            System.out.println("获取连接失败");
        } catch (Exception e) {
            System.out.println("未知异常");
            e.printStackTrace();
        }
        return conn;
    }
    /\*\*
 \* 关闭资源连接 非空判断:防止空指针
 \* @param rs
 \* @param ps
 \* @param conn
 \*/
    public static void close(ResultSet rs, PreparedStatement ps,Connection conn){
        if (rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                System.out.println("关闭rs失败");
            }
        }
        if (ps!=null){
            try {
                ps.close();
            } catch (SQLException e) {
                System.out.println("关闭ps失败");
            }
        }
        if (conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                System.out.println("关闭conn失败");
            }
        }
    }
}

3、JUnit测试框架

  • 作用:DAO层和Service层中的方法通常需要经过测试JUnit可以通过@Test注解完成执行测试,大大减少测试成本

3.1、使用步骤

  1. 导入jar包:

    • hamcrest-core-1.3.jar
    • junit-4.12.jar
  2. 创建测试类

    • 命名:被测试的类/接口+Test
    • 包:须放在test包下
  3. 使用

    • @Test注解必须写在方法上方
    • 方法必须为公开、非静态、无参、无返回值的最普通的普通方法
    • 一个测试方法中只能测试一个方法
    • 通常情况下,测试方法名应与被测试方法一致,目的更为清晰

3.2、使用示例

package com.bz.test;

import com.bz.dao.AccountDao;
import com.bz.dao.impl.AccountDaoImpl;
import com.bz.entity.Account;
import org.junit.Test;

public class AccountDaoImplTest {

    //创建被测试的对象
    AccountDao ad=new AccountDaoImpl();

    @Test
    public void selectAccountByName(){
        Account a = ad.selectAccountByName("张三");
        System.out.println(a);
    }
    @Test
    public void updateAccountByName(){
        int n = ad.updateAccountByName("张三", 100);
        System.out.println(n);
    }
}

4、JDBC项目开发步骤总结

首先要根据要求来建库建表(数据库的内部操作)

  1. 导入jar包:

hamcrest-core-1.3.jar
junit-4.12.jar
mysql-connector-java-8.0.23.jar
2. 添加工具类(JDBCUtils最终版)
3. 在src下添加工具类所需的jdbc.properties
4. 书写实体类
5. 搭建DAO

* **必须测试**
  1. 搭建Service

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

[外链图片转存中…(img-DHPzXYWX-1715636686238)]
[外链图片转存中…(img-0tO8ON4g-1715636686239)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 22
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. EasyMock是一款什么类型的测试工具? A. 单元测试工具 B. 集成测试工具 C. 端对端测试工具 D. 性能测试工具 2. JUnit是一款什么类型的测试框架? A. 单元测试框架 B. 集成测试框架 C. 端对端测试框架 D. 性能测试框架 3. JProfiler是一款用于哪种类型应用程序的分析工具? A. Web应用程序 B. 移动应用程序 C. 桌面应用程序 D. 云应用程序 4. JMeter是一款用于哪种类型应用程序的压力测试工具? A. Web应用程序 B. 移动应用程序 C. 桌面应用程序 D. 云应用程序 5. QTP是一款什么类型的自动化测试工具? A. 单元测试工具 B. 集成测试工具 C. 端对端测试工具 D. 功能测试工具 6. EasyMock可以用于什么类型的测试? A. 单元测试 B. 集成测试 C. 端对端测试 D. 手动测试 7. JProfiler可以用来做什么? A. 性能分析 B. 功能测试 C. 压力测试 D. 安全测试 8. JMeter可以使用哪些协议进行测试? A. HTTP B. FTP C. JDBC D. 所有以上选项 9. QTP是哪个公司的产品? A. IBM B. Microsoft C. Oracle D. HP 10. EasyMock可以模拟哪些对象? A. 接口 B. 抽象类 C. 具体类 D. 所有以上选项 11. JProfiler可以检测哪些性能问题? A. 内存泄漏 B. 死锁 C. 阻塞 D. 所有以上选项 12. JMeter可以模拟哪些用户行为? A. 点击链接 B. 填写表单 C. 下载文件 D. 所有以上选项 13. QTP可以测试哪些应用程序类型? A. Web应用程序 B. Windows桌面应用程序 C. Java应用程序 D. 所有以上选项 14. EasyMock可以验证哪些方法的调用? A. public方法 B. private方法 C. final方法 D. 所有以上选项 15. JProfiler可以分析哪些应用程序类型? A. Java应用程序 B. C#应用程序 C. Python应用程序 D. 所有以上选项 16. JMeter可以模拟哪些网络协议? A. TCP/IP B. SMTP C. POP3 D. 所有以上选项 17. QTP可以与哪些测试管理工具集成? A. Quality Center B. JIRA C. TFS D. 所有以上选项 18. EasyMock可以使用哪些语言进行编写? A. Java B. C++ C. Python D. 所有以上选项 19. JProfiler可以检测哪些JVM参数? A. GC参数 B. 内存参数 C. 线程参数 D. 所有以上选项 20. JMeter使用哪种脚本语言来编写测试用例? A. Java B. C++ C. Python D. JMeter专用的脚本语言

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值