Spring中dbUtil的概念和搭建使用

embedded/2024/11/9 16:45:04/

目录

dbUtil-toc" style="margin-left:80px;">1、什么是dbUtil

2、lombok插件

dbUtil%E9%80%9A%E8%BF%87xml%E6%9D%A5%E5%AE%9E%E7%8E%B0-toc" style="margin-left:80px;">3、dbUtil通过xml来实现

4、SpringJunit的作用和效果

(1)标记测试方法和配置方法的注解

dbUtil%E9%80%9A%E8%BF%87%E6%B3%A8%E9%87%8A%E6%9D%A5%E5%AE%9E%E7%8E%B0-toc" style="margin-left:80px;">5、dbUtil通过注释来实现

dbUtil%E9%80%9A%E8%BF%87config%E9%85%8D%E7%BD%AE%E7%B1%BB%E6%9D%A5%E5%AE%9E%E7%8E%B0-toc" style="margin-left:80px;">6、dbUtil通过config配置类来实现

dbUtil%E9%80%9A%E8%BF%87aop%E7%9A%84XML%E7%9A%84%E5%AE%9E%E7%8E%B0-toc" style="margin-left:80px;">7、dbUtil通过aop的XML的实现

(1)连接工具类

(2)事务工具类

(3)service层业务事务逻辑实现    


dbUtil">1、什么是dbUtil

        dbUtil阿帕奇提供操作数据库的插件,它主要用于减少样板代码,并简化Java程序与数据库的交互。

  • 简化ResultSet处理:DBUtils 提供了 ResultSetHandler 接口和一些常用的实现类,用于将 ResultSet 转换为Java对象或集合。
  • 简化SQL执行:DBUtils 提供了 QueryRunner 类,用于执行SQL查询和更新操作。它提供了简洁的方法来处理参数和处理结果集。
  • 处理资源的关闭:DBUtils 提供了 DbUtils 类,其中包含关闭数据库连接、语句和结果集的方法,以确保资源在使用后被正确释放。

2、lombok插件

        如果你有一个人员信息的bean类,如果其中删除某个数属性或者添加某个属性,难道我们要去重新写所有的set、get、构造方法吗,这时候就可以用idea提供的lombok插件来完成这个代码维护。

        lombok是用于简化 Java 编码过程中的样板代码(boilerplate code)。它通过注解处理器在编译时生成代码,帮助开发者减少编写样板代码的负担。Lombok 提供了多种注解,用于自动生成常见的 Java 代码,例如 getter、setter、构造函数、toString 方法等。

        首先在pom.xml配置lombok配置:

       <!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.26</version></dependency>

        接下来就可以在pojo类中去简化一个Bean对象的getset等诸多方法。

java">// 这个注解会生成一个无参构造方法。
@NoArgsConstructor
// 这个注解会生成一个包含所有字段的构造方法。
@AllArgsConstructor
// 这个注解是一个综合性注解,它会生成以下常用的方法:
// getter和setter方法
// toString方法
// equals和hashCode方法
// 还会生成一个canEqual方法
@Data
public class Account {private int aid;private String aname;private int amoney;public Account(String aname, int amoney) {this.aname = aname;this.amoney = amoney;}}
  • @NoArgsConstructor:是生成的无参构造方法。
  • @AllArgsConstructor:是自动生成包含所有字段的构造函数。
  • @RequiredArgsConstructor:自动生成包含 final 字段和带有 @NonNull 注解字段的构造函数。
  • @Data:自动生成多个常见的样板代码,包括 getter、setter、toString、equals 和 hashCode 方法等。

