SpringMVC整合Mybatis-Junit-Self4j

SpringMVC整合Mybatis

步骤:

  • 导入相关依赖
    • Spring核心依赖
    • Spring-MVC核心依赖
    • Mybatis核心依赖
      • MySQL数据库驱动依赖
        • 注意Mysql的版本和驱动版本保持一致
      • Druid数据库连接池依赖
  • Spring-Mybatis整合依赖
    • 会自动导入Spring-mabtis、Spring-jdbc和spring-tx依赖
<dependencies><!--Spring核心依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.2.RELEASE</version></dependency><!--SpringMVC核心依赖--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.1.2.RELEASE</version></dependency><!--整合Mybatis--><!--1. Mysql数据库驱动依赖--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><!--2. 连接池依赖--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.23</version></dependency><!--3. mybatis本身的依赖--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version></dependency><!--4. 整合mybatis和spring的依赖--><!--MyBatis提供的和Spring进行整合的jar包--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.6</version></dependency><!--spring对jdbc封装的jar包也要导入进来,否则mybatis无法整合--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.1.2.RELEASE</version></dependency><!--编译时DispatcherServlet的依赖--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope></dependency>
  • 在配置文件中配置数据库连接信息jdbc.properties

    • driver=com.mysql.cj.jdbc.Driver
      url=jdbc:mysql://localhost:3306/learn?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true
      db-username=root
      password=root
      
  • 编写mapper接口实现对数据库操作

    • @Mapper注解可加可不加

    • @Mapper
      public interface UserMapper {@Select("select * from user where id=#{id}")User getUserById(int id);@Select("select * from user")List<User> getAllUser();}
      
  • 在Spring容器配置类中扫描mapper接口所在的包

  • 并通过配置文件创建数据源和sqlSession工厂,将mybatis相关对象交给spring容器进行管理

    • @Configuration
      @ComponentScan(basePackages = {"server"})
      @MapperScan(basePackages = "mapper")
      @PropertySource("classpath:jdbc.properties")
      public class SpringConfig {@Value("${driver}")String driver;@Value("${url}")String url;/*这里在测试的时候使用的是username,不过username被解析为默认值即电脑名称而不是配置文件中配置的值原因如下:username 和 password 被系统属性或环境变量覆盖,如果系统属性或环境变量中存在 username,Spring 会优先使用这些值,而不是从 jdbc.properties 中读取。*/@Value("${db-username}")String username;@Value("${password}")String password;@Beanpublic DataSource dataSource(){DruidDataSource dataSource = new DruidDataSource();// 基本配置dataSource.setDriverClassName(driver);dataSource.setUrl(url);dataSource.setUsername(username);dataSource.setPassword(password);return dataSource;}@Bean@Autowiredpublic SqlSessionFactoryBean sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource){SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();sqlSessionFactory.setDataSource(dataSource);/*加载xml文件的位置// 指定 Mapper XML 文件的位置sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));// 调用 getObject() 返回 SqlSessionFactory 实例return sessionFactory.getObject();*/return sqlSessionFactory;}}
      
  • 在Server相关类中注入mapper接口,调用mapper接口的方法完成对数据库的操作

    • @Service
      public class UserServer {@AutowiredUserMapper userMapper;public String getUser(){User user=userMapper.getUserById(1);String str=user.toString();return str;}}
      

事务管理

默认行为:

  • JDBC 连接的默认行为
    • 在 JDBC 中,连接的默认行为是 自动提交事务autoCommit=true)。
    • 这意味着,如果没有显式地开启事务,每个 SQL 语句都会立即提交到数据库。
  • Spring 整合 MyBatis 的情况
    • 如果没有配置任何事务管理器(如 DataSourceTransactionManager),Spring 不会介入事务管理。
    • MyBatis 会直接使用底层的 JDBC 连接,因此每个 SQL 语句会立即提交。
  • 如果配置了事务管理器,确保事务管理器和mybatis使用的是统一个数据库源
    • 共享数据源:事务管理器和 MyBatis 通常共享同一个数据源。这样,事务管理器可以管理 MyBatis 使用的数据库连接,确保事务的一致性。
    • 事务管理器的优先级:事务管理器会覆盖 MyBatis 的默认事务行为。如果配置了事务管理器,MyBatis 会使用事务管理器管理的事务,而不是 MyBatis 的默认行为。

配置事务管理器:

  • 将事务管理器Bean配置在Spring容器中:

    • @Bean
      public PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);
      }
      
  • 启动注解驱动

    • 区分spring-config和web-config场景需要注意

      • 注意配置该注解驱动上的配置类中,配置的包扫描中要能扫到 @Transactional 注解
    • @Configuration
      @EnableTransactionManagement
      public class AppConfig {
      }
      
  • 使用 @Transactional 注解管理事务

    • @Service
      public class UserService {@Autowiredprivate UserMapper userMapper;@Transactionalpublic void createUser(User user) {userMapper.insert(user);throw new RuntimeException("Test exception"); // 抛出异常}
      }
      

事务传播行为

  • 默认行为

    • 默认的传播行为是 REQUIRED,即如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新事务。

    • @Transactional
      public void methodA() {// 开启事务methodB(); // 调用方法 B// 提交或回滚事务
      }@Transactional(propagation = Propagation.REQUIRED)
      public void methodB() {// 在方法 A 的事务中执行
      }
      
  • 嵌套事务

    • 如果方法 A 调用方法 B,且方法 B 的传播行为是 REQUIRES_NEW,则方法 B 会开启一个新事务,方法 A 的事务会被挂起。
    • 如果方法 B 的传播行为是 NESTED,则方法 B 会在方法 A 的事务中创建一个嵌套事务。
    • REQUIRES_NEW 创建的新事务是独立的,如果方法 B 回滚,不会影响方法 A 的事务。

事务超时行为

  • 默认行为

    • 默认情况下,事务没有超时限制。
  • 设置超时

    • 可以通过 @Transactional 注解的 timeout 属性设置事务的超时时间(单位:秒)。

    • @Transactional(timeout = 10)
      public void updateUser(User user) {userMapper.update(user);
      }
      
    • 超时回滚:如果事务在超时时间内未完成,Spring 会回滚事务。

    • 性能影响:设置合理的超时时间,避免长时间占用数据库资源。

事务的只读属性

  • 默认行为

    • 默认情况下,事务是可读写的。
  • 设置只读

    • 可以通过 @Transactional 注解的 readOnly 属性将事务设置为只读。

    • @Transactional(readOnly = true)
      public User getUserById(int id) {return userMapper.selectById(id);
      }
      
    • 性能优化:只读事务可以优化数据库的性能,因为数据库不需要为写操作维护锁。

    • 写操作禁止:在只读事务中执行写操作会抛出异常。

事务的失效场景

  • @Transactional 注解只能用于 public 方法。如果将其应用于非 public 方法(如 protectedprivate 或包级私有方法),事务不会生效。

    • 确保 @Transactional 注解仅用于 public 方法。
  • 如果方法 A 调用同一个类中的方法 B,且方法 B 有 @Transactional 注解,事务不会生效。这是因为 Spring 的事务管理是基于代理的,自调用不会经过代理。

    • @Service
      public class UserService {public void createUser(User user) {insertUser(user); // 自调用,事务失效}@Transactionalpublic void insertUser(User user) {userMapper.insert(user);}
      }
      
    • 解决方法

      • 将方法 B 移到另一个类中

        • @Service
          public class UserService {@Autowiredprivate UserHelper userHelper;public void createUser(User user) {userHelper.insertUser(user); // 通过依赖注入调用}
          }@Service
          public class UserHelper {@Autowiredprivate UserMapper userMapper;@Transactionalpublic void insertUser(User user) {userMapper.insert(user);}
          }
          
      • 使用 AopContext.currentProxy()

        • @Service
          public class UserService {public void createUser(User user) {((UserService) AopContext.currentProxy()).insertUser(user); // 通过代理调用}@Transactionalpublic void insertUser(User user) {userMapper.insert(user);}
          }
          
  • 如果在事务方法中捕获了异常但没有重新抛出,事务不会回滚。默认情况下,Spring 只会在遇到运行时异常(RuntimeException)时回滚事务。

    • 在捕获异常后重新抛出,或使用 @Transactional 注解的 rollbackFor 属性指定回滚的异常类型。
  • 如果事务方法被 finalstatic 修饰,事务不会生效。这是因为 Spring 的事务管理是基于动态代理的,无法代理 finalstatic 方法。

    • JDK 动态代理基于接口实现,要求目标类必须实现至少一个接口。
    • CGLIB 动态代理基于继承实现,通过生成目标类的子类来创建代理对象。
    • 被代理的方法要求是从接口中实现的方法或者可以继承的方法,所以final方法无法被代理
    • static方法是类级别的,所以无法被代理

Junit

作用:

  • 自动加载Spring容器而无需手动加载
  • 运行demo方法

流程:

  • 导入依赖

    • <dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.1.5.RELEASE</version>
      </dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope>
      </dependency>
      
  • 编写测试类,通过注解指定Spring容器的位置

    • 通过自动注入导入Spring容器中的Bean即可测试

    • 注意测试方法需要@Test注解

    • @RunWith(SpringJUnit4ClassRunner.class)
      //@ContextConfiguration(value = {"classpath:applicationContext.xml"})		// 指定配置文件
      @ContextConfiguration(classes = SpringConfig.class)       // 指定配置类
      public class junitTest {@Autowiredpublic UserServer userServer;@Testpublic void test(){String user = userServer.getUser();System.out.println(user);}
      }
      

Slf4j

作用:

  • 日志框架

流程:

  • 导入相关依赖

  • <!-- Log4j2核心库 -->
    <dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.14.1</version>
    </dependency>
    <!-- Log4j2 API -->
    <dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.14.1</version>
    </dependency><!-- 可选:SLF4J 绑定 -->
    <dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j-impl</artifactId><version>2.14.1</version>
    </dependency>
    
  • 创建logger对象,该对象不需要交给Spring容器进行管理

    • import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;@RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration(classes = SpringConfig.class)       // 指定配置类
      public class junitTest {private static final Logger logger = LoggerFactory.getLogger(junitTest.class);@Autowiredpublic UserServer userServer;@Testpublic void test(){String user = userServer.getUser();System.out.println(user);logger.debug("This is a debug message.");}}
      
    • 注意:导入的一定是org.slf4j包下的相关组件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/900967.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Arduino雷达使用Android移动应用程序

该系统可以检测障碍物并收集距离和角度信息,并且可以通过移动应用程序通过蓝牙进行控制。 Arduino雷达使用Android移动应用程序本项目是一个由超声波传感器和伺服电机驱动的雷达系统。该系统可以检测障碍物并收集距离和角度信息,并且可以通过移动应用程序通过蓝牙进行控制。该…

使用cursor打造智能客服demo

cursor AI它真的是非常强大。 今天讲下如何使用它,搭配deepseek api接口,来生成一个智能客服系统。这是最终的效果。首先cursor需要登录后才能使用。登录之后有两周的免费试用期。我们在窗口的右侧填写智能客服的需求。帮我实现一个网页智能客服。详细要求如下: 1.生成一个h…

【蓝牙小程序】小程序使用echart图表报错:setOption of undefined

转载自:https://developers.weixin.qq.com/community/develop/doc/0004ac054ccec0f26df7baa8756800问题:小程序使用echart图表报错 Cannot read property setOption of undefined;at api request success callback function TypeError: Cannot read property setOption of un…

前端中的Javascript

前端中的Javascript javascript定义方式内联JavaScript直接在HTML元素的事件属性中编写JavaScript代码<body><h1>Hello, World!</h1><button onclick="alert(Button clicked!)">Click Me</button> </body>内部JavaScript可以直接…

NVM:安装配置使用

一、简介 在实际的开发和学习中可能会遇到不同项目的 node 版本不同,而出现的兼容性问题。 而 nvm 就可以很好的解决这个问题,它可以在同一台机器上下管理多个 node 版本,使得程序员可以轻松地安装、卸载和切换不同的 node 版本。 在下载和配置 nvm 前,需要在控制面板中先删…

硬盘科普,M.2,PCI-E,NVMe 傻傻分不清

首先从三个层面去理解这个问题:物理接口,通道,协议 1:物理接口(相当于通讯中的电,光口) 大白话- 物理规格,像是 公路,铁路 专门跑PCI-E通道的那个物理接口:扩展性极强,可以插显卡的PCI-E X16的那个物理接口,或者插网卡,声卡的那个PCI-E X1那个物理接口,都是属于一类…

第二届长城杯ciscn半决赛awdp pwn以及应急响应wp

这次半决赛还真是状况频出,先是上午全场靶机断联了2轮,下午的应急又在坐大牢,还好是后面捋顺了逻辑做出来了,下半场干了个赛区第二,总成绩第四,这回是真燃尽了 上半场AWDP typo fix 一开始一直在改这道结果后面才发现那个prompt是真的好改,白浪费了3轮。。。 进入程序是…

LLM Assistance for Memory Safety

LLM Assistance for Memory SafetyMohammed, Nausheen, et al. "LLM Assistance for Memory Safety." 2025 IEEE/ACM 47th International Conference on Software Engineering (ICSE). IEEE Computer Society, 2024.Introduction 在软件安全的漏洞中,内存安全是主要…

『Plotly实战指南』--折线图绘制进阶篇

上一篇介绍了Plotly绘制折线图的基础知识和数据预处理的技巧, 本文将重点探讨如何利用Plotly实现多线折线图的布局设计以及动态折线图的实现, 让我们一起掌握进阶的折线图绘制技巧。 1. 多折线图布局 在实际的数据分析场景中,常常需要同时展示多组数据,例如对比不同产品的销…

使用gradio快速实现聊天机器人

我们可以使用gradio库通过低代码的方式快速实现聊天机器人界面及交互: import gradio as gr from ollama import chatdef predict(message,history):stream = chat(model="deepseek-r1:1.5b",messages=[{"role":"user","content":mess…

Edge浏览器登录微软账户报错0x80190001的解决办法

问题 0x80190001是什么错误?有用户在Edge浏览器上登录微软账户遇到了这个错误代码,这是什么意思?要如何解决呢?一个比较靠谱的解决办法解决方式1、下载一个finder(抓包软件)官网下载地址(最新版本):https://www.telerik.com/download/fiddler2、直接安装就好,选择左上…

2025年项目管理软件革命:7大工具重新定义团队协作

本文深度解析2025年项目管理工具的技术革新与市场格局,聚焦AI、量子计算、混合现实等技术对团队协作模式的颠覆性影响。一、2025年项目管理生态的三大颠覆性变化 在生成式AI、量子计算与混合现实技术推动下,项目管理工具正经历三大变革:决策权转移:AI从辅助工具升级为“虚拟…