dbUtil%E9%80%9A%E8%BF%87xml%E6%9D%A5%E5%AE%9E%E7%8E%B0">3、dbUtil通过xml来实现

        首先是XML中定义一个数据库连接池Bean注入数据源

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="${msg1}"></property><property name="jdbcUrl" value="${msg2}"></property><property name="user" value="${msg3}"></property><property name="password" value="${msg4}"></property></bean>

        id属性指的是Bean名称,class这里指的是ComboPooledDataSource,是C3P0提供的一个实现类,这个实现类中有driverClass等jdbc的set方法,通过使用Spring的占位符(${}),这些属性值从外部配置文件中读取。

        dataSorce是管理数据库连接的,使用 getConnection() 方法可以从数据源中获取一个 Connection 对象,从而执行 SQL 查询和更新操作。

       

        然后是注入QueryRunner

    <bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner"><constructor-arg name="ds" ref="dataSource"></constructor-arg></bean>

        这里的class是org.apache.commons.dbutils.QueryRunner类创建的一个queryRunner的实例,再通过ds这个构造函数注入数据源dataSource。dataSource 是之前定义的 ComboPooledDataSource的Bean,用于管理数据库连接。

        然后是注入dao、注入service、注入controller

    <!--注入dao--><bean id="mapperImp" class="com.apesource.dao.AccountMapperImp"><property name="queryRunner" ref="queryRunner"></property></bean><!--注入service--><bean id="service" class="com.apesource.service.AccountServiceImp"><property name="mapper" ref="mapperImp"></property></bean><!--注入controller--><bean id="controller" class="com.apesource.controller.AccountControllerImp"><property name="service" ref="service"></property></bean>

        其中dao注入的是queryRunner,用它来执行SQL查询和更新操作,与数据库之间的交互。

        其次是dao层中的接口和实现类:

        接口IAccountMapper:

java">public interface IAccountMapper {public void save(Account account);public Account findByName(String name);public List<Account> findAll();public void updateById(Account account);public void deleteById(int id);
}

        里面定义了增删改查的抽象方法。 

        其次是AccountMapperImp实现类:

java">public class AccountMapperImp implements IAccountMapper {//操作数据库的核心类QueryRunner queryRunner;public void setQueryRunner(QueryRunner queryRunner) {this.queryRunner = queryRunner;}@Overridepublic void save(Account account) {try {queryRunner.update("insert into account(aname,amoney) value(?,?)",account.getAname(),account.getAmoney());} catch (SQLException throwables) {throwables.printStackTrace();}}@Overridepublic Account findByName(String name) {try {queryRunner.query("select * from account where name = ?",new BeanHandler<Account>(Account.class),name);} catch (Exception e) {e.printStackTrace();}return null;}@Overridepublic List<Account> findAll() {try {return queryRunner.query("select * from account",new BeanListHandler<Account>(Account.class));} catch (SQLException throwables) {throwables.printStackTrace();}return null;}@Overridepublic void updateById(Account account) {try {queryRunner.update("update account set aname=?,amoney=? where aid=?",account.getAname(),account.getAmoney(),account.getAid());} catch (SQLException throwables) {throwables.printStackTrace();}}@Overridepublic void deleteById(int id) {try {queryRunner.update("delete from account where aid=?",id);} catch (SQLException throwables) {throwables.printStackTrace();}}
}

        首先实现类继承了接口,重新了其中的方法,其中在中间创建一个成员变量queryRunner用于执行数据库操作的核心类,并通过set方法通过xml注入的方式设置 QueryRunner 实例。

        QueryRunner中有两个方法,一个为query,用来查询。一个为update,用来增删改。?为要传的参数,后面依次跟上传入的参数值。

        其中findAll()方法中是要查询所有的学生,返回的学生集合,所以这里出现了new BeanListHandler<Account>,因为 BeanListHandler 是 Apache Commons DBUtils 库中用于处理 ResultSet 的一种处理器。它将结果集中的每一行映射为一个 Java 对象,并将这些对象收集到一个 List 中

        

        service层、controller层:用户传入参数给controller层,controller层传给service层,一层套一层来传递,这里我就只给一个service层的代码,controller层一样的道理。

java">public class AccountServiceImp implements IAccountService {private IAccountMapper mapper;public void setMapper(IAccountMapper mapper) {this.mapper = mapper;}@Overridepublic void save(Account account) {mapper.save(account);}@Overridepublic Account findByName(String name) {return mapper.findByName(name);}@Overridepublic List<Account> findAll() {return mapper.findAll();}@Overridepublic void updateById(Account account) {mapper.updateById(account);}@Overridepublic void deleteById(int id) {mapper.deleteById(id);}
}

        通过controller层传递来的参数,通过XML里面的Bean来创建一个mapper对象,再把参数传递给mapper的方法,去dao层中的方法实现逻辑。

4、SpringJunit的作用和效果

        然后就是如果我们的想要去调用方法难道要写很多个测试类吗,所以Spring中提供了Junit,用于编写和运行可重复的测试。它主要用于单元测试,但也可以用于集成测试。JUnit 提供了一组注解、断言和运行测试的工具,使得测试代码变得简洁而易于理解。

(1)标记测试方法和配置方法的注解
@Test可以运行的测试方法
@Before在每个@Test运行之前执行。常用于初始化测试环境。
@After在每个@Test运行之后执行。常用于清理测试环境。
@BeforeClass在所有@Test运行之前执行一次。常用于耗时的全局初始化。
@AfterClass在所有@Test运行之后执行一次。常用于全局资源的释放。

        实例代码(手动管理):

java">public class Test01 {ClassPathXmlApplicationContext applicationContext = null;IAccountController controller = null;@Beforepublic void beforeMethod() {applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");controller = (IAccountController) applicationContext.getBean("controller");}@Afterpublic void afterMethod() {applicationContext.close();}@Testpublic void show1() {controller.save(new Account("大头", 2000));controller.save(new Account("小头", 2000));}@Testpublic void show2() {List<Account> all = controller.findAll();for (int i = 0; i < all.size(); i++) {Account account = all.get(i);System.out.println(account);}}@Testpublic void show3(){controller.updateById(new Account(2,"大头",1000));}
}

        上面的代码是去手动的调用applicationContext对象和getBean方法,有没有一种写法可以不用手动的去写这些需求操作呢。这里就用到自动管理

java">@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class Test02 {@AutowiredIAccountController controller;@Testpublic void show1(){controller.save(new Account("林航宇",2000));controller.save(new Account("杨文琪",2000));}@Testpublic void show2(){List<Account> all = controller.findAll();for (int i = 0; i < all.size(); i++) {Account account =  all.get(i);System.out.println(account);}}
}

        @RunWith()这个注解告诉 JUnit 使用SpringJUnit4ClassRunner类来运行测试。这是一个 Spring 提供的 Runner,它可以在 JUnit 测试中加载 Spring 应用上下文,并将 Spring 的依赖注入机制与 JUnit 测试结合起来。

        @ContextConfiguration()这个注解指定了 Spring 应用上下文的配置文件位置。从类路径加载 applicationContext.xml 配置文件。Spring 会根据这个配置文件创建应用上下文,并进行 Bean 的初始化和依赖注入。

dbUtil%E9%80%9A%E8%BF%87%E6%B3%A8%E9%87%8A%E6%9D%A5%E5%AE%9E%E7%8E%B0">5、dbUtil通过注释来实现

        其实和通过xml差不多,只不过将bean标签注入换成了扫描注入通过在controller、service、dao层加上注释来完成bean对象的注入。

        将原本的构造注入换成了注释来实现标签注入

java">@Controller("controller")
public class AccountControllerImp implements IAccountController{@Autowiredprivate IAccountService service;

        再在XML文件中把bean标签注入删除,换成扫描:

java"><context:component-scan base-package="com.apesource"></context:component-scan>

        这里就不过多描述了,跟XML注入非常接近。

dbUtil%E9%80%9A%E8%BF%87config%E9%85%8D%E7%BD%AE%E7%B1%BB%E6%9D%A5%E5%AE%9E%E7%8E%B0">6、dbUtil通过config配置类来实现

        其实也跟前两种非常的接近,就是多了一层config配置类,通过加载配置类来连接数据库和创建bean实例。

java">@Configuration
@PropertySource(value = "classpath:jdbc.properties")
public class DataConfig {@Value("${msg1}")private String driverClass;@Value("${msg2}")private String jdbcUrl;@Value("${msg3}")private String user;@Value("${msg4}")private String password;@Beanpublic DataSource dataSource(){try {ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();comboPooledDataSource.setDriverClass(driverClass);comboPooledDataSource.setJdbcUrl(jdbcUrl);comboPooledDataSource.setUser(user);comboPooledDataSource.setPassword(password);return comboPooledDataSource;} catch (PropertyVetoException e) {e.printStackTrace();}return null;}@Beanpublic QueryRunner queryRunner(){return new QueryRunner(dataSource());}}

        @Configuration:标记 DataConfig 类为 Spring 的配置类,表示这个类包含一个或多个 @Bean 方法,用于定义 Spring 容器中的 Bean。

        @PropertySource("classpath:jdbc.properties"):指定一个或多个属性文件,用于加载应用程序的属性配置。在这里,jdbc.properties 文件位于类路径下。Spring 会将这些属性文件中的属性加载到 Environment 中,以便通过 @Value 注解进行注入。

        @Value是将配置文件中的属性值注入到字段中,将从 jdbc.properties 文件中读取并注入到 DataConfig 类中。

        然后又定义了DataSource,通过 ComboPooledDataSource 配置数据库连接池,创建了dataSource对象。QueryRunner:使用注入的 DataSource 实例来创建 QueryRunner Bean,用于简化数据库操作。

        再通过DataConfig配置类的实现来合作完成ApplicationConfig:

java">@Configuration
@ComponentScan(basePackages = "com.apesource")
@Import(DataConfig.class)
public class ApplicationConfig {
}

        这里@ComponentScan是扫描组件扫描的基础包路径,Spring 会扫描 com.apesource 包及其子包中的所有类,自动识别并注册带有 @Component、@Service、@Repository、@Controller 等注解的 Bean。

java">applicationContext = new AnnotationConfigApplicationContext(ApplicationConfig.class);

        在测试类中通过AnnotationConfigApplicationContext来获取context。

dbUtil%E9%80%9A%E8%BF%87aop%E7%9A%84XML%E7%9A%84%E5%AE%9E%E7%8E%B0">7、dbUtil通过aop的XML的实现

        如果我们在service层写一个逻辑,一个人对另一个人借了多少钱,呢双方的金额都要进行改变,但是如果中间发生了异常,但是没有事务的注入没有发生回滚,那么就会发生逻辑错误,一个人钱少了,一个人没拿到钱。

        这时候我们就要进行注入连接工具类和事务工具类了。

    <!--连接工具类--><bean id="connectionUtil" class="com.apesource.util.ConnectionUtil"><property name="dataSource" ref="dataSource"></property></bean><!--事务工具类--><bean id="transactionUtil" class="com.apesource.util.TransactionUtil"><property name="connectionUtil" ref="connectionUtil"></property></bean>

        在XML中加入这两个注入,一个为管理数据库连接的工具类。在其中注入用构造注入完成了对dataSource的注入。另一个为处理处理数据库事务的工具类,在其中设置 connectionUtil 属性。

        如果想要同时提交或回滚那么就要用同一个connection同一个业务方法的多个dao方法公用一个connection对象,为了确保每个线程都有一个数据库连接,我们就要创建一个Connect再创建一个ConnectionUtil类来管理数据库的连接。如果有连接则就用当前连接,如果没有连接则创建连接。

(1)连接工具类
java">public class ConnectionUtil {//装配数据源DataSource dataSource;public void setDataSource(DataSource dataSource) {this.dataSource = dataSource;}//线程区域对象ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();//获取连接public Connection createCon(){try {//1.获取线程内的连接对象Connection connection = threadLocal.get();//2.判断if (connection==null){connection = dataSource.getConnection();//创建连接threadLocal.set(connection);//保存}return connection;} catch (SQLException throwables) {throwables.printStackTrace();}return null;}//移除连接public void removeCon(){threadLocal.remove();//移除连接对象}}

        ThreadLocal<Connection>:用于在每个线程中存储一个 Connection 实例。

        createCon方法:用于获取当前线程的数据库连接。其中的threadLocal.get():尝试从 ThreadLocal 中获取当前线程的 Connection 实例。如果 ThreadLocal 中没有连接(即 connection 为 null),则通过 dataSource.getConnection() 创建一个新的连接,并将其保存到 ThreadLocal 中。如果有则直接返回当前的connection对象。

        removeCon 方法:用于从 ThreadLocal 中移除当前线程的 Connection 实例和连接。

        

(2)事务工具类
java">public class TransactionUtil {//注入连接工具类ConnectionUtil connectionUtil;public void setConnectionUtil(ConnectionUtil connectionUtil) {this.connectionUtil = connectionUtil;}//开启事务public void beginTx(){try {connectionUtil.createCon().setAutoCommit(false);} catch (SQLException throwables) {throwables.printStackTrace();}}//提交事务public void commitTx(){try {connectionUtil.createCon().commit();} catch (SQLException throwables) {throwables.printStackTrace();}}//回滚事务public void rollbackTx(){try {connectionUtil.createCon().rollback();} catch (SQLException throwables) {throwables.printStackTrace();}}//关闭事务public void closeTx(){try {connectionUtil.createCon().close();//关闭事务connectionUtil.removeCon();//移除事务} catch (SQLException throwables) {throwables.printStackTrace();}}
}

        这个类用于管理数据库事务。它封装了事务的开启、提交、回滚和关闭操作,并依赖于 ConnectionUtil 来获取数据库连接,因为里面定义了dataSourse。

        然后就是事务的开启、提交、回滚、关闭等方法操作。

        开启事务:通过调用createCon()方法获取当前线程的连接,并将其自动提交模式设置为 false。这意味着事务需要手动提交或回滚。

        提交/回滚事务:获取当前线程的连接提交/回滚事务。

        关闭事务:connectionUtil.createCon().close():关闭当前线程的连接,将其返回到连接池中。connectionUtil.createCon().close():关闭当前线程的连接,将其返回到连接池中。

(3)service层业务事务逻辑实现    

        呢么在哪个层加入这个转账的方法呢,就是在service的业务逻辑层来完成逻辑的实现。

java">//装配TransactionUtil transactionUtil;public void setTransactionUtil(TransactionUtil transactionUtil) {this.transactionUtil = transactionUtil;}
@Overridepublic void transfer(String sourceName, String targetName, int money) {try {transactionUtil.beginTx();//1.查询数据Account sourceAccount = mapper.findByName(sourceName);Account targetAccount = mapper.findByName(targetName);//2.转账sourceAccount.setAmoney(sourceAccount.getAmoney()-money);targetAccount.setAmoney(targetAccount.getAmoney()+money);//3.修改数据库mapper.updateById(sourceAccount);// int a = 10/0;//模拟异常mapper.updateById(targetAccount);transactionUtil.commitTx();} catch (Exception e) {e.printStackTrace();transactionUtil.rollbackTx();}finally {transactionUtil.closeTx();}}

        进行装配,在XML中id为service的bean自动构造注入实例化TransactionUtil事务工具类对象。

        首先调用 TransactionUtil 的 beginTx 方法开始一个事务。这会将连接的自动提交模式设置为 false,意味着所有对数据库的操作都将在一个事务中执行,直到提交或回滚。

        其次就是对转账这个逻辑进行相应的操作,查看数据、转账、修改数据库

        紧接着调用.commitTx方法提交事务。service逻辑层就完成了事务的逻辑操作了。

        

        在dao层中的实体类完成了注入连接工具类:

java">    ConnectionUtil connectionUtil;public void setConnectionUtil(ConnectionUtil connectionUtil) {this.connectionUtil = connectionUtil;}

        呢为什么要在dao层获取连接工具类呢,第一,在TransactionUtil中定义了一个ConnectionUtil的成员变量,所以在dao层实例化一个ConnectionUtil对象就可以被service层中的TransactionUtil对象调用。第二,TransactionUtil 需要通过 ConnectionUtil 来获取数据库连接。第三,dao层是与dataSource有直接关系的,所以用dao层来实例化ConnectionUtil。第四,ConnectionUtil要用dataSource,TransactionUtil要用ConnectionUtil,所以逐一迭代的关系分别放在service层和dao层。

        而controller层只用调用transfer方法即可,将参数传入service层。

        总而言之,这种实现方法的本质为通过连接对象对事务的统一管理


http://www.ppmy.cn/embedded/95032.html

相关文章

手机在不同地方ip地址一样吗

在这个数字化时代&#xff0c;手机已成为我们日常生活中不可或缺的一部分&#xff0c;它不仅是我们沟通的工具&#xff0c;更是我们获取信息、娱乐休闲和社交互动的重要平台。然而&#xff0c;你是否曾好奇过&#xff0c;当你带着手机穿梭于不同的地方&#xff0c;手机的IP地址…

Hive学习(一)

一、Hive基本概念 1.简介&#xff1a;是基于Hadoop的一个数据仓库工具&#xff0c;可以将结 构化的数据文件映射成一张表&#xff0c;并提供 SQL查询功能&#xff0c;用于解决海量数据结构化日志的数据统计工具。 2.本质&#xff1a;将HQL转换成MapReduce程序 1&#…

网站如何被Google收录?

想让你的网站快速被Google收录&#xff1f;试试GSI快速收录服务吧&#xff0c;这是通过谷歌爬虫池系统来实现的。这套系统吸引并圈养Google爬虫&#xff0c;提高你网站的抓取频率。每天有大量Google爬虫抓取你的网站页面&#xff0c;大大提高了页面的收录概率&#xff0c;从而增…

FFmpeg源码:avio_tell函数分析

AVIOContext结构体和其相关的函数分析&#xff1a; FFmpeg源码&#xff1a;avio_r8、avio_rl16、avio_rl24、avio_rl32、avio_rl64函数分析 FFmpeg源码&#xff1a;avio_tell函数分析 一、avio_tell函数的定义 avio_tell函数定义在FFmpeg源码&#xff08;本文演示用的FFmpeg…

算法:排序(前言)

所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。排序算法&#xff0c;就是如何使得记录按照要求排列的方法。排序算法在很多领域得到相当地重视&#xff0c;尤其是在大量数据的处理方面。一个优秀的…

Sputnik 打靶渗透

一、信息收集 1、查看靶机的MAC地址&#xff1a; 2、查看靶机的ip地址&#xff1a; nmap 192.168.13.0/24 3、查看靶机开放的端口&#xff1a; nmap -p- -sC -sT -sV -A 192.168.13.159 4、分别访问靶机的8089、55555和61337端口&#xff0c;发现在61337端口有一个登录框&…

服务器远程管理-Windows远程桌面协议实操

目录 1.因为是在内网所有将操控服务器的计算机与服务器放在同一网段&#xff0c;如果是真实服务器可以直接访问其公网ip 2.启用远程桌面 3.在本地计算机连接远程计算机 4.连接成功 连接远程桌面方式有两种&#xff1a; 方式一&#xff1a;远程桌面通讯协议&#xff08;RDP…

SQL面试题练习 —— 有序行转列

目录 1 题目2 建表语句3 题解 1 题目 有学生各学科分数表&#xff0c;记录了学生的各科分数&#xff0c;请按照学生粒度&#xff0c;生成两列数据分别为学科和分数&#xff0c;要求学科内的顺序与分数顺序一致。 样例数据 期望结果 2 建表语句 --建表语句 create table if not